![]() |
Mutex-Handling in DLL für zwei Programme
Hallo Community,
ich sitze hier gerade an einem sehr "interessanten" (man könnte auch nervig dazu sagen...) Phänomen, das ich mir nicht so recht erklären kann. Zunächst mal kurz die Motivation: Es gibt hier zwei Prozesse, die sich eine INI-Datei teilen. Der eine Prozess ist eine EXE-Datei in Delphi geschrieben (32 bit), der andere ist ein Matlab-Skript. Beide Prozesse schreiben und lesen diese INI-Datei, daher ist eine Synchronisation absolut notwendig. Das wollte ich mit einer DLL realisieren, die einen Mutex erzeugt. Eine DLL deshalb, weil Matlab wohl das Prinzip der Mutexe nicht unterstützt und ich dem Entwickler somit dieselbe Funktionalität zur Verfügung stellen kann. Es gibt 4 Methoden, die die DLL zur Vefügung stellt: Register, UnRegister, Acquire und Release. In der DLL wiederum gibt es eine globale Variable FMutex (Vom Typ System.SyncObj.TMutex), die über die komplette Laufzeit hinweg gehalten wird. Register macht ein Create, UnRegister ein Free und Acquire bzw. Release sind ja selbsterklärend. Jetzt kommt der Clou: Wenn ich diese 4 Methoden einfach im Delphi-Programm "hart rein programmiere", dann klappt das alles wie am Schnürchen. Sobald diese Methoden aber in der DLL stehen und aufgerufen werden, fliegt mir das Programm um die Ohren wie eine Kuh bei einem Tornado. Hier mal die DLL:
Delphi-Quellcode:
In dem Delphi-Programm, das ich auch entwickle, lade ich die DLL mittels LoadLibrary und hole mir die 4 Methoden über GetProcAddress. Die rufe ich dann an den entsprechenden Stellen auf.
uses
System.SysUtils, System.Classes, System.SyncObjs; {$R *.res} var FMutex: TMutex; procedure RegisterMutex(); stdcall; begin if not Assigned(FMutex) then FMutex := TMutex.Create(nil, false, 'MyUniqueMutexName'); end; procedure UnRegisterMutex(); stdcall; begin if Assigned(FMutex) then FMutex.Free; end; procedure AcquireMutex(); stdcall; begin if Assigned(FMutex) then FMutex.Acquire; end; procedure ReleaseMutex(); stdcall; begin if Assigned(FMutex) then FMutex.Release; end; exports RegisterMutex, UnRegisterMutex, AcquireMutex, ReleaseMutex; begin end. Hat irgendwer von euch schon Mal so ein Konstrukt gebaut oder verwendet? |
AW: Mutex-Handling in DLL für zwei Programme
Zitat:
|
AW: Mutex-Handling in DLL für zwei Programme
Nein, auch wenn wir hier Geräte herstellen, die durchaus genug Wind erzeugen könnten, damit so etwas passiert, ist das nicht der Fall :P
Das schöne (oder eher schlimme) ist, dass keine Fehlermeldung erscheint, sonst hätte ich sie ja mit dazu geschrieben. Aus Sicht des Anwenders kommt aus heiterem Himmel "Programm reagiert nicht mehr und muss geschlossen werden". Ich habe den Absturz zwar lokalisieren können, aber es macht keinen wirklichen Sinn: Nach dem Laden der DLL wird die Register-Funktion aufgerufen (klappt), danach kommt ein Acquire (geht auch noch) und ein Release (klappt auch) und selbst das UnRegister scheint zu klappen (laut Debug-Ausgaben). Nur in dem Moment, in dem die UnRegister Funktion verlassen wird, knallt's. |
AW: Mutex-Handling in DLL für zwei Programme
Minimales Beispielprojekt zum Nachvollziehen?
|
AW: Mutex-Handling in DLL für zwei Programme
Zitat:
Delphi-Quellcode:
TMyDllProc = procedure() of object; stdcall; TExampleClass = class(TThread) private FHandleDLL: THandle; // methods from DLL FRegister: TMyDllProc; FUnRegister: TMyDllProc; FAcquire: TMyDllProc; FRelease: TMyDllProc; function InitMutexDLL(): boolean; procedure DeInitMutexDLL(); procedure ExecuteMutex(); procedure Execute(); override; end; // ... function TExampleClass.InitMutexDLL(): boolean; begin Result := false; FHandleDLL := LoadLibrary(PChar('MutexDLL.dll')); if FHandleDLL <> INVALID_HANDLE_VALUE then begin @FRegister := GetProcAddress(FHandleDLL, 'RegisterMutex'); @FAcquire := GetProcAddress(FHandleDLL, 'EnterMutex'); @FRelease := GetProcAddress(FHandleDLL, 'ReleaseMutex'); @FUnregister := GetProcAddress(FHandleDLL, 'UnRegisterMutex'); Result := Assigned(FRegister) and Assigned(FAcquire) and Assigned(FRelease) and Assigned(FUnregister); if Result then FRegister(); end; end; // ... procedure TExampleClass.DeInitMutexDLL(); begin if FHandleDLL <> INVALID_HANDLE_VALUE then begin FUnRegister(); FreeLibrary(FHandleDLL); end; end; // ... procedure TExampleClass.ExecuteMutex(); begin try FAcquire(); // access INI-File finally FRelease(); end; end; // ... procedure TExampleClass.Execute(); begin InitMutexDLL(); while not Terminated do begin ExecuteMutex(); Sleep(100) end; DeInitMutexDLL(); end; |
AW: Mutex-Handling in DLL für zwei Programme
Zitat:
Mit deiner obigen Deklaration wird beim Aufruf ein zusätzlicher Parameter (Self) übergeben, den die DLL aber nicht erwartet. Das bringt den Call-Stack durcheinander. |
AW: Mutex-Handling in DLL für zwei Programme
Zitat:
Im Konkreten Fall deklariere ich sowas hier:
Delphi-Quellcode:
und belege die Variable FCallbackOnError dann mit der Prozedur:
TErrCallback = procedure(const AMsg: string) of object;
FCallbackOnError: TErrCallback;
Delphi-Quellcode:
Edit
// Deklaration
procedure ShowErrorMessage(const AMsg: string); // Definition procedure TFormClass.ShowErrorMessage(const AMsg: string); begin MessageDlg(AMsg, mtError, [mbOK], -1); end; Hab meine Frage glaub selbst beantwortet. Unten aufgeführter Link gibt da das entsprechende Stichwort:
Code:
Ein Methodenzeiger wird in Form zweier Zeiger codiert, von denen der erste die Adresse der Methode speichert, während der zweite eine Referenz auf das Objekt enthält, zu dem die Methode gehört.
![]() |
AW: Mutex-Handling in DLL für zwei Programme
Hallo,
sobald du eine Methode in einer Klasse hast, wird das Self beim Methodenaufruf immer mit übergeben. Ist halt so. Entweder deine Dll-Methoden (im Programm) sind nicht in einer Klasse, oder du änderst die Prozeduren in der Dll -> neuer Parameter Dummy: TObject. |
AW: Mutex-Handling in DLL für zwei Programme
Man kann sich viel Ärger ersparen, wenn man das erheblich einfacher umsetzt.
Hier mal die DLL
Delphi-Quellcode:
library TheMutex;
{ Wichtiger Hinweis zur DLL-Speicherverwaltung: ShareMem muss die erste Unit in der USES-Klausel Ihrer Bibliothek UND in der USES-Klausel Ihres Projekts (wählen Sie 'Projekt-Quelltext anzeigen') sein, wenn Ihre DLL Prozeduren oder Funktionen exportiert, die Strings als Parameter oder Funktionsergebnisse übergeben. Dies gilt für alle Strings, die an oder von Ihrer DLL übergeben werden, auch für solche, die in Records und Klassen verschachtelt sind. ShareMem ist die Interface-Unit zur gemeinsamen BORLNDMM.DLL-Speicherverwaltung, die zusammen mit Ihrer DLL weitergegeben werden muss. Übergeben Sie String-Informationen mit PChar- oder ShortString-Parametern, um die Verwendung von BORLNDMM.DLL zu vermeiden. } uses System.SysUtils, System.Classes, TheMutexImplementation in 'TheMutexImplementation.pas'; {$R *.res} exports MutexAcquire, MutexRelease; begin end.
Delphi-Quellcode:
Und nun noch den benötigten Wrapper für die Dll
unit TheMutexImplementation;
interface procedure MutexAcquire(); stdcall; procedure MutexRelease(); stdcall; implementation uses System.SyncObjs, System.SysUtils; var _Mutex: TMutex; procedure MutexAcquire(); begin _Mutex.Acquire(); end; procedure MutexRelease(); begin _Mutex.Release(); end; initialization _Mutex := TMutex.Create(nil, false, 'MyUniqueMutexName'); finalization FreeAndNil(_Mutex); end.
Delphi-Quellcode:
unit TheMutexWrapper;
interface uses Winapi.Windows; procedure MutexAcquire(); stdcall; procedure MutexRelease(); stdcall; const TheMutexDll = 'TheMutex.dll'; implementation procedure MutexAcquire(); external TheMutexDll name 'MutexAcquire'; procedure MutexRelease(); external TheMutexDll name 'MutexRelease'; end. |
AW: Mutex-Handling in DLL für zwei Programme
Zitat:
Aber der Hinweis mit dem "of object" hat da tatsächlich geholfen, passt ja auch wunderbar zum Fehlerbild. Danke dafür, die jetzt anstehenden Tests werden es zeigen, aber sieht bisher ganz vielversprechend aus. Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:04 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz