Seite 1 von 1

[gelöst] Programm crasht bei Aufruf von DLL-Funktion

Verfasst: 15. Januar 2015 13:50
von matthiasw
Hallo alle zusammen,

ich bin in meiner Anwendung (Qt 4.7.4, Windows 7) auf ein Problem gestoßen, dass ich mir nicht erklären kann.

Im Hauptthread binde ich dynamisch eine DLL über LoadLibrary() ein. Das zurückgegebene Handle verwende ich, um Funktionszeiger mit GetProcAdress() auf die jeweilige Adresse der DLL-Funktion zeigen zu lassen. Dann erzeuge ich 4 Threads, in denen die Funktionen der DLL verwendet werden. Alles funktioniert prima mit der Debug-Buildkonfiguration!

Wechsle ich auf die Release-Buildkonfiguration, crasht die Anwendung, wenn die 4 Threads "gleichzeitig" ausgeführt werden und die DLL-Funktionen verwenden (Fehlercode 0xc0000005, unerlaubter Speicherzugriff) Füge ich aber vor jeden Funktionsaufruf eine qDebug() << "irgendwas" Zeile ein, funktioniert alles!!! :?: Die DLL-Funktionsaufrufe sind übrigens über ein Mutex serialisiert, so dass 2 Threads nie gleichzeitig auf eine Funktion der DLL zugreifen sollten.

Was kann da schief laufen? Scheinbar bringt Qt mit QLibrary selbst eine Klasse zum Einbinden von DLLs mit, diese habe ich aber noch nicht getestet.

PS: Auf Quellcode habe ich vorerst verzichtet, da es mit einer anderen Build-Konfiguration (scheinbar) problemlos funktioniert.

Re: Programm crasht bei Aufruf von DLL-Funktion im Release-B

Verfasst: 19. Januar 2015 10:46
von matthiasw
Hallo,

mittlerweile habe ich die Windows-API-Aufrufe durch die QLibrary-Klasse ersetzt. Zudem verwende ich jetzt nur noch 1 statt 4 Threads, um das gleichzeitige Aufrufen der DLL-Funktionen auch wirklich sicher zu vermeiden. Das Problem besteht aber weiterhin!

Führe ich die DLL-Funktionen im Hauptthread aus, funktioniert es scheinbar wieder...

Mir ist bewusst, dass Threads unterschiedliche Adressbereiche zur Verfügung haben, doch scheint es mit den DLL-Funktionen bis zu einer bestimmten Stelle zu gehen und dann schmiert das Programm ab. Ich lass mir vorher immer die Werte der Funktionspointer anzeigen, um etwaige NULL-Pointer zu detektieren. Kein NULL-Pointer dabei.

Viele Grüße

Re: Programm crasht bei Aufruf von DLL-Funktion im Release-B

Verfasst: 19. Januar 2015 13:34
von softwaremaker
Was machst du in der DLL-Funktion? Eventuell werden Objekte manipuliert bzw. zerstört während ein anderer Thread auf diese zugreift.
Werden Objekte von Thread 1 erzeugt und von Thread 2 gelöscht?

Re: Programm crasht bei Aufruf von DLL-Funktion im Release-B

Verfasst: 19. Januar 2015 16:11
von matthiasw
Die DLL (Third Party, die Innereien kenn ich nicht, lediglich die Schnittstelle ist dokumentiert + Header beigefügt) sendet und empfängt Daten übers LAN. Die Threads habe ich zu Testzwecken schon deaktiviert und führe die DLL-Funktionen sequentiell im Main-Thread aus.

Was mir aufgefallen ist, nach bestimmten DLL-Funktionen kennt das Programm keine Steuerelemente mehr :( Wenn ich mir z.b. einfach nur mit

qDebug() << ui->btnDownload

den Zeiger auf das Steuerelement ausgeben lassen will, crashts... Kann es sein, dass die DLL-Funktion den Speicherbereich einfach überschreibt, sodass das Objekt dann nicht mehr vorhanden ist? Warum macht es das dann nicht auch, wenn ich die DLL statisch einbinde? Da funktioniert nämlich alles.

Re: Programm crasht bei Aufruf von DLL-Funktion im Release-B

Verfasst: 19. Januar 2015 18:14
von veeman
Um welche Schnittstelle handelt es sich genau?
Offensichtlich ist die DLL bzw. die Funktionen der DLL nicht Threadsicher.
Ggf. jeden Funktionsaufruf mit nem Mutex schützen.Wobei, wenn man nicht weiß was die Funktion macht,
dann kann man das ganze Thradingkram auch gleich lassen da es keinen Performancegewinn bringt.

Re: Programm crasht bei Aufruf von DLL-Funktion im Release-B

Verfasst: 21. Januar 2015 07:35
von matthiasw
Das Problem ist gelöst. Die Funktionspointer mussten mit dem Schlüsselwort "CALLBACK" bzw. "__stdcall" definiert werden, danach lief alles so wie es sollte, auch mit 4 Threads parallel.

Ein Beispiel aus dem Quellcode:

typedef HRESULT (CALLBACK *PLogin)(HANDLE,LPCSTR,LPCSTR,PASYNC,DWORD);

Der Typ PLogin kann nun zum Deklarieren eines Funktionspointers verwendet werden, der über ein QLibrary-Objekt die Adresse der Dll-Funktion zugewiesen bekommt und anschließend die Dll-Funktion aufruft.

Grüße

Matthias