views:

1219

answers:

2

I'd like to do some custom drawing to my windows desktop such that it appears to replace the desktop background (wallpaper). My first try was to get a DC for the desktop's listview and draw to it:

IntPtr desktopDC = GetWindowDC(desktopListView);
Graphics g = Graphics.FromHwnd(desktopDC); <-- fails on out of memory error

I then tried to create a NativeWindow and capture the WM_PAINT message by assigning the native window's handle to the desktop and do my own drawing, but I was unable to see any messages to the desktop.

Ideally I'd like to do this in WPF and not windows forms at all. Any clue how to create a WPF window that I can draw to that sits beneath the desktop icons but on top of the wallpaper such that it ignores any mouse messages and the desktop continues to work normally?

+1  A: 

If you get the window handle of the desktop, you can create a new window and add your own custom window as a child of that. Putting it behind the list view may give you the result you need, though I'm not 100% sure how well the transparency will work.

Found some code - Most of what you need is in the first part if you don't need to deal with multiple screens that change shape.

    public void SetDesktopWindows()
    {
        Thread.Sleep(0);
        while (this.Count < Screen.AllScreens.Length)
        {
            OrangeGuava.Desktop.DesktopWindow.DesktopControl dtc = new OrangeGuava.Desktop.DesktopWindow.DesktopControl();
            User32.SetParent(dtc.Handle, User32.FindWindow("ProgMan", null));
            this.Add(dtc);

        }

        int minx = 0;
        int miny = 0;

        foreach (Screen screen in Screen.AllScreens)
        {      
            if (screen.Bounds.Left < minx) minx = screen.Bounds.Left;
            if (screen.Bounds.Top < miny) miny = screen.Bounds.Top;
        }

        for (int i = Screen.AllScreens.Length; i < Count; i++)
        {
            OrangeGuava.Desktop.DesktopWindow.DesktopControl dtc = (OrangeGuava.Desktop.DesktopWindow.DesktopControl)this[i];
            dtc.Hide();
        }

        for (int i = 0; i < Screen.AllScreens.Length; i++)
        {
            OrangeGuava.Desktop.DesktopWindow.DesktopControl dtc = (OrangeGuava.Desktop.DesktopWindow.DesktopControl)this[i];
            dtc.DeviceId = i.ToString();


            Rectangle r = Screen.AllScreens[i].WorkingArea;
            r.X -= minx;
            r.Y -= miny;



            dtc.SetBounds(r.X, r.Y, r.Width, r.Height);

            dtc.displaySettingsChanged(null, null);


        }

    }
Tom Clarkson
Thanks - can you point me towards appending a child to an existing window? I don't see any obvious API function to do this.
It's all pinvoke stuff - It's been a few years since I did this, but I think you want to look for sethwndparent or setwindow.
Tom Clarkson
Creating a form and adding as a child of the desktop listview seems to almost work. The form is underneath all other windows, but still on top of the icons. Any idea how to truly make it back of the background / wallpaper?
The program I wrote this for was replacing the icons, so that issue didn't come up. You probably want to set the form as the child of the parent of the list view and then set zindex to put it behind the list view.
Tom Clarkson
+1  A: 

I've done this by having my window respond to the WM_WINDOWPOSCHANGING message by setting WINDOWPOS.hWndInsertAfter = HWND_BOTTOM. This says to the OS: make sure my window is underneath all other windows, and makes it appear as though your window is glued to the desktop.

Tim Robinson
That produces a slightly different result - your window will be in front of any child windows of the desktop and I believe the show desktop function will make it disappear.
Tom Clarkson