DirectX Desktop
Asked Answered
B

3

19

I'd like to make an animated desktop background for Windows 7 using DirectX. I'm using C#, SlimDX and a couple of P/Invoke imports of Windows API functions. I'm not brilliant with native Windows programming, but I've had a poke around online and I believe what I need to do is either:

1) Find the handle of the window containing the dekstop wallpaper, hook it up to a DirectX device and draw into it.

2) Make a new output window, and insert it above the desktop wallpaper but below the desktop icons.

I've tried both these, but neither seems to work. If I navigate the Window heirarchy starting from the handle returned by GetDesktopWindow(), I can go Desktop -> WorkerW -> SHELLDLL_DefView -> SysListView32. If I hook up a DirectX device to this handle, I can draw over the entire desktop, but it also covers the icons. If I create a Windows form, set its parent to SHELLDLL_DefView using SetParent() and then use SetWindowPos to play with its Z-order I can only seem to get it to go either behind the desktop wallpaper or in front of the desktop + icons.

It looks as though the desktop wallpaper is background to the folder view containing the icons, and therefore what I am trying to do cannot work. The only solution then would be to not use the desktop for icons, or to find some alternative, e.g. overwriting the desktop then overlaying a transparent window containing a view of the contents of some folder.

Does anyone have any idea of what I should be doing, or even whether what I want to do is possible? It seems you can draw to the desktop background using the GDI (as I believe the wxSnow program does), and I've seen something similar to what I want done by VLC Media Player under Windows XP with its DirectX wallpaper mode (interestingly, I can't seem to get this option enabled on my system).

Thanks!

Bracteole answered 12/4, 2010 at 0:44 Comment(4)
Wow, I didn't even realize DreamScene had been removed from 7. I kinda liked that feature of Vista! Here's a blog post on how to get it back mydigitallife.info/2009/01/14/… (this, of course, allows you to animate your desktop without needing to write a program to do it, for those who read this question hoping to simply animate their desktop and not need to write a program to do it).Tactful
You would be better off doing your development in C++, as I believe DirectX 9 was the last version with a managed DirectX API.Sergent
SlimDX (slimdx.org) is a wrapper for DirectX which, unlike MDX, is updated regularly to support the latest versions of DirectX. You're right, I probably should be developing in C++, but I like C# too much for that.Bracteole
@Tactful I think a big part of the decision to remove dreamscene is that it was buggy. I used it for a while, but it was always breaking and behaving oddly, so much that I had to give it up.Foochow
C
5

Looks like this might not be possible. See this link:

http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/69839cec-3424-4300-9ac3-486b8c2fe492

If you need to draw some controls between the desktop background and desktop icons, an alternative step is below:

  1. Create your user control in a windows control library.
  2. Embed the user control in an ActiveX control.
  3. Embed the ActiveX control in a web page.
  4. Enable active desktop and set the web page to be your desktop background.

This can only be done in XP since Vista doesn’t support active desktop.

Another post there suggests that you could possibly do this with the background of an explorer window - if you could get the handle of the window that constitutes it. Of course, if that's possible then it may be possible also to get the handle of the desktop window behind the icons.

Update: Well, so far the only thing I've found that could possibly "work" is just creating Bitmap files and changing the wallpaper over and over again (I suspect this would be slow, as you mentioned).

That full screen image must be resident in memory somewhere, but there may be no way to access it without some serious low-level memory hacking. I'm going to keep looking.

Update 2: This might work, but I'm not sure:

http://social.msdn.microsoft.com/forums/en-US/vcgeneral/thread/4af734fb-d2c1-414b-a9f1-759b76692802

The meat of it is this:

HWND p = FindWindow("ProgMan", NULL);
HWND s = FindWindowEx(p, NULL, "SHELLDLL_DefView", NULL);
HWND dtw = FindWindowEx(s, NULL, "SysListView32", NULL);
HDC hdc = GetDC(dtw);

You're basically starting with the ProgMan window and drilling down from there to the desktop wallpaper ("SysListView32", I guess). I'm going to try this out.

Update 3: No go - the above code does get the desktop's DC, but it's above the icons so BitBlt draws over them. It's not drawing to the Screen, though, because I can draw underneath an open form without covering it, so that's progress at least.

I'm guessing that there's some window available other than "SysListView32" that is the desktop behind the icons, or there's more than one "SysListView32" window.

Update 4: I'm pretty sure something using this would work:

http://msdn.microsoft.com/en-us/library/bb761155(v=VS.85).aspx http://msdn.microsoft.com/en-us/library/bb774742(v=VS.85).aspx

Basically, it's an API method that you call, passing in a structure which include a bitmap handle. If the call is successful, that bitmap becomes the desktop.

Does DirectX expose frames as bitmap handles (GDI-compatible), or does it only expose the DC? In my case, my animation is already an array of GDI-compatible bitmaps, so I would have no trouble using this approach. If this is the only route, and DirectX doesn't expose the bitmap handles (and I don't think they would), then for each frame you would have to create a new GDI bitmap, which would slow things down quite a bit.

Actually, there might be an easier way, although I'm not sure it would work. Once you get the handle to the actual bitmap of the wallpaper, you can select it into a device context using SelectObject, and then just use that device context as the BitBlt destination. You might have to send a repaint instruction to the desktop, though, which might trigger the icons to be repainted every time.

How about you do some work here? :)

