如何在C#中有效地在桌面上绘制?

如何在C#中有效地在桌面上绘制?,c#,drawing,gdi,buffer,onpaint,C#,Drawing,Gdi,Buffer,Onpaint,我想直接在桌面上用C#绘图。通过搜索,我最终使用了桌面HDC中的图形对象(null)。然后,我通常使用这个图形对象进行绘制 问题是,当屏幕的任何部分被重新绘制时,我的形状都会丢失。我尝试了一个While循环,但它实际上以应用程序最快的速度结束,这不是桌面的更新速度 通常,我需要将绘图代码放在“OnPaint”事件中,但桌面上不存在这种情况 我该怎么做 示例代码:这很难正确执行 制作自己的无边界表单将更容易、更可靠。当您绘制到HDC(NULL)时,您将以非托管方式绘制到屏幕。正如您所发现的,只要w

我想直接在桌面上用C#绘图。通过搜索,我最终使用了桌面HDC中的图形对象(null)。然后,我通常使用这个图形对象进行绘制

问题是,当屏幕的任何部分被重新绘制时,我的形状都会丢失。我尝试了一个While循环,但它实际上以应用程序最快的速度结束,这不是桌面的更新速度

通常,我需要将绘图代码放在“OnPaint”事件中,但桌面上不存在这种情况

我该怎么做


示例代码:

这很难正确执行

制作自己的无边界表单将更容易、更可靠。

当您绘制到HDC(NULL)时,您将以非托管方式绘制到屏幕。正如您所发现的,只要windows刷新屏幕的该部分,您所做的更改就会被覆盖

根据您想要实现的目标,有两种选择:

  • 创建一个无边界的,可能的 非矩形窗口。(使用 设置WindowRGN以创建一个窗口 非矩形。)您可以将其作为桌面窗口的子窗口
  • 为桌面窗口创建子类。这不是直截了当的,而且涉及到 将DLL注入到 Explorer.exe进程

  • 要获得桌面的
    OnPaint
    ,您需要对桌面窗口进行子类化,并在它收到
    WM_PAINT/WM_ERASEBKGND
    消息时使用绘图逻辑

    正如您链接到的线程所说,您只能使用钩子(
    SetWindowsHookEx
    从DLL)截获发送到外部进程窗口的消息


    如前所述,透明窗口是另一种方式,或者(取决于更新频率)复制、绘制和设置临时墙纸(如前所述)。

    我发布了两种解决方案来满足类似的要求

    基本上你有两个选择

    1-获取桌面的图形对象并开始绘制。问题是你是否需要开始清理你以前画的东西等等

    Point pt = Cursor.Position; // Get the mouse cursor in screen coordinates 
    
    using (Graphics g = Graphics.FromHwnd(IntPtr.Zero)) 
    {         
      g.DrawEllipse(Pens.Black, pt.X - 10, pt.Y - 10, 20, 20); 
    }
    
    2-我在上面的链接中提供的第二个选项是创建一个透明的顶部窗口,并在该窗口中绘制所有图形。这基本上为桌面提供了一个透明的覆盖层,您可以在上面绘制。正如我在最初的回答中提到的那样,这种情况的一个可能的缺点是,在应用程序启动后创建的其他窗口也是最上面的窗口,这会模糊你最上面的窗口。如果这是一个问题,这是可以解决的

    对于选项2,使窗体透明就像使用透明键一样简单,这允许鼠标单击等进入底层桌面

    BackColor = Color.LightGreen; 
    TransparencyKey = Color.LightGreen; 
    

    什么版本的Windows?可能这不适用于全屏应用程序(游戏等)?应该将GetDesktopWindow()传递给Graphics.FromHwnd(),因为IntPtr.Zero是一个可能会更改的实现细节,并且肯定不适用于多桌面或多会话工作站。您如何使该窗口成为桌面窗口的子窗口?有可用的代码示例吗?