Nightfall Geschrieben 31. Januar 2008 Geschrieben 31. Januar 2008 Hi Leute, ich habe ein Problem. Und zwar soll ich in einem MFC Projekt einen nicht auf Ressourcen basierenden Dialog aufrufen, der in einer statischen Win32-Bibliothek Programmiert wird. Auf dem Dialog soll auch noch ein Button sein. Bis dahin isses kein Problem. Aber nun soll sich der dynamische Dialog schließen sobald ich auf den Button drücke. Nun zu meiner Frage: Wie kann ich auf das Event des Buttons reagieren? Hier mein Code: So erzeuge ich den Dialog in der Win32-static library: Das struct was ich verwende: struct MyStruct { DLGTEMPLATE mHeader; #pragma pack(2) WORD mNoMenu; // 0x0000 -- no menu WORD mStdClass; // 0x0000 -- standard dialog class wchar_t mTitle[5]; // title: "Test" #pragma pack(4) DLGITEMTEMPLATE mItem; #pragma pack(2) WORD mFfff; // 0xFFFF -- next is standard class ID WORD mCtrlClassId; // 0x0080 -- class ID for button wchar_t mText[5]; // text (not used for listbox) WORD mNoData; // 0 #pragma pack(4) }; Das erzeugen und aufrufen des Dialoges: void CTestClass::ShowDialog(long lState) { MyStruct ms = { { WS_CAPTION | WS_VISIBLE | DS_CENTER, 0, 1, 10, 10, 100, 100 }, 0, // no menu 0, // standard dialog class L"Test", // text { WS_VISIBLE | WS_CHILD | WS_BORDER, 0, 1, 1, 50, 50, 1234 }, 0xFFFF, // next is standard class ID 0x0080, // 0x0080 -- class ID for button L"Test", // text 0 }; if (SW_SHOW == lState) { m_hMyDialog = ::CreateDialogIndirect(NULL, &ms.mHeader, NULL, NULL); ::SetForegroundWindow(m_hMyDialog); } } In meinem MFC Projekt schreibe ich dann einfach: CTestClass TestClass; TestClass.ShowDialog(SW_SHOW); Bin für jede Hilfe dankbar! Zitieren
SwordMaster Geschrieben 1. Februar 2008 Geschrieben 1. Februar 2008 Hallo Nightfall. Ich verwende zwar eine ältere Version von Visual Studio, aber normalerweise sollte sich da nichts verändert haben. Du kannst in deiner Dialogklasse (des dynamischen Dialogs) die WindowProc überschreiben. Die WindowProc bekommt nachrichten wie "buttonklicks" mit. Beispielcode: LRESULT CForeignEditorDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { if ( HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDC_ID ) CDialog::OnOK( ); return CDialog::WindowProc(message, wParam, lParam); } IDC_ID ist die ID deines Buttons. Ich hoffe das hilft dir Weiter. Viele grüße Stefan Zitieren
TDM Geschrieben 4. Februar 2008 Geschrieben 4. Februar 2008 LRESULT CForeignEditorDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { if ( HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDC_ID ) CDialog::OnOK( ); return CDialog::WindowProc(message, wParam, lParam); } Warum so umständlich? BOOL CALLBACK DialogProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (uMessage) { case WM_CLOSE: EndDialog(hwnd, 0); return FALSE; default: return FALSE; } } Zitieren
Nightfall Geschrieben 5. Februar 2008 Autor Geschrieben 5. Februar 2008 Hi. Vielen Dank für eure Antworten! Aber leider führen beide Lösungen nicht zu meinem Ziel. Hier eine kleine Erklärung warum: LRESULT CForeignEditorDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { if ( HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDC_ID ) CDialog::OnOK( ); return CDialog::WindowProc(message, wParam, lParam); } IDC_ID ist die ID deines Buttons. Ich kenne die ID des Buttons nicht. Warum so umständlich? Code: BOOL CALLBACK DialogProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (uMessage) { case WM_CLOSE: EndDialog(hwnd, 0); return FALSE; default: return FALSE; } } Der Button schickt kein WM_CLOSE. Der Button schickt nix. ^^ Höchstens ein: Button_Click Event. Sorry falls ich es ein wenig umständlich formuliert habe. Ich möchte nur herausfinden wann mein Button geklickt wurde. Er wurde dynamisch erzeugt. (Der Dialog auf dem der Button ist auch.) Die ID des Buttons ist die nächst mögliche. (0xFfff) Gruß, Yasin Zitieren
Guybrush Threepwood Geschrieben 5. Februar 2008 Geschrieben 5. Februar 2008 Wenn du den Button mit CreateWindow erstellst dann musst du ihm die gewünschte ID im hMenu Parameter angeben. Das ist auf den ersten Blick nicht so ganz ersichtlich aus dem Parameternamen da er für unterschiedliche Sachen verwendet werden kann hMenu [in] Handle to a menu, or specifies a child-window identifier depending on the window style. For an overlapped or pop-up window, hMenu identifies the menu to be used with the window; it can be NULL if the class menu is to be used. For a child window, hMenu specifies the child-window identifier, an integer value used by a dialog box control to notify its parent about events. The application determines the child-window identifier; it must be unique for all child windows with the same parent window. Die ID selber musst du halt irgendwo definieren, z.B. #define MyButton 1 [/PHP] In deiner DialogProc musst du dann WM_COMMAND abfangen welches die ID des Controls im LOWORD(wParam) liefert: [PHP] switch(Msg) { case WM_COMMAND: { switch(LOWORD(wParam)) { case MyButton: Zitieren
Nightfall Geschrieben 6. Februar 2008 Autor Geschrieben 6. Februar 2008 Das Funktioniert leider nicht. Es kommt keine Msg die WM_COMMAND ist. Aber der Tipp mit der ID war gut. Danke! Hat noch jemand nen vorschlag? Zitieren
Klotzkopp Geschrieben 6. Februar 2008 Geschrieben 6. Februar 2008 Ich kenne die ID des Buttons nicht.Wieso nicht? Du erstellst ihn doch. Zeig doch mal, wie du den Button erstellst. Der Button schickt kein WM_CLOSE. Der Button schickt nix. ^^ Höchstens ein: Button_Click Event.Was soll das sein? Der Button schickt Nachrichten an sein Elternfenster, also deinen Dialog. Du gibt aber bei CreateDialogIndirect gar keine DialogProc an, also kannst du auch nicht die Nachrichten des Buttons empfangen. Die ID des Buttons ist die nächst mögliche. (0xFfff)Das ist eher die letzte mögliche. Hast du nicht eben noch geschrieben, du kennst die ID gar nicht? Zitieren
Guybrush Threepwood Geschrieben 6. Februar 2008 Geschrieben 6. Februar 2008 Dann ist irgendwo was falsch. Hast du denn den Code oben von dir entsprechend angepasst und eine entsprechende DialogProc übergeben? m_hMyDialog = ::CreateDialogIndirect(NULL, &ms.mHeader, NULL, NULL); [/PHP] Zitieren
Klotzkopp Geschrieben 6. Februar 2008 Geschrieben 6. Februar 2008 Es kommt keine Msg die WM_COMMAND ist. In welcher Nachrichtenbehandlungsfunktion willst du das denn verarbeiten? Dein Dialog hat ja gar keine. Zitieren
Nightfall Geschrieben 6. Februar 2008 Autor Geschrieben 6. Februar 2008 Hier Antworten auf eure Fragen und der neueste Stand: Wieso nicht? Du erstellst ihn doch. Zeig doch mal, wie du den Button erstellst. Der Button schickt Nachrichten an sein Elternfenster, also deinen Dialog. Du gibt aber bei CreateDialogIndirect gar keine DialogProc an, also kannst du auch nicht die Nachrichten des Buttons empfangen. Hast du denn den Code oben von dir entsprechend angepasst und eine entsprechende DialogProc übergeben? Also die ID des Buttons kenne ich jetzt dank dem Tipp von Guybrush (danke nochmal dafür). So erstelle ich den Dialog mit dem Button: Das Strukt was man dafür brauch: MyStruct ms = { { WS_CAPTION | WS_VISIBLE | DS_CENTER, 0, 1, 10, 10, 100, 100 }, 0, // 0x0000 -- Kein Menü 0, // 0x0000 -- Standart Dialog Klasse L"Test", // title: "Test" { WS_VISIBLE | WS_CHILD | WS_BORDER, 0, 1, 1, 50, 50, 1234 }, MyButton, // ID des Buttons. 0x0080, // Klassen ID von Buttons L"Test", // Button Beschriftung 0 }; Und hier der Create mit dem zugehörigen WinProc aufruf: m_hMyDialog = ::CreateDialogIndirect(NULL, &ms.mHeader, NULL, NULL); ::SetWindowLong(m_hMyDialog, GWL_WNDPROC, (LONG)OurWinProc); ::SetForegroundWindow(m_hMyDialog); Und hier mein WinProc: void OurWinProc(UINT message, WPARAM wParam, LPARAM lParam) { switch(message) { case WM_COMMAND: { switch(LOWORD(wParam)) { case MyButton: ; } } } } Zitieren
Guybrush Threepwood Geschrieben 6. Februar 2008 Geschrieben 6. Februar 2008 hmm also erstmal fällt mir auf die Signatur deiner Nachrichtenbehandlungsroutine falsch ist. Da muss ein Rückgabewert hin und die hat 4 Parameter DialogProc Function () Außerdem kannst du die doch direkt bei CreateDialogIndirect im letzten Parameter übergeben und dir somit den SetWindowLong Aufruf sparen. Zitieren
Klotzkopp Geschrieben 6. Februar 2008 Geschrieben 6. Februar 2008 Das Strukt was man dafür brauch:Warum benutzt du eigentlich nicht DLGTEMPLATEEX und DLGITEMTEMPLATEEX, sondern baust das in einer eigenen Struktur nach? Und hier der Create mit dem zugehörigen WinProc aufruf: m_hMyDialog = ::CreateDialogIndirect(NULL, &ms.mHeader, NULL, NULL); ::SetWindowLong(m_hMyDialog, GWL_WNDPROC, (LONG)OurWinProc); [/CODE]Du kannst die DialogProc auch gleich bei CreateDialogIndirect angeben, dafür ist der vierte Parameter da. Und hier mein WinProc:Du musst dich schon an die vorgegebene Signatur halten. Eine DialogProc hat so auszusehen: INT_PTR CALLBACK DialogProc(HWND, UINT, WPARAM, LPARAM); Und es wäre natürlich auch gut, wenn du in dem relevanten case-Block auch etwas tun würdest. Schließen kannst du den Dialog mittels EndDialog. Zitieren
Nightfall Geschrieben 6. Februar 2008 Autor Geschrieben 6. Februar 2008 Außerdem kannst du die doch direkt bei CreateDialogIndirect im letzten Parameter übergeben und dir somit den SetWindowLong Aufruf sparen. Ist erledigt. ^^ Und es wäre natürlich auch gut, wenn du in dem relevanten case-Block auch etwas tun würdest. Schließen kannst du den Dialog mittels EndDialog. Hab ich. ^^ So der WinProc sieht nun so aus: void OurWinProc(HWND h_Dialog, UINT message, WPARAM wParam, LPARAM lParam) { switch(message) { case WM_COMMAND: { switch(LOWORD(wParam)) { case MyButton: ::EndDialog(h_Dialog, NULL); } } } } Jetzt gibts nur noch ein Problem. Wenn ich den Button Klicke dann ist wParam = 1234 wParam müsste aber eigentlich die ID des Buttons haben. Oder habe ich grade nen Denkfehler? Zitieren
Klotzkopp Geschrieben 6. Februar 2008 Geschrieben 6. Februar 2008 So der WinProc sieht nun so aus:Der Rückgabetyp ist immer noch falsch. Den darfst du nicht einfach ändern. Jetzt gibts nur noch ein Problem. Wenn ich den Button Klicke dann ist wParam = 1234 wParam müsste aber eigentlich die ID des Buttons haben.Nicht ganz. Das untere WORD von wParam enthält die ID. Welche ID hat der Button denn überhaupt? Welchen Wert erwartest du? Sprich: Welchen Wert hat MyButton? Zitieren
Nightfall Geschrieben 6. Februar 2008 Autor Geschrieben 6. Februar 2008 Der Rückgabetyp ist immer noch falsch. Den darfst du nicht einfach ändern. wäre mein WinProc dann so korrekt? int* CALLBACK OurWinProc(HWND h_Dialog, UINT message, WPARAM wParam, LPARAM lParam) { switch(message) { case WM_COMMAND: { switch(LOWORD(wParam)) { case MyButton: ::EndDialog(h_Dialog, NULL); } } } return FALSE; } Nicht ganz. Das untere WORD von wParam enthält die ID. Bekomme ich den nicht durch diese Zeile? switch(LOWORD(wParam)) Welche ID hat der Button denn überhaupt? Welchen Wert erwartest du? Sprich: Welchen Wert hat MyButton? MyButton habe ich so definiert: #define MyButton 0xFfff Deswegen erwarte ich den Wert: 65535 Zitieren
Klotzkopp Geschrieben 6. Februar 2008 Geschrieben 6. Februar 2008 wäre mein WinProc dann so korrekt?INT_PTR, nicht int*. Bekomme ich den nicht durch diese Zeile? switch(LOWORD(wParam)) Doch, da ziehst du ja das LOWORD heraus. Aber im HIWORD von wParam steckt auch noch der Notification Code. Das ist in deinem Fall allerdings 0 (für BN_CLICKED). MyButton habe ich so definiert: #define MyButton 0xFfffDas ist eine denkbar schlechte Wahl. Dieser Wert (die höchstmögliche ID) ist normalerweise reserviert für Static Controls. Nimm mal etwas kleineres, z.B. 1000. Zitieren
Nightfall Geschrieben 6. Februar 2008 Autor Geschrieben 6. Februar 2008 Das ist eine denkbar schlechte Wahl. Dieser Wert (die höchstmögliche ID) ist normalerweise reserviert für Static Controls. Nimm mal etwas kleineres, z.B. 1000. Ich habe es mit einigen kleineren Werten ausprobiert. Das Problem ist das der Dialog dann nicht mehr in meiner MFC Anwendung aufgerufen wird. Zitieren
Klotzkopp Geschrieben 7. Februar 2008 Geschrieben 7. Februar 2008 Ich habe es mit einigen kleineren Werten ausprobiert. Das Problem ist das der Dialog dann nicht mehr in meiner MFC Anwendung aufgerufen wird. Was heißt das konkret? Gibt CreateDialogIndirect NULL zurück? Falls ja, was liefert GetLastError? Zitieren
Nightfall Geschrieben 7. Februar 2008 Autor Geschrieben 7. Februar 2008 Im Handle welches CreateDialogIndirect als Return wert hat steht: CXX0030: Fehler: Ausdruck kann nicht ausgewertet werden. GetLastError gibt 0 zurück. Zitieren
Klotzkopp Geschrieben 7. Februar 2008 Geschrieben 7. Februar 2008 Im Handle welches CreateDialogIndirect als Return wert hat steht: CXX0030: Fehler: Ausdruck kann nicht ausgewertet werden.Das ist eine Fehlermeldung des Debuggers, nicht der Rückgabewert. Zitieren
Nightfall Geschrieben 7. Februar 2008 Autor Geschrieben 7. Februar 2008 CreateDialogIndirect gibt doch ein HWND zurück. Und darin steht: unused=??? Oder was möchtest du wissen? :confused: Zitieren
Klotzkopp Geschrieben 7. Februar 2008 Geschrieben 7. Februar 2008 CreateDialogIndirect gibt doch ein HWND zurück. Und darin steht: unused=???In einem HWND kann nicht "unused=???" stehen, genauso wie in einem int nicht "HundKatzeMaus" stehen kann. Bist du sicher, dass du dir den Wert zum richtigen Zeitpunkt ansiehst, also direkt nach dem Aufruf? Zitieren
Nightfall Geschrieben 7. Februar 2008 Autor Geschrieben 7. Februar 2008 ja ich bin mir sicher. Hatte mich auch gewundert. Hab mal nen Screenshot gemacht. Zitieren
Klotzkopp Geschrieben 7. Februar 2008 Geschrieben 7. Februar 2008 Da steht's doch: Das Handle ist Null (0x00000000). CreateDialogIndirect ist also fehlgeschlagen. Welchen Wert gibt GetLastError direkt nach diesem Aufruf zurück? Zitieren
Nightfall Geschrieben 7. Februar 2008 Autor Geschrieben 7. Februar 2008 GetLastError() gibt "0" zurück. Zitieren
Empfohlene Beiträge
Dein Kommentar
Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.