Cantillate answered 12/4, 2010 at 1:45 Comment(13)
Thanks for the link. As I mentioned in my reply to the previous post, using the GDI for animation seems to take too much CPU power. wxSnow uses a similar method to the suggestion on the forum to paint bitmaps of snowflakes over the desktop, and, as well as eating 20% CPU for itself, it drives the Desktop Window Manager and Windows Explorer mad and causes them to take up the best part of the other 80%.Bracteole
GDI (BitBlt etc.) does not have any intrinsic performance problems. I use it for fast, fullscreen animation (>30 fps), which takes much less of the CPU than the corresponding DirectX/DirectShow approach. In fact, the primary limitation of animation with GDI is that there is no way at all of dealing with "tearing" effects, because GDI has no awareness at all of the position of your monitor's scan line. DirectX has a semi-reliable method for doing this, although it's still a pain to use it to prevent tearing.Cantillate
Yes, I use GDI for animations (> 30 fps) too. But only for simple 2D animations. If you are working with 3D, you need to use the GPU. But notice that using GDI rather than DirectX would not solve the problem. When you write to the DC obtained from GetDC(GetDesktopWindow), you'll overwrite the icons on the desktop.Hasten
@Andreas: as far as I can see, neither GDI nor DirectX can solve this particular problem. Morever, as far as I can tell, the asker just wants to render a 2D animation (just because DirectX can do 3D doesn't mean that's what he's doing here). Moremoreover, GDI can handle 3D, just not in the sense that you mean (GDI can be used for animation of any arbitrary level of complexity - including 3D - so long as the cels are pre-generated).Cantillate
@MusiGenesis: Yes, I know. But rendering real-time 3D without hardware acceleration is slow.Hasten
@Andreas: here's my final I-am-right-you-are-wrong: Jonathan didn't say anything about 3D. :)Cantillate
As an unrelated point, I just noticed how funny the phrase "hardware acceleration" is, given that all computer graphics are "hardware accelerated" with or without a dedicated graphics chip on board.Cantillate
Sorry, should have been clearer on what I wanted. I want to use DirectX for the animation because I'd be looking to draw more complex geometry / transformations than would be easily achievable using the GDI. Plus as I mentioned the main reason I wanted to use DirectX is to offload as much of the work to the GPU as possible.Bracteole
I was thinking of trying to render to a surface, grab it into the system memory and transfer it to the background via GDI - DirectX 9 has a method to obtain a DC for a surface, so presumably it would be possible to somehow do a BitBlt from this, avoiding saving/loading bitmaps? However, as Andreas said this would overwrite the icons too, so I may as well just use DirectX directly. Just taken another look at wxSnow in action, and the flakes are on top of the icons. I guess the 'animated desktop' programs you can download must do something more complicated than hijack the desktop wallpaper...Bracteole
@Jonathan: yes, I think you could just run a DirectX object on an invisible surface, and whenever it updates a frame (there's presumably an event for this) you could use the surface's DC to BitBlt to the desktop. The BitBlt itself should take less than 1 millisecond, so it's essentially free in terms of CPU usage. Just need to grab the right destination DC.Cantillate
@MusiGenesis: sounds like the best idea I've seen so far. DirectX has functions to render to a texture, drag the texture into system memory, then get its DC. I'll need to read up on DCs and BitBlt, but presumably I could hold a suitable bitmap in memory and each time I've rendered a frame (I'd know this from my code) BitBlt the texture into the bitmap, use the API function you found and then, if neccessary, send a paint message using SendMessage()? Be interesting to figure out how to do this from C#, but I'll certainly have a go! Thanks very much - I doubt Id've found this on my own!Bracteole
No problem, it's fun getting sucked into things like this once in awhile. I just asked another question related to this, because I think this is almost certainly the way to do it, by getting a handle to the background bitmap.Cantillate
By the way, I have to say that I don't think there's much practical application for this, but you never know. :)Cantillate
H
1

I guess you could get quite a few frames per second by dynamically generating bitmaps and constantly setting these as the desktop background. However, this sounds unnecessarily (almost stupidly) heavy for the CPU. Update: Now that I think about it (it was late when I wrote this), the main problem with such an approach is that you need to write and read bitmaps from the hard drive every time a new frame is to be displayed. This is not feasible.

Are you really using the desktop for icons? In Windows 7 the start menu search function and the new taskbar has made me not use the desktop for icons.

Just an idea

It might be possible to alter the desktop window, by means of SendMessage(GetDesktopWindow, WM_SOME_MESSAGE, wParam, lParam), so that you can achieve what you want. I might investigate this further tomorrow (currently 3 am, local time).

Hasten answered 12/4, 2010 at 0:55 Comment(1)
Thanks. As you say, I think using the GDI or setting the wallpaper with API functions would probably kill the CPU, which unfortunately is the main reason I want to use DirectX rather than DreamScene. I think I have seen some references to using SendMessage() to do what I want, but at the moment this part of the Windows API is a bit beyond me. If it looks promising though, I'll go read up on it. Otherwise, I will take your advice and stop using my desktop as a store for random junk.Bracteole
U
1

I've done some animation of alpha blended windows that are always on the top of the Z-Order. One idea would be to ignore trying to modify the desktop bitmap and just draw your stuff as a layered window but manage the ZOrder somehow so it is always the bottom-most, non-desktop window (perhaps by strategically calling Form.SendToBack() or something at the right times).

Depending on what you are trying to do this may give you the same effect of animating the desktop.

Ung answered 13/4, 2010 at 20:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.