0

I'm trying to create an interactive desktop wallpaper for Windows 7/8 in Mono/.Net . I'm only updating the Wallpaper when it changes, and I'm using SystemParametersInfo() in user32.dll to do so. My code looks like this :

const int SPI_SETDESKWALLPAPER = 20;
const int SPIF_UPDATEINIFILE = 0x01;
const int SPIF_SENDWININICHANGE = 0x02;

[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern int SystemParametersInfo(int uAction, int uParam, string lpvParam, int fuWinIni);

public static void Set2(string path)
{
    SystemParametersInfo(SPI_SETDESKWALLPAPER,0,path,SPIF_UPDATEINIFILE | 
    SPIF_SENDWININICHANGE);
}

Even though I'm only updating it whenever necessary, my wallpaper still feels very unresponsive. Using Stopwatch I found out that SystemParametersInfo takes about 1 second to reload the wallpaper. Using a second thread would not make it any more responsive, as it would still require the same amount of time to refresh the wallpaper. This seems to be mostly independent from the Bitmap size. Just updating the image at the path location does not change the wallpaper unless SystemParameterInfo is called.

From what I understand user32.dll uses unmanaged code, and SystemParameterInfo loads the image into memory. However, there must be some sort of pointer to it, otherwise Windows wouldn't find it again when it renders the desktop.

Long story short, I would like to know whether it is possible to access this pointer. My image size doesn't change so I could just overwrite the image directly without worrying too much about memory allocation. This way I could avoid the expensive SystemParametersInfo method.

Please tell me if I misunderstood something, as I'm kind of lost when it comes to Windows. If you know a solution that requires unsafe code or c++ code, that would be fine too. Any comment or discussion would be appreciated.

Thank you.

EDIT: I now know what is causing the slowdown.

SystemParametersInfo(SPI_SETDESKWALLPAPER,0,path,SPIF_UPDATEINIFILE | 
    SPIF_SENDWININICHANGE);

The last argument states whether the windows ini file will be updated. In all the threads here I found regarding Wallpaper changes, this was set to 3, which apparently is the Windows main ini file. In cases like these, where the background is reloaded many times each second, this should be set to 0, as the actual image path doesn't change. After doing so, I can easily reach 100 fps.

Since this is almost certainly the only thread on StackOverflow that mentions this, and since I'm sure other people would be interested in knowing this as well (this is not really explained in the Microsoft Windows Library docs), I added this "discovery" to the title, so people can search and find it.

Now, this is not the solution though. I'm still interested in the actual memory pointer of the working copy of the wallpaper. By using it, one would not need to pass the entire image, but instead one could selectively change only the bytes of the image that really changed between frames, as is done in most GUI systems.

Sven
  • 13
  • 3
  • Are you sure that the problem is in bitmap loading? It might be just the way setting wallpaper on windows works, implementation doesn't guarantees to set it instantaneously. – vim Aug 29 '14 at 10:45
  • From the Stopwatch results I'm fairly certain that a 1 second sleep is included in SystemParametersInfo. Otherwise my results, which range from 1.05 to 1.09 seconds would be too regular for actual code I think. Normally script execution speed differs a lot more on my system. But this is just a best guess. This is why I would like set the wallpaper without using this method. – Sven Aug 29 '14 at 10:56
  • @vim Let me correct myself, after a lot more tests I have gotten some results which take less than 1 second, so the sleep hypothesis seems disproven. – Sven Aug 29 '14 at 11:21

0 Answers0