OSD-Uhr, Message ohne Window, HotKey und Funktionen



  • Der Ursprung für diesen Thread stammt von diesem Thread

    Es ging darum HotKey Messages zu verarbeiten ohne ein Window, bzw. ein HWND zu haben.
    Um das mal anhand eines Beispiels zu verdeutlichen, habe ich daraus eine OSD-Uhr gemacht.
    Für viele kleine Sachen benötigen wir kein Fenster daher verstecken wir es ständig, doch für einige Programme brauchen wir kein Fenster zu verstecken, es reicht aus keins zu erstellen 😉
    An dieser Stelle mal ein Dankeschön an (UNREGISTRIERTER)Alt+S, und ein TuckTuck an Windows, für seine schlüssige SDK Doku.

    Hier mal der Dokumentierte Code der OSD-Uhr:

    #include <windows.h>
    #define COUNTELEMENTS(z) (sizeof((z)) / sizeof((z)[0]))
    
    SYSTEMTIME st;     /* Die Systemtime Struct */
    TCHAR szTime[32];  /* kennen wir doch, oder? */
    RECT toRec;        /* Das kennen wir auch */
    HFONT hFont;       /* ein Object Handle für nen Font */
    
    VOID CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime); /* Timer Procedure */
    
    /* unsere WinMain, das kennt jeder hier */
    int WINAPI WinMain(HINSTANCE hIns, HINSTANCE pIns, LPSTR pSt, int eg) 
    { 
        /* Ein Font Objekt erstellen, göße 24 (keine echten 24pix), Bold, Font:Arial */
        hFont = CreateFont(24,0,0,0,FW_BOLD,0,0,0,0,0,0,0,FIXED_PITCH,"Arial");
        /* Timer setzten mit unserer Timer Procedure */
        SetTimer(NULL, 0, 200, TimerProc); 
        MSG message; /* unsere Message Struct */
        /* Nun Regestrieren wir Strg+Q als HotKey um damit unser Programm zu beenden */
        RegisterHotKey(NULL, 1000, MOD_CONTROL, 'Q');
        /* Die message Schleife */ 
        while(GetMessage(&message, NULL, 0, 0)) 
        {   
            if (message.message == WM_HOTKEY)
            {
                    /* Anzeige bereich zurücksetzten */
                    RedrawWindow(NULL,&toRec,NULL, RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN);
                    PostQuitMessage(0);
            }    
            /* DispatchMessage würde nicht benötigt, wenn wir nicht eine TimerProc da wäre */
            /* da wir aber eine TimerProc haben müßen wir die Nachricht weiterleiten an diese */                  
            DispatchMessage(&message); 
        }    
        return message.wParam; 
    }
    
    /* nun unsere TimerProc */
    VOID CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
    {
        /* das TagRect mit Daten Fütern (Bereich der Anzeige) */
        toRec.left = 5;
        toRec.top = 5;
        toRec.right = 200;
        toRec.bottom = 35;
        /* die Uhrzeit holen */
        GetLocalTime (&st);
        /* und in Klartext ins TCHAR schreiben */
        GetTimeFormat (LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP, &st, NULL, szTime, COUNTELEMENTS(szTime));
        /* Hintergrund neu Aufbauen, damit die Ausgabe sich nicht übermalt */
        RedrawWindow(NULL,&toRec,NULL, RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN);
        /* Sleep(1) um Windows seine WM_PAINT mesages senden zu lassen, damit der Hintergrund auch neu kommt */
        Sleep(1);
        HDC hdc;
        /* DC des Desktop (das was man sieht) holen */
        hdc = GetDC(NULL);
        /* neuen Font zuordnen (unseren) */
        HGDIOBJ OldObject = SelectObject(hdc,hFont);
        /* Transparent damit die Schrift kein Hintergrund hat */
        SetBkMode(hdc,TRANSPARENT);
        /* so, erst Textfarbe Schwarz als Schatten */
        SetTextColor(hdc,RGB(0,0,0));
        /* und um 3 Pixel verschoben ausgeben (Schatten) */
        TextOut(hdc, toRec.left+3, toRec.top+3, szTime, strlen(szTime));
        /* jetzt Textfarbe Gelb als eigentliche Ausgabe */
        SetTextColor(hdc,RGB(255,255,0));
        /* und an der Orginal Stelle ausgeben */
        TextOut(hdc, toRec.left, toRec.top, szTime, strlen(szTime));
        /* DC wieder freigeben */
        ReleaseDC(NULL,hdc);
        /* hFont Objekt zurücksetzten */
        SelectObject(hdc, OldObject);            
    } 
    
    /* Fertisch dat wa dat */
    

    Das kann man noch zum nen Wecker ausbauen, nur für die eingabe der Weckzeit, muß wieder ein Window oder Dialog her.

    Dennoch vertrette ich die Meinung das dies nicht Anwenderfreundlich ist, freundlicher wird es z.B. mit einem TrayIcon und/oder ähnlich.



  • So ist das doch allerübelst dirty. Das flackert und wenn man mit anderen Fenstern darüber zieht gibt es Grafikfehler.

    Also wenn ich sowas machen würde, würde ich ein Fenster mit Regions erstellen.



  • region schrieb:

    So ist das doch allerübelst dirty. Das flackert und wenn man mit anderen Fenstern darüber zieht gibt es Grafikfehler.

    Also wenn ich sowas machen würde, würde ich ein Fenster mit Regions erstellen.

    Hmmm, du hast nicht verstanden worum es geht! Es geht nicht um die Anzeige der Uhr, sondern darum kein Fenster zu erstellen, auch keins mit Regionen. Lese mal vom vorgänger Theard die letzten 2 Seiten, dann verstehst du worum es geht.
    Das kann man aber auch sauberer bekommen, ich wollte aber als Windowless beispiel den Code begrenzen.



  • Guten Tag,

    kann man auch das Flackern vermeiden, ohne ein Fenster erstellen und/oder benutzen zu müssen? Vielen Dank im Voraus für Antworten, die für einen WinAPI-C-Programmierer hilfreich sind.

    Mit freundlichen Grüßen

    ein Interessierter



  • Evtl. hilft DoubleBuffering 🙄



  • flenders schrieb:

    Evtl. hilft DoubleBuffering 🙄

    Jain, in der Richtung schon, aber noch etwas eleganter, werde das mal raussuchen
    wie ich es bei meinem mediaPlayer habe, aber das sollte jetzt eigentlich
    nicht das Thema sein, sondern die Anwender Unfreundlichkeit kein Fenster
    zu bieten, oder sonst jeglicher visuelle Hinweis auf das Programm.


Anmelden zum Antworten