如何在Windows桌面上直接绘图,使用C#?

16

这个问题已经被提出并询问过其他语言,在那些语言中,我发现它们的答案在如何干净地实现(没有糟糕的屏幕重绘等)方面缺乏精确的解释。

能否从C#向Windows桌面绘图?如果可能的话,请给出一个示例。


7
目前没有官方支持的干净方式能够从任何语言绘制桌面窗口。实际上,大多数最接近于干净绘制桌面的方法都涉及向资源管理器进程中注入自己的dll,并为桌面窗口子类化窗口过程。我不建议在C#中这样做。而且,这种方法没有保证将来的Windows版本或现有版本的服务包或热修复是否仍然有效。 - Franci Penov
3个回答

29

请尝试以下方法:

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Runtime.InteropServices;

class Program {

    [DllImport("User32.dll")]
    static extern IntPtr GetDC(IntPtr hwnd);

    [DllImport("User32.dll")]
    static extern int ReleaseDC(IntPtr hwnd, IntPtr dc);

    static void Main(string[] args) {
        IntPtr desktop = GetDC(IntPtr.Zero);
        using (Graphics g = Graphics.FromHdc(desktop)) {
            g.FillRectangle(Brushes.Red, 0, 0, 100, 100);
        }
        ReleaseDC(IntPtr.Zero, desktop);
    }
}

6
对于那些认为不可能的人,FYI,这对我有效,尽管移动任何窗口都会立即重绘它 :( - esac
1
看起来将我的项目更改为.NET 3.5解决了这个不平衡的问题。 - gonzobrains
6
堆栈失衡是由于ReleaseDC方法被错误地定义所致。正确的定义应该是:static extern int ReleaseDC(IntPtr hwnd, IntPtr dc); - Frank Hagenson
void ReleaseDC(IntPtr dc) 在 x86 进程中会导致不平衡的堆栈错误。x64 使用寄存器传递参数,因此如果你很幸运,它可以工作。Msdn - Atomosk
我不能确定,因为这是一个相当旧的答案,但通常我不会自己编写我的 DllImport 语句,所以我真的不知道为什么我选择了错误的 ReleaseDC 签名... - Paolo Tedesco
显示剩余4条评论

9
您可以尝试以下方法:
Graphics.FromHwnd(IntPtr.Zero)

3
Paolo Tedesco的答案曾经适用于我,但现在不行了,我无法弄清原因。Leppie的答案让它再次可用。 - chrismead

4
您可以在https://uiautomationverify.codeplex.com/SourceControl/latest#UIAVerify/Tools/visualuiverify/utils/screenrectangle.cs中查看一个真实的代码示例。该示例绘制了一个矩形,直到用户选择在任意位置将其移除(不会被重绘)。它使用一个隐藏/作为弹出窗口出现的Windows表单。这是当前Windows SDK中UIAVerify.exe工具的代码背后。
如果您想使用上面的代码,请将以下文件复制到您的项目中:
  • utils\screenboundingrectangle.cs
  • utils\screenrectangle.cs
  • win32\*
可能需要相应地更新命名空间并添加对System.DrawingSystem.Windows.Forms的引用。
然后,您可以使用以下代码绘制一个矩形:
namespace Something
{
    public class Highlighter
    {
        ScreenBoundingRectangle _rectangle = new ScreenBoundingRectangle();
        public void DrawRectangle(Rectangle rect)
        {
            _rectangle.Color = System.Drawing.Color.Red;
            _rectangle.Opacity = 0.8;
            _rectangle.Location = rect;
            this._rectangle.Visible = true;
        }
    }
}

并且

var rect = Rectangle.FromLTRB(100, 100, 100, 100);
var hi = new Highlighter();
hi.DrawRectangle(rect);

1
代码现在可以在这里找到 https://github.com/TestStack/UIAVerify/blob/master/VisualUiaVerify/utils/screenrectangle.cs - frank koch

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