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 + ExtTextOut

    window = 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 danach PostMessage( ... WM_CLOSE ... ); (das passiert aus einem anderen thread, falls das von interesse ist)

    1. 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.
    2. nun wird aber das zu erst instantiierte fenster zwar im vordergrund angezeigt, die folgenden jedoch nicht mehr.
    3. 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 geschafft

    So 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


  • Mod

    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 deactivated

    wieso 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.)


  • Mod

    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 von SWP_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.


Log in to reply