createwindowex mit eigener wnd_class
-
hallo.
ich möchte eine art notification-box erstellen.
also ein popup, was wenige sekunden sichtbar ist; keinen focus bekommt aber immer angezeigt wird (topmost window oder was man da sagt).das ist mir so weit auch gelungen, aber irgendwie habe ich irgendwas in der doku übersehen und finde den fehler (siehe ganz unten) nicht...
also geht es mir eher um die generelle herangehensweise und ein paar code-fetzen:
RegisterClassEx / einmalig vor dem ersten createwindowex
LRESULT CALLBACK msg_callback_nop( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam ) { switch( Msg ) { case WM_CLOSE: DestroyWindow( hWnd ); return 0; case WM_DESTROY: PostQuitMessage( 0 ); return 0; default: return DefWindowProc( hWnd, Msg, wParam, lParam ); } } void register_wnd_classes() { WNDCLASSEX wcx; wcx.cbSize = sizeof(wcx); // size of structure wcx.lpfnWndProc = msg_callback_nop; wcx.lpszClassName = "my_empty_class"; wcx.style = CS_NOCLOSE; wcx.cbClsExtra = 0; // no extra class memory wcx.cbWndExtra = 0; // no extra window memory wcx.hInstance = 0; // handle to instance wcx.hIcon = 0; wcx.hCursor = 0; wcx.hbrBackground = 0; wcx.lpszMenuName = 0; wcx.hIconSm = 0; ATOM ok = RegisterClassEx(&wcx); ok = ok || GetLastError() == ERROR_CLASS_ALREADY_EXISTS; if (ok == 0) throw std::runtime_error("RegisterClassEx: " + get_last_error()); }
das anzeigen an sich:
CreateWindowEx + ExtTextOutwindow = CreateWindowEx( WS_EX_CLIENTEDGE, "my_empty_class", 0, WS_VISIBLE | WS_DISABLED | WS_POPUP, //window style pos_x, pos_y, //pos size_x, size_y, //size NULL, //hWndParent NULL, //hMenu this_hinstance(), //hInstance NULL //lpParam ); device_context = GetDC( window ); //... BOOL error = ExtTextOut( device_context, x_start, y_start, ETO_OPAQUE, &rect, to_show.c_str(), int(to_show.size()), 0 );
schließen nach ein paar sekunden mittels
ShowWindow( SW_HIDE );
ReleaseDC(window, device_context);
und danachPostMessage( ... WM_CLOSE ... );
(das passiert aus einem anderen thread, falls das von interesse ist)- eine ganze weile wurde das fenster gar nicht gezeigt. ich bin mir nicht sicher, warum das so war und warum es jetzt wieder immer angezeigt wird.
- nun wird aber das zu erst instantiierte fenster zwar im vordergrund angezeigt, die folgenden jedoch nicht mehr.
- grundsätzlich scheint die idee keine gute zu sein; habe gerade noch mal vlc aufgemacht und durch das fenster vor vlc hat mein gesamter PC nicht mehr reagiert. offensichtlich wurde nach jedem repaint vom vlc auch mein fenster neu gezeichnet. hab dann per handy zuerst vlc und später mein programm gekillt, um überhaupt mal wieder den taskmgr aufzubekommen.
abgesehen von fertigen lösungen: wie würde man so etwas denn richtig anstellen?
danke schon mal
-
unskilled schrieb:
RegisterClassEx / einmalig vor dem ersten createwindowex
Stimmt das wirklich? Sonst treten oben erwähnte Fehler auf. Solche Probleme hatte ich auch schon mal, habe mir dazu folg. Notizen gemacht:
In WinMain() muß zuerst die Unterfensterklasse registriert werden, bevor das Hauptfenster erzeugt wird. Danach kann ein Unterfenster mit Stil WS_POPUP in WinMain oder MainWndProc/WM_CREATE erzeugt werden. Ein Unterfenster mit Stil WS_CHILD kann in WinMain erzeugt werden, aber nicht in MainWndProc/WM_CREATE, anderenfalls wird dadurch folg. Systemfehler verursacht: ERROR_TLW_WITH_WCHILD 1406 (0x57E), Cannot create a top-level child window
Wird das Hauptfenster erzeugt, bevor die Unterfensterklasse registriert wurde, dann verursacht der Versuch, in MainWndProc\WM_CREATE ein Unterfenster mit Stil WS_CHILD oder WS_POPUP zu erzeugen, den folg. Systemfehler: ERROR_CANNOT_FIND_WND_CLASS 1407 (0x57F), Cannot find window class
Ansonsten laufen o.g. Codeschnipsel bei mir problemlos.
-
danke für die rückmeldung
dann ist ja gut, wenn das alles richtig ist - habe mittlerweile auch keine probleme mehr damit. hatte nur angst, dass ich irgendwas undefiniertes mache usw...^^rudi994 schrieb:
unskilled schrieb:
RegisterClassEx / einmalig vor dem ersten createwindowex
Stimmt das wirklich?
ziemlich sicher; aber das bekommt man doch auch mit, dass es weitere male unnötig ist. deshalb ja auch der kleine umweg beim fehlercode auswerten:
ATOM ok = RegisterClassEx(&wcx); ok = ok || GetLastError() == ERROR_CLASS_ALREADY_EXISTS;
topmost hab ich übrigens nur mit nem zusätzlichen
SetWindowPos
-Aufruf geschafft:BOOL success = SetWindowPos(window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
bb
edit: das beschriebene flackern war übrigens ein ganz anderer fehler. ich hatte ausversehen beim fehlerhaften initialisieren eine endlosschleife gebaut und deshalb kam das fenster immer wieder neu; was für mich den anschein machte, es würde flackern. und weil ich noch dazu die log im gleichen ordner hatte, hat windows UAC die log-einträge verhindert, die mir das gesagt hätten. *shame*
danke für die hilfe jedenfalls
-
unskilled schrieb:
topmost hab ich übrigens nur mit nem zusätzlichen
SetWindowPos
-Aufruf geschafftSo wird das auch im WinAPI-Tutorial auf MSDN empfohlen:
WS_EX_TOPMOST (0x00000008L) - Das Fenster sollte über allen Fenstern platziert werden, die keine Topmost-Fenster sind, und es sollte auch dann über diesen bleiben, wenn das Fenster deaktiviert wird. Zum Hinzufügen oder Entfernen dieses Stils soll die Funktion SetWindowPos() verwendet werden.Allerdings: Auch ohne SetWindowPos() bleibt das Fenster hier bei mir immer im Vordergrund, wenn ich WS_EX_TOPMOST in CreateWindowEx() als 1. Parameter (erweit. Fensterstil) angebe. LG
-
Das ist ja auch der Sinn. Den Stil hast Du angegeben.
HWND_TOPMOST gilt nur intern in der eigenen Z-Order der Owner/Parent Kette.
-
Martin Richter schrieb:
HWND_TOPMOST gilt nur intern in der eigenen Z-Order der Owner/Parent Kette.
<a href= schrieb:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms633545(v=vs.85).aspx">
HWND_TOPMOST
Places the window above all non-topmost windows. The window maintains its topmost position even when it is deactivatedwieso aber WS_EX_TOPMOST nicht ausreicht, kann ich nicht sagen. deshalb die "frage".
(SWP_NOOWNERZORDER
war aber überflüssig, ja. hab keine anderen fenster. ist mehr oder mindest ein dienst, der aber ein paar wichtige änderungen anzeigen soll.)
-
Diu irrst.
Durch SWP_NOOWNERZORDER wird der erste Parameter in SetWindowPos ignoriert.RTFM (Read the fine MSDN)
-
Martin Richter schrieb:
Durch SWP_NOOWNERZORDER wird der erste Parameter in SetWindowPos ignoriert.
also ich hab nur "Does not change the owner window's position in the Z order." gefunden. und da ich keinen owner habe bzw der owner kein fenster hat, ist mir das ja egal.
du redest vll vonSWP_NOZORDER
?!wieso ich ohne setwindowpos kein foreground hinbekomme, versteh ich noch immer nicht... stört mich aber auch nicht all zu sehr, weils mit ja klappt.