Handle von Desktophintergrund und auf diesen zeichnen

  • VB.NET

Es gibt 9 Antworten in diesem Thema. Der letzte Beitrag () ist von Nitro-X.

    Handle von Desktophintergrund und auf diesen zeichnen

    Hallo zusammen,

    da ich sehr lange nichts mehr richtiges programmiert habe und noch nie verstanden habe, wie man Fenster "übernimmt" um anschließend auf diese zu zeichnen frage ich nun hier.

    Kann mich da jemand einführen und das ganze für den Anfang möglichst simpel erklären?
    Ich will mir im Unterricht einfach mal einen anderen Desktophintergrund einblenden, evtl. auch die CPU Auslastung, usw.. (Ja das darf ich, geht aber aufgrund der Nutzerbeschränkungen nicht.) :D

    Zur Verfügung steht mir Visual Basic 2010 Express Edition. Also auch kein Spy++ (mit dem ich auch noch nicht umgehen kann). :D
    M.f.G. Nitro-X
    Gute Spieler cheaten schlecht! 8-)

    Button1.Visible = False
    If Button1.Click then Shell ("C:\brain.exe")
    end if
    Das Thema hatten wir erst.
    Text Mittig, in Vordergrund und entfernen

    Die Lösung dürfte allerdings nicht deinen Vorstellungen entsprechen. Denn sobald der Desktop aktualisiert wird verschwindet die gezeichnete Grafik.
    Spoiler anzeigen

    p/Invoke

    C#-Quellcode

    1. public static class NativeMethodes
    2. {
    3. // http://www.pinvoke.net/default.aspx/user32/GetWindowDC.html
    4. [DllImport("user32.dll")]
    5. public static extern IntPtr GetWindowDC(IntPtr hWnd);
    6. }


    C#-Quellcode

    1. private void DrawOnDesktop()
    2. {
    3. IntPtr pHdc = NativeMethodes.GetWindowDC(IntPtr.Zero); // IntPrt.Zero ermöglicht das Zeichnen auf den Desktop
    4. using (Graphics g = Graphics.FromHdc(pHdc)) {
    5. g.DrawString("Hallo Welt", new Font("impact", 50, FontStyle.Bold), new SolidBrush(Color.Red), Screen.PrimaryScreen.WorkingArea, CenterText());
    6. }
    7. }
    8. private StringFormat CenterText()
    9. {
    10. StringFormat stringFormat = new StringFormat();
    11. stringFormat.Alignment = StringAlignment.Center;
    12. stringFormat.LineAlignment = StringAlignment.Center;
    13. return stringFormat;
    14. }

    Bilder
    • preview.PNG

      34,56 kB, 827×507, 171 mal angesehen
    Danke, das schaue ich mir nachher mal an.

    Fakiz schrieb:

    Denn sobald der Desktop aktualisiert wird verschwindet die gezeichnete Grafik.
    Ach, notfalls greife ich irgendwo ab, ob ein Fenster im Vordergrund ist und zeichne es neu, sobald man den Desktophintergrund wieder sehen kann.
    Ich habe auch schon an DirectX bzw. Direct2D gedacht, allerdings soll das mit den API´s ein ziemlicher Aufwand sein.

    Ich bin mir nur nicht sicher, wie ich den hintersten Teil mit dem Desktophintergrund überzeichnen kann. Das soll doch eine untergeordnete Instanz von einem Programm sein?
    Notfalls, könnte ich auch eine Form mit Picturebox unter die Icons bzw. vor den Desktophintergrund legen. Falls das irgendwie möglich ist.
    M.f.G. Nitro-X
    Gute Spieler cheaten schlecht! 8-)

    Button1.Visible = False
    If Button1.Click then Shell ("C:\brain.exe")
    end if
    Notfalls, könnte ich auch eine Form mit Picturebox unter die Icons bzw. vor den Desktophintergrund legen. Falls das irgendwie möglich

    Das würde ich dir empfeheln, zumindest wenn du die CPU auslastung haben willst. Dann kannst du aber nicht ohne weiteres auf die Verknüpfungen zugreifen und der Hintergrund wird sich auch nicht ändern.

    Danke, das schaue ich mir nachher mal an.

    Für dich wäre dann die Methode Graphics.FromHwnd interesant. Dabei sparst du dir die p/Invoke's.

    Das soll doch eine untergeordnete Instanz von einem Programm sein?

    Soweit ich mich entsinne ist das der Explorer

    Fakiz schrieb:

    Dann kannst du aber nicht ohne weiteres auf die Verknüpfungen zugreifen und der Hintergrund wird sich auch nicht ändern.
    Sicher? Denn die Icons sollen wohl eine eigene Ebene sein, so könnte ich einfach eine Form zwischen Hintergrundbild legen.

    Fakiz schrieb:

    Graphics.FromHwnd
    Das habe ich heute beim stöbern auch schon entdeckt. Hatte nur keine Zeit mir das anzusehen.

    Fakiz schrieb:

    Soweit ich mich entsinne ist das der Explorer
    In einem Thread in dem unter anderem @Artentus gepostet hat, war da immer die Rede von einem "WorkerW", immerhin verschwindet der Hintergrund auch nicht, wenn ich die Explorer.exe beende. Deswegen bin ich davon ausgegangen, dass es sich nicht um den Explorer handelt.
    M.f.G. Nitro-X
    Gute Spieler cheaten schlecht! 8-)

    Button1.Visible = False
    If Button1.Click then Shell ("C:\brain.exe")
    end if
    so könnte ich einfach eine Form zwischen Hintergrundbild legen.

    Ah, ich habe dich falsch verstanden. Dann kannst du Graphics.FromHwnd vergessen. Hier benötigst du Graphics.FromHdc.

    war da immer die Rede von einem "WorkerW"

    Dann passt der Ansatz den ich hier gepostet habe doch. Du benötigst dann nur das richtige Handle. Ich glaube das es von Progman.exe ist. Werd das später mal kurz testen. Interesiert mich jetzt auch.
    Ich hab mich mit diesem Thema schon mal beschäftigt. Zumindest in neueren Windows-Versionen ist es aber leider nicht so einfach. Der Desktophintergrund ist zwar tatsächlich ein anderes Fenster als das ListView-Control, das die Icons anzeigt, allerdings kann man nicht einfach auf den Hintergrund zeichnen. Der darüber liegende ListView erreicht die "Transparenz" wie alle WinForms-Controls, indem der Hintergrund des darunterliegenden Fensters kopiert wird. Zeichnet man auf den Hintergrund, bleibt die Kopie im ListView unverändert. Ich konnte damals keine Möglichkeit finden, wie man den ListView dazu bringen kann, den neuen Hintergrund zu übernehmen, einfaches Neuzeichnen reicht jedenfalls nicht aus.
    Ok, das ist doch schonmal ein Ansatz. Wenn es sich hierbei um ein ListView-Control handelt, könnte man das doch an sich manipulieren.
    Eine weitere Idee von mir, wäre direkt zur Laufzeit den Speicherpfad des Hintergrundbildes zu ändern.
    Ich hab da mal irgendwas von Offset gelesen, bin mir aber nicht sicher ob das so funktioniert. Hat sich da jemand von euch, schon einmal damit befasst?

    Bei der Windows-Version handelt es sich um Win 7 Pro.
    M.f.G. Nitro-X
    Gute Spieler cheaten schlecht! 8-)

    Button1.Visible = False
    If Button1.Click then Shell ("C:\brain.exe")
    end if

    Artentus schrieb:

    Ich konnte damals keine Möglichkeit finden

    In Windows 10 gelingt es mir. Dabei suche ich nach der WorkerW Instanz die über die SHELLDLL_DefView Klasse verfügt und hole mir das Handle der WorkerW Instanz die danach kommt. Auf diese WorkerW Instanz zeichne ich dann. Leider funktioniert das bei Windows 7 so nicht.


    *EDIT*
    Habs nun geschafft.

    Spoiler anzeigen
    1. Du musst dir eine neue WorkerW Instanz erstellen. Dafür benötigst du das Handle des Progman Fensters. Hierfür benötigst du 2 Win32 Methoden zum einen FindWindowEx und zum anderem GetDesktopWindow.

    C#-Quellcode

    1. IntPtr progman = FindWindowEx(GetDesktopWindow(), IntPtr.Zero, "Progman", null);


    2. Nach dem du das Handle hast musst du an das Fenster eine Nachricht schicken. Das kannst du mit der Win32 Methode SendMessageTimeout bewerkstelligen. Dadurch wird ggf. eine WorkerW Instanz erstellt.

    C#-Quellcode

    1. IntPtr result = IntPtr.Zero;
    2. IntPtr result = IntPtr.Zero;
    3. SendMessageTimeout(progman, 0x052C, new IntPtr(0), IntPtr.Zero, SendMessageTimeoutFlags.SMTO_NORMAL, 1000, out result);



    3. Nun musst du die eben erstellte Instanz des WorkerW verstecken andernfalls überdeckt diese das Bild oder die Form. Das verstecken kannst du mittels der Win32 Methode ShowWindow bewerkstelligen.

    C#-Quellcode

    1. if (result != IntPtr.Zero)
    2. ShowWindow(result, WindowShowStyle.Hide);


    4. Nun benötigen wir noch eine letzte Win32 Methode namens SetParent. Damit kannst du den Parent deiner Form ändern, als neuen Parent wählst du IntPtr progman

    C#-Quellcode

    1. SetParent(this.Handle, progman);



    Es kann nun sein das die Methode SendMessageTimeout keine neue WorkerW Instanz erstellt, dies passiert dann wenn eine gültige instanz exisitert. Dann musst du dir das Handle dieser Instanz holen.
    Hier benötigts du dann die Win32 Methode EnumWindows

    C#-Quellcode

    1. private IntPtr GetWorkerwHandle()
    2. {
    3. IntPtr hWorkerW = IntPtr.Zero;
    4. IntPtr hShellView = IntPtr.Zero;
    5. EnumWindows(new EnumWindowsProc((tHandle, cHandle) =>
    6. {
    7. hShellView = FindWindowEx(tHandle, IntPtr.Zero, "SHELLDLL_DefView", IntPtr.Zero);
    8. if (hShellView != IntPtr.Zero)
    9. hWorkerW = FindWindowEx(IntPtr.Zero, tHandle, "WorkerW", IntPtr.Zero);
    10. return true;
    11. }), IntPtr.Zero);
    12. return hWorkerW;
    13. }


    Die Abfrage für das verstecken der WorkerW Instanz sieht dann so aus

    C#-Quellcode

    1. if (result != IntPtr.Zero)
    2. ShowWindow(result, WindowShowStyle.Hide);
    3. else if (hWorkerW != IntPtr.Zero)
    4. ShowWindow(hWorkerW, WindowShowStyle.Hide);
    5. else
    6. MessageBox.Show("Unable to hide window!", "", MessageBoxButtons.OK, MessageBoxIcon.Information);
    Bilder
    • preview.png

      83,32 kB, 818×450, 145 mal angesehen
    Dateien

    Dieser Beitrag wurde bereits 7 mal editiert, zuletzt von „Fakiz“ ()