Benutzer mit den meisten Antworten
Anzeigen eines Dialogs, der in einer DLL ausgelagert ist

Frage
-
Hallo,
ich habe ein Problem mit dem Auslagern von Ressourcen in eine DLL. Ich habe eine DLL in der verschiedene Dialoge ausgelagert sind. Die Hauptapplikation soll diese Dialoge anzeigen. Hinweise: Als Zeichensatz muss ich momentan den Multibyte-Zeichensatz verwenden.
1. Szenario:
Meine Hauptapplikation lädt die DLL und zeigt einen beliebigen Dialog an. Das funktioniert solange, wie ich keinerlei MFC-Steuerelemente verwende. Sobald ich z.B. einen MFC-Button hinzufüge, kann der Dialog nicht mehr angezeigt werden.
2. Szenario:
Wenn ich in meiner Hauptapplikation einen Dialog anlege und dort einen MFC-Button integriere, wird der Dialog immer korrekt angezeigt.
3.Szenario:
Meine Hauptapplikation hat einen Dialog mit einem MFC-Button. Wenn ich nun einen ausgelagerten Dialog anzeigen möchte, klappt das wieder nur, wenn kein MFC-Steuerelement in dem Dialog vorhanden ist.
Nun zum Code:
BOOL CAppApp::InitInstance() { ... // Ressource in der Hauptapplikation AboutDlg* pAboutDlg = new AboutDlg(); // Funktioniert immer, egal ob mit oder ohne MFC-Steuerlement pAboutDlg->DoModal(); delete pAboutDlg; // Laden der weiteren Ressourcen HINSTANCE res = AfxLoadLibrary(_T("AppRes.dll")); AfxSetResourceHandle(res); // Ressource in der DLL TestDlg* pTestDlg = new TestDlg(); // Funktioniert, solange kein MFC-Steuerelement in dem Dialog vorhanden ist pTestDlg->DoModal(); delete pTestDlg; return TRUE; }
Beim Debuggen habe ich folgende Stelle gefunden, bei der der Fehler auftritt:
dlgcore.cpp Zeile 365 - 368
hWnd = ::CreateDialogIndirect(hInst, lpDialogTemplate, pParentWnd->GetSafeHwnd(), AfxDlgProc);
dwError = ::GetLastError();
Wenn ein MFC-Steuerelement in der DLL-Ressource vorhanden ist, dann ist hWnd = NULL; und dwError = 0.
Wenn kein MFC-Steuerelement in der DLL-Ressource vorhanden ist, enthält hWnd eine Adresse und dwError = 0.
Um euch dies mal zu veranschaulichen habe ich euch unter
http://www.loaditup.de/645274-8y5kycg6w6.html
mal ein kleines Testprojekt zur Verfügung gestellt (VS2010).
Ich hoffe Ihr könnt mir schnell weiterhelfen.
Antworten
-
Siehe Case und Beschreibung hier:
http://connect.microsoft.com/VisualStudio/feedback/details/686157/satellite-dlls-doesnt-work-when-new-mfc-controls-like-cmfcbutton-are-used-in-an-mbcs-projectEmail an die Produktgruppe ist raus.
Martin Richter -- MVP for VC++ [Germany] -- http://blog.m-ri.de- Als Antwort markiert Martin RichterModerator Freitag, 9. September 2011 09:48
-
Hier nun die Antwort von Microsoft:
Thanks for the report. This issue has been fixed in MFC for the next major release of Visual Studio. If the dialog fails to load when the resource handle is used, the instance handle will be used as a fallback.
- Als Antwort markiert bonkaehlchen Donnerstag, 8. September 2011 16:59
- Bearbeitet bonkaehlchen Donnerstag, 8. September 2011 16:59
Alle Antworten
-
Hmmm. Eigentümlich, eigentlich sollte das gehen.
Ich kann keinen Fehler in Deinem Code sehen.
Auch CreateWindowIndirect liefert keinen GetLastError exakt wie Du es beschreibst. Der ist 0, also auch nichts wie Klasse nicht registriert oder so.Allerdings bezweifle ich, dass es ohne Manifest funktioniert. Du hast kein Common Control 6.0 Manifest in Deinem Programm.
Martin Richter -- MVP for VC++ [Germany] -- http://blog.m-ri.de -
Hallo, vielen Dank für die schnelle Antwort!
Ich habe jetzt ein CommonControl 6 Manifest in die Applikation integriert. Die Dialoge werden nun korrekt angezeigt, wenn ich den Unicodezeichensatz in der Hauptapplikation verwende. Beim Multibytezeichensatz stürzt das Programm sofort bei der Methode "DoModal" ab. Momentan ist es für mich leider nicht möglich denUnicodezeichensatz zu verwenden. Gibt es vielleicht auch eine Lösung für Multibyte-Anwendungen?
Vom Prinzip her funktioniert das Anzeigen von MFC-Steuerelementen korrekt, solange diese aus der eigenen Ressource bzw. dem Hauptprogramm kommen. Nur das Laden aus einer DLL ist problematisch.
Hat vielleicht noch jemand eine Idee?
-
> Ich habe jetzt ein CommonControl 6 Manifest in die Applikation integriert. Die Dialoge werden nun korrekt angezeigt, wenn ich den Unicodezeichensatz in der Hauptapplikation verwende. Beim Multibytezeichensatz stürzt das Programm sofort bei der Methode "DoModal" ab. Momentan ist es für mich leider nicht möglich denUnicodezeichensatz zu verwenden. Gibt es vielleicht auch eine Lösung für Multibyte-Anwendungen?
Eigentümlich. Eigentlich müsste es auch so funktionieren. Ich kenne keine Einschränkung, die die MFC auf Unicode limitiert.
Könnte ein Bug sein...
Warum kannst Du nicht auf Unicode umschalten?
das wäre sowieso angesagt und vernünftig.
Martin Richter -- MVP for VC++ [Germany] -- http://blog.m-ri.de -
Warum ich die Applikation nicht umstellen kann ist ganz einfach: Quellcode der in ~ 20 Jahren entstanden ist, der den Multibytezeichensatz nutzt ;-).
Also so wie ich gelesen habe sind wohl CommonControls auf Unicode beschränkt. Das wird auch nochmal vom Debugger bestätigt - Fehler: Heap block at xxx modified at xxx past requested size of xxx, wenn ich auf Multibyte umschalte. Ich will da jetzt aber auch nichts falsches behaupten.
Im Internet finden sich auch vereinzelte Fälle, welche die gleichen Probleme wie ich habe (hwnd=null && GetLastErrorCode = 0), jedoch alle ohne Lösung. Bei Microsoft ist dieser Fall folgendermaßen dokumentiert: Sometimes, CreateDialogIndirect() returns NULL and GetLastError() returns 0. This can happen, for example, if the dialog contains a custom control whose window class cannot be found. (http://msdn.microsoft.com/en-us/library/ms645436%28v=vs.85%29.aspx)
Komisch nur, dass das mit Ressourcen aus dem Hauptprogramm funktioniert aber nicht mit Ressourcen aus einer DLL.
Wenn noch jemand eine schlaue Idee hat, wäre ich gerne interessiert.
-
Warum ich die Applikation nicht umstellen kann ist ganz einfach: Quellcode der in ~ 20 Jahren entstanden ist, der den Multibytezeichensatz nutzt ;-).
Meistens betrifft es nur Teile und dann kann man diese auf MBCS separat belassen.
Also so wie ich gelesen habe sind wohl CommonControls auf Unicode beschränkt. Das wird auch nochmal vom Debugger bestätigt - Fehler: Heap block at xxx modified at xxx past requested size of xxx, wenn ich auf Multibyte umschalte. Ich will da jetzt aber auch nichts falsches behaupten.
Hmmm. Auch das halte ich für einen Bug.
Eigentlich haben die Common Control 6.0 auch in MBCS gut funktioniert. Allerdings garantiert MS nur die volle Funktion in Unicode Projekten.
> Im Internet finden sich auch vereinzelte Fälle, welche die gleichen Probleme wie ich habe (hwnd=null&& GetLastErrorCode = 0), jedoch alle ohne Lösung. Bei Microsoft ist dieser Fall folgendermaßen dokumentiert: Sometimes, CreateDialogIndirect() returns NULL and GetLastError() returns 0. This can happen, for example, if the dialog contains a custom control whose window class cannot be found. (http://msdn.microsoft.com/en-us/library/ms645436%28v=vs.85%29.aspx)Aber die Klasse wird registriert. Ganz eindeutig.
AfxRegisterMFCCtrlClasses wird aufgerufen!Komisch nur, dass das mit Ressourcen aus dem Hauptprogramm funktioniert aber nicht mit Ressourcen aus einer DLL.
Ja! Da gebe ich Dir recht. Ich werde mal die Produktgruppe kontaktieren.
Martin Richter -- MVP for VC++ [Germany] -- http://blog.m-ri.de -
Siehe Case und Beschreibung hier:
http://connect.microsoft.com/VisualStudio/feedback/details/686157/satellite-dlls-doesnt-work-when-new-mfc-controls-like-cmfcbutton-are-used-in-an-mbcs-projectEmail an die Produktgruppe ist raus.
Martin Richter -- MVP for VC++ [Germany] -- http://blog.m-ri.de- Als Antwort markiert Martin RichterModerator Freitag, 9. September 2011 09:48
-
Also ich mache zwei Ursachen an dem ganzen fest.
1. Ist kein Common-Control 6.0 Manigfest vorhanden wird der MFCButton nicht mit CS_GLOBALCLASS erzeugt und damit in der DLL nicht gefunden.
2. Weitere Ursache ist die falsche Verwendung des hInst Parameters in CreateDialogIndirect von CDialog::DoModal. Unsinniger weise wird hier nicht die Anwendung übergeben (AfxGetInstanceHandle) sondern das Ressource Handle. Mir scheint das den Entwickler hier ganz klar war was sie tun. Das Problem ist auch, dass hier Extension-DLLs auch mit behandelt werden müssen... also komen sich hier zwei Absichten in die Quuere.
Da hier die hInst aber für die Klassensuche auch verantwortlich wird, wird die MFCButton Klasse mangels WS_GLOBALCLASS nicht gefunden...Klarer Workarround: Common Control 6.0 verwenden. Damit werden die Klassen als CS_GLOBALCLASS registriert und alles geht.
Also übertrage Dein Projekt nach Unicode ;) oder zumindest die UI Teile. Alles andere kannst Du ja mit MBCS kompilieren.
Nur mal als Zwischenbericht.
Martin Richter -- MVP for VC++ [Germany] -- http://blog.m-ri.de- Als Antwort vorgeschlagen Martin RichterModerator Mittwoch, 31. August 2011 12:19
-
Es gibt noch einen zweiten Workarround.
Man wandelt die Ressoucren-DLL in eine reguläre DLL und integriert dort die betreffenden Ressourcen + Schnittstellenmethoden. In den Schnittstellenmethoden wird dann der Dialog mittels DoModal() aufgerufen. In den Tests hat das soweit funktioniert.
Jedoch stehen dieser Workarrounds in keinem Verhältnis zum dem Aufwand der betrieben werden muss. Weiterhin haben wir schon ein bisschen mit Unicode herumgespielt und festgestellt, dass das Laden von Unicode-DLLs aus MBCS-Projekten heraus, problematisch ist. Beispielsweise wird die Referenz auf die Applikation von dem MBCS-Projekt nicht auf die Unicode-DLL übertragen. Erst wenn die Applikation Unicode nutzt oder die DLL Multibyte nutzt, funktioniert das.
Naja warten wir einfach mal ab was die zuständigen Entwickler von MS schreiben.
-
Für mich ist das kein Workarround. Die Verwendung von Satellite DLLs für Überersetzungen ist ein Standard.
Wenn es einen Workarround gibt der imer geht, dann ist es das klassiche Subclassing.
Man entwirft den Button als "Button" und macht in DoDataExchange den Subclass auf CMFCButton und stellt ein was man braucht.Das eigentliche Problem ist ja nur die Verwendung des Resource-Editors für diese erweiterten Klassen.
Martin Richter -- MVP for VC++ [Germany] -- http://blog.m-ri.de -
Hier nun die Antwort von Microsoft:
Thanks for the report. This issue has been fixed in MFC for the next major release of Visual Studio. If the dialog fails to load when the resource handle is used, the instance handle will be used as a fallback.
- Als Antwort markiert bonkaehlchen Donnerstag, 8. September 2011 16:59
- Bearbeitet bonkaehlchen Donnerstag, 8. September 2011 16:59
-
> Thanks for the report. This issue has been fixed in MFC for the next major release of Visual Studio. If the dialog fails to load when the resource handle is used, the instance handle will be used as a fallback.
Naja. Es gäbe mehrere korrkte Ansätze.
Martin Richter -- MVP for VC++ [Germany] -- http://blog.m-ri.de