InvalidateRect() - Desktop reagiert nicht



  • Hallo, ich bin gerade dabei mit der GDI etwas auf den Desktop zu zeichnen und versuche es durch Neuzeichnen eines desktopteils mit InvalidateRect() wieder zu löschen.

    Das Problem ist nur dass der Desktop auf InvalidateRect() gar nicht zu reagieren scheint weil einfach gar nichts passiert 😞 .

    Das Handle von GetShellWindow() bzw. GetDesktopWindow() scheint auch zu stimmen und InvalidateRect() gibt true zurück, eigentlich sollte also alles stimmen 😉

    hier mal der relevante Codeausschnitt:

    RECT rect;
       rect.left=110;
       rect.top=110;
       rect.right=220;
       rect.bottom=220;
       bool success=InvalidateRect(GetShellWindow(), &rect , TRUE);
    

    bei allen andere Fenster funktioniert der code auch, nur nicht am desktop, deshalb sollte er auch stimmen^^

    kann ich also den Desktop irgendwie (ggf. durch eine andere Funktion) dazu bringen auf InvalidateRect() zu reagieren? und wenn nicht, gibt es noch eine andere Möglichkeit einen Teil eines Fenster neu zu zeichnen?

    danke schonmal,
    andi01.



  • kann man den Desktop wirklich nicht teilweise neu zeichnen? das kann doch nich sein...



  • Man sollte gar nicht direkt auf den Desktop zeichen.
    Besonders unter Vista/Win7 nicht:

    blog schrieb:

    Drawing To and Reading From the Screen -- Baaaad!

    Lastly, since we're on the redirection topic, one particularly dangerous practice is writing to the screen, either through the use of GetDC(NULL) and writing to that, or attempting to do XOR rubber-band lines, etc. There are two big reasons that writing to the screen is bad:

    1. It's expensive... writing to the screen itself isn't expensive, but it is almost always accompanied by reading from the screen because one typically does read-modify-write operations like XOR when writing to the screen. Reading from the video memory surface is very expensive, requires synchronization with the DWM, and stalls the entire GPU pipe, as well as the DWM application pipe.

    2. It's unpredictable... if you somehow manage to get to the actual primary and write to it, there can be no predictability as to how long what you wrote to the primary will remain on screen. Since the UCE doesn't know about it, it may get cleared in the next frame refresh, or it may persist for a very long time, depending on what else needs to be updated on the screen. (We really don't allow direct writing to the primary anyhow, for that very reason... if you try to access the DirectDraw primary, for instance, the DWM will turn off until the accessing application exits)

    http://blogs.msdn.com/greg_schechter/archive/2006/05/02/588934.aspx

    Nimm ein transparentes Fenster 😉

    Es kann sehr gut sein das der Desktop sich denkt, ich hab grad keine Lust mich neu zu zeichnen, also mach ichs einfach mal nicht.
    Man malt halt nicht in fremde Anwendungen rein, das ist im recht frei übertragenen Sinne ja so, als würdest du nicht bei dir aufs Klo gehen, sondern beim Nachbarn wenn er grad nich guckt...



  • ok, das mit dem transparenten Fenster ist vermutlich tatsächlich die einzige gut Lösung...

    ich hab es mal als eine Art Vorversuch mit Notepad getestet, mit folgendem Code:

    #include <windows.h>   
    #include <gdiplus.h>   
    #include<conio.h> 
    #include<iostream> 
    #pragma comment(lib, "gdiplus.lib") 
    #include<wchar.h> 
    
    using namespace Gdiplus; 
    using namespace std; 
    
    HDC hdc=GetWindowDC(FindWindow(NULL, L"Unbenannt - Editor")); 
    
    void rechteck(int x, int y, int width, int length) 
    { 
        Graphics graphics(hdc); 
        Rect rect(x, y, width, length); 
        Pen pen(Color(255, 255, 0, 0), 1); 
        graphics.DrawRectangle(&pen, rect); 
    } 
    
    int main() 
    { 
        for(;;) 
        { 
        system("cls"); 
       GdiplusStartupInput gdiplusStartupInput; 
       ULONG_PTR           gdiplusToken;   
       GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); 
       //... 
       system("PAUSE"); 
       cout<<"zeichne rechteck 1\n"; 
       rechteck(50, 50, 10, 10); 
       Sleep(2000); 
       rechteck(10, 10, 10, 10); 
       cout<<"zeichne rechteck 2\n"; /*dieses Rechteck sollte nachher von InvalidateRect() komplett gelöscht werden!*/
       Sleep(2000); 
       RECT rect; 
       rect.left=50; 
       rect.top=50; 
       rect.right=600; 
       rect.bottom=600; 
       bool success=InvalidateRect(FindWindow(NULL, L"Unbenannt - Editor"), &rect, FALSE); 
       if(success==true) 
       { 
           cout<<"rect successfull invalidated\n"; 
       } 
       if(success==false) 
       { 
           cout<<"error while trying to invalidate rect\n"; 
       } 
       Sleep(2000); 
       // ... 
       GdiplusShutdown(gdiplusToken); 
        } 
    }
    

    Dabei hat sich allersings ein Problem mit den Koordinaten ergeben:
    denn das 2.gezeichnete Rechteck solle eigentlich von Invalidate Rect komplett gelöscht werden, nicht nur teilweise.

    Dabei stimmen die Koordinaten des gezeichneten und des gelöschten Rechtecks doch überein!?

    hier mal ein Screen: http://rapidshare.de/files/49044427/fehler.bmp.html

    Muss ich die irgendwie umrechnen? oder woran liegt das?

    danke schonmal,
    andi01.



  • Ich hab grad ein Beispielprojekt gebaut, wo ein transparentes Fenster erzeugt wird und zufällig alle paar ms irgendwohin ne Ellipse gezeichnet wird: draw_on_desktop.rar

    msdn schrieb:

    A pointer to a RECT structure that contains the client coordinates of the rectangle to be added to the update region. If this parameter is NULL, the entire client area is added to the update region.

    D.h. ja du musst umrechnen (es gibt da z.B. ScreenToClient(), ClientToScreen()...)

    (btw: rapidshare ist suboptimal für Bilder, nimm lieber sowas wie http://imageshack.us/ oder irgendnen anderen image-hoster...)



  • wie soll das mit ScreenToClient gehen?

    die msdn bietet ja 2 Möglichkeiten zu der Funktion:

    1.:

    msdn schrieb:

    void ScreenToClient(
       LPPOINT lpPoint 
    ) const;
    

    lpPoint
    Points to a CPoint object or POINT structure that contains the screen coordinates to be converted.

    damit habe ich es versucht.

    ich habe es so versucht:

    HWND editor=FindWindow(NULL, L"Unbenannt - Editor");
    
       RECT rect; 
       rect.left=110; 
       rect.top=110; 
       rect.right=220; 
       rect.bottom=220;
    //konvertieren:
       POINT oben_links;
       oben_links.x=rect.left;
       oben_links.y=rect.top;
    
       POINT unten_rechts;
       unten_rechts.x=rect.right;
       unten_rechts.y=rect.bottom;
    
       ScreenToClient(editor, static_cast<LPPOINT>(&oben_links));
       ScreenToClient(editor, static_cast<LPPOINT>(&unten_rechts));
    
       rect.left=oben_links.x;
       rect.top=oben_links.y;
       rect.right=unten_rechts.x;
       rect.bottom=unten_rechts.y;
    
       //Rechteck löschen:
    
       bool success=InvalidateRect(editor, &rect , TRUE);
    

    sehr umständlich und auch nicht wirklich erfolgreich, hier mal ein screen:

    http://img64.imageshack.us/img64/320/fehlernachkonvertierung.png

    dann gibt es da laut msdn noch ne 2. Möglichkeit die viel einfacher wäre, aber der Compiler (MS Visual C++ 2008 EXpress Edition) leider nicht zu kennen scheint:

    msdn schrieb:

    void ScreenToClient(
       LPRECT lpRect 
    ) const;
    

    lpRect
    Points to a CRect object or RECT structure that contains the screen coordinates to be converted.

    wenn ich es damit versuche sagt der Compiler:

    Microsoft Visual C++ 2008 Express Edition schrieb:

    error: ScreenToClient(). Konvertierung des Parameters 2 von RECT+ in LPPOINT nicht möglich.

    deshalb scheint er diese Variante nicht zu kennen 😞 .

    wie kann ich es denn nun richtig machen? ein kleines Codebeispiel wäre schön 🙂

    danke schonmal,
    andi01.



  • Du hast da in der MSDN scheinbar die MFC-Version gefunden.
    Was du suchst ist:
    http://msdn.microsoft.com/en-us/library/dd162952(VS.85).aspx



  • wie muss ich es denn richtig machen?

    ich mache es momentan so:

    //konvertieren:
       POINT oben_links;
       oben_links.x=110;
       oben_links.y=110;
    
       POINT unten_rechts;
       unten_rechts.x=220;
       unten_rechts.y=220;
    
       ScreenToClient(editor, static_cast<LPPOINT>(&oben_links));
       ScreenToClient(editor, static_cast<LPPOINT>(&unten_rechts));
    
       rect.left=oben_links.x;
       rect.top=oben_links.y;
       rect.right=unten_rechts.x;
       rect.bottom=unten_rechts.y;
    
       //Rechteck löschen:
    
       bool success=InvalidateRect(editor, &rect , TRUE);
    

    doch das Ergebnis bleibt gleich(siehe Screenshot). was ist an meinem Code denn falsch?

    mfg,
    andi01.



  • Sieht richtig aus.
    Hast Du Vista/Win7? Da könnte ich mir so ein Verhalten vorstellen...



  • ne win XP SP2, aber das ergebnis sieht immernoch aus wie am 1. screen.

    weiß irgendjemand woran das liegt und v.a. was ich besser/anders machen kann?

    edit:

    -Könnte das vielleicht daran liegen?:

    -ich ermittle den Device Context mit GetWindowDC(). sollte ich vllt lieber GetDC() nehmen?

    -sollte ich vllt ClientToScreen() statt ScreenToClient() nehmen?

    danke schonmal,
    andi01.



  • irgendwie muss das doch hinzukriegen sein... immerhin kann man eigentlich bei allen Zeichenprogrammen das Gezeichnete löschen.


  • Mod

    andi01 schrieb:

    irgendwie muss das doch hinzukriegen sein... immerhin kann man eigentlich bei allen Zeichenprogrammen das Gezeichnete löschen.

    Jo! Die zeicnen auch in ihre eigenen Fenster und nicht irgendwohin in andere Fenster...



  • Martin Richter schrieb:

    Jo! Die zeicnen auch in ihre eigenen Fenster und nicht irgendwohin in andere Fenster...

    das will ich ja eigentlich auch machen mit einem eigenen transparenten Fenster über dem Desktop, aber deswegen wird sich wohl kaum etwas an der Umrechnung der Koordinaten ändern, oder?

    mein Problem war ja genau diese Umrechnung(siehe Screenshot).

    mfg,
    andi01.


  • Mod

    Was ist daran so schwer. Es gibt Client Koordinaten und Fenster Koordinaten.
    Was für Koordinaten willst Du denn nun wohin umrechnen?
    Entsprechende nimmst Du ClientToScreen oder ScreenToClient.



  • Martin Richter schrieb:

    Was ist daran so schwer.

    das problem ist dass ich die Koordinaten bereits mit ScreenToClient() (testweiese sogar schon mit ClientToScreen() ) umgerechnet habe und aber, wie man am screenshot deutlich erkennen kann, die Umrechnung irgendwie nicht richtig zu funktionieren scheint weil das testrechteck nur teilweise gelöscht wird.

    mfg,
    andi01.


Anmelden zum Antworten