在桌面背景上作画,替换壁纸(Windows/C#)

13

我正在尝试制作一个应用程序,需要在桌面上绘图,在图标后面绘制,以便看起来替换了桌面壁纸。我已经找到了一些解决方案,但大多数都效果不佳(闪烁很多)。其中一个解决方案似乎是我想要的,但我真的不明白。我通常使用较高级别的图形库或仅使用Windows Forms来编写C#应用程序,还有一些C++,但仅限于非Windows平台。

如果有人能为我“翻译”一下或提供另一种解决方案,那将不胜感激!

5个回答

8
我没有找到我想要的解决方案,但以下是最好的(也许是唯一的?)替代方案:
  • 绘制到“SysListView32”窗口(ProgMan -> SHELLDLL_DefView -> SysListView32)。这将在桌面图标后面绘制,但在使用动画时会闪烁。如何操作:链接(您需要在.NET中使用Interop)。

  • 使用DirectDraw覆盖。将桌面颜色设置为某种不常见的颜色,所有具有该颜色的内容都将被替换为覆盖层上的内容。这在我的问题示例和VLC壁纸模式中使用。然而,这与Aero不兼容。如何操作:链接(我猜您可以在.NET中使用Managed DirectX?)。


很遗憾,据我所知目前似乎不行。我已经放弃了尝试的事情,似乎这真的不太可能实现。 - nardi
3
虽然有点晚了,但是我使用了这个链接成功完成了它。 - Clark
@Clark,我认为你可以将它发布为答案。这是这个问题的答案,会让那些来到这个页面的人更容易找到它。此外,楼主应该将其设置为正确答案。 - Barnack

2

你可以在VLC媒体播放器代码中找到灵感。有一个壁纸模式可以实现你想要的功能。


2

我知道这是一个相当晚的答案,但最近我自己也研究了一下,如果其他用户有同样的问题,这可能会对他们有所帮助。

注意:这个答案是针对C++的,但也许它可以帮助你在C#中做同样的事情。

正如上面的评论中提到的,我遵循了这个指南理解我将如何能够在Windows壁纸窗口上绘制图形

通过使用以下两种方法:

BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) {
    HWND p = FindWindowEx(hwnd, NULL, "SHELLDLL_DefView", NULL);
    HWND* ret = (HWND*)lParam;

    if (p)
        {
        // Gets the WorkerW Window after the current one.
        *ret = FindWindowEx(NULL, hwnd, "WorkerW", NULL);
        }
    return true;
}

HWND get_wallpaper_window() {
        // Fetch the Progman window
        HWND progman = FindWindow("ProgMan", NULL);
        // Send 0x052C to Progman. This message directs Progman to spawn a 
        // WorkerW behind the desktop icons. If it is already there, nothing 
        // happens.
        SendMessageTimeout(progman, 0x052C, 0, 0, SMTO_NORMAL, 1000, nullptr);
        // We enumerate all Windows, until we find one, that has the SHELLDLL_DefView 
        // as a child. 
        // If we found that window, we take its next sibling and assign it to workerw.
        HWND wallpaper_hwnd = nullptr;
        EnumWindows(EnumWindowsProc, (LPARAM)&wallpaper_hwnd);
        // Return the handle you're looking for.
        return wallpaper_hwnd;
}

我能够检索到Windows句柄。

由于我只熟悉SDL,这是我找到的唯一解决方案,但我相信任何允许你基于另一个窗口创建/修改窗口的方法都可以起作用。

window = SDL_CreateWindowFrom((void*)get_wallpaper_window());

上述代码允许我使用get_wallpaper_window()方法检索到的HWND创建一个SDL窗口。

由于涉及大量代码,我将链接我的github解决方案。这可以在您的桌面图标后面绘制很多星星(尽管我认为它可以改进)。


1
我只是偶然看到了这个问题,虽然我部分解决了这个问题(但我无法提供任何有用的代码),可以制作一些很酷的游戏,尽管可能没有你想要的应用程序:
  • 将桌面背景设置回正常,并拍摄桌面截图
  • 将桌面背景设置为黑色,并拍摄桌面截图
  • 将桌面背景设置为白色,并拍摄桌面截图
  • 将黑色和白色版本合并以制作掩模,并将第一个截图作为覆盖层设置像素值不同的透明度。

现在,在您的表单上按顺序绘制以下内容:

  1. 绘制第一个截图
  2. 绘制您的表单内容
  3. 绘制您创建的桌面叠加层

这就是我为全屏表单所做的事情,但是很容易适应非全屏表单。本质上,您已经重新创建了桌面,但具有执行任何操作的能力,包括一些很酷的游戏。绘制速度和性能对于任何应用程序都是令人满意的,但桌面交互性是一个问题... :( 这是使用该原理的坦克游戏的图片,除了我将背景设置为白色并使所有白色背景也透明!

我的坦克游戏


0

是的,使用Interop,参见this线程。


那会绘制在所有东西的上面;我想要绘制在所有东西(除了桌面壁纸)的后面。 - nardi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接