Kann ein konsolenprogramm ein WM_CLose auf seine Shell abfangen?
-
Hallo,
ich habe ein reines C Konsolenprogramm nach Windows portiert. Es wird von einer anderen Applikation im Hintergrund gestartet und soll von dieser Applikation auch wieder geschlossen werden.
Diese Applikation startet einfach C:\foobar.exe worauf ein CMD-Fenster aufgeht und in dem läuft mein C-Programm. Alles fein. Jetzt will die Applikation das Programm irgendwann wieder schließen.
Allerdings wird das Programm bzw die Shell in der es läuft, nicht geschlossen. Ich habe daher einen Signalhandler auf so ziemlich alle POSIX-Signale installiert und empfange kein einziges. Eine Nachfrage beim Hersteller der Applikation förderte nun zutage, dass sie eine "WM_Close" message sendet.
Da das wohl eine Windows-message ist, kann ich sie in einem reinen Konsolenprogramm wohl nicht abfangen.
Mein Frage ist daher: Kann ich irgendein minimales, möglichst noch nicht-sichtbares Fenster erzeugen (vielleicht eine Message-Box), das auf die WM-Close message hört, so dass ich dann mein Konsolenprogramm kontrolliert herunterfahren kann?
Gruß,
Phil
-
Siehe SetConsoleCtrlHandler Function
http://msdn.microsoft.com/en-us/library/ms686016(VS.85).aspxAnsonsten:
- Erzeuge eine UI Programm (kein Consolen Programm),
- Erzeuge ein verstecktes Fenster mit einem Dir bekannten Fensterklssennamen
- Sende an dieses Fenster, dass Du mit FindWindow findet WM_CLOSE
- In diesem Fenster löst Du das schließen der Anwendung aus.
-
Martin Richter schrieb:
Siehe SetConsoleCtrlHandler Function
http://msdn.microsoft.com/en-us/library/ms686016(VS.85).aspxProbiert, geht nicht. Scheinbar löst das WM_CLOSE kein Ctrl-Break oder Ctrl-C Event aus.
Ansonsten:
- Erzeuge eine UI Programm (kein Consolen Programm),
- Erzeuge ein verstecktes Fenster mit einem Dir bekannten Fensterklssennamen
- Sende an dieses Fenster, dass Du mit FindWindow findet WM_CLOSE
- In diesem Fenster löst Du das schließen der Anwendung aus.Gibts dafür eine fertige Lösung? Wieviel Zeilen sind das etwa?
Ich habe noch nie WinAPI programmiert, ich bin Unixxer ...
-
Aber sicher wird der aufgerufen. Lies doch die Doku:
http://msdn.microsoft.com/en-us/library/ms683242CTRL_CLOSE_EVENT
2 A signal that the system sends to all processes attached to a console when the user closes the console (either by clicking Close on the console window's window menu, or by clicking the End Task button command from Task Manager).Du kannst mit dem VS Wizard Dir den Rahmen für solch ein Gui Programm erzeugen lassen. Dann musst Du höchstens 10 Zeilen ändern...
-
Martin Richter schrieb:
Aber sicher wird der aufgerufen. Lies doch die Doku:
http://msdn.microsoft.com/en-us/library/ms683242Genau das habe ich gemacht. Und ja, der Cntrl-Close handler wird auch aufgerufen, wenn ich das "X" am consolenfenster anklicke.
Nur leider scheint die Applikation, die das Konsolenfenster schließen soll, dieses nicht schließen zu können, weil sie keinen Window-handle darauf findet (ist meine Vermutung, siehe hier: http://support.microsoft.com/kb/124103/en-us)Du kannst mit dem VS Wizard Dir den Rahmen für solch ein Gui Programm erzeugen lassen. Dann musst Du höchstens 10 Zeilen ändern...
Ach du schei....
Ich habe mir jetzt mal von VC++ 2010 den Boilerplate für eine Win32 Applikation erzeugen lassen. Heilige Mutter Gottes, das sind zusammen fast 400 Zeilen !!!! Geht's noch?Ich habe das ganze jetzt mal für mein Programm auf folgenden Code reduziert:
#define WIN32_LEAN_AND_MEAN #include <windows.h> #define MAX_LOADSTRING 100 #define IDI_TEST 107 #define IDI_SMALL 108 #define IDC_TEST 109 HINSTANCE hInst; TCHAR szTitle[MAX_LOADSTRING]; // The title bar text TCHAR szWindowClass[MAX_LOADSTRING]; BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { HWND hWnd; hInst = hInstance; // Store instance handle in our global variable hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); if (!hWnd) { return FALSE; } ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; } LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_CLOSE: Log() << Log::Info << "Closing" << Log::endl; // Hier das tun, was ich eigentlich tun will beim schließen break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_TEST)); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = MAKEINTRESOURCE(IDC_TEST); wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); return RegisterClassEx(&wcex); } int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { MSG msg; MyRegisterClass(hInstance); // Perform application initialization: if (!InitInstance (hInstance, nCmdShow)) { return FALSE; } // Main message loop: while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); // hierdrin meine eigentliche Main-Funktion aufrufen... } return (int) msg.wParam; }Das kompiliert zwar, gibt aber folgenden Linker error:
/mingw/lib/libmingw32.a(main.o)(.text+0x106):main.c: undefined reference to `WinMain@16' collect2: ld returned 1 exit statusBoah... Was eine gequirlte Kacke um das zu tun, was unter Unix die Zeile
signal(SIGTERM, &my_signal_handler);macht.

-
Okay, es ist wohl keine so gute Idee, von Visual Studio erzeugten Code mit minGW zu kompilieren.
Ich habe jetzt stattdessen diesen Code hier benutzt : http://osix.net/modules/article/?id=670
Damit habe ich das Problem, dass er bei allen String-Konstanten folgenden Fehler ausgibt:
error: cannot convert `const char*' to `WCHAR*' in initializationEDIT: Gelöst. Man muss L"Hello World" statt "Hello World" schreiben.