You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#无窗体在第二屏幕绘制文本时背景异常问题问询

解决无窗体C#在第二屏幕绘制文本时背景异常的问题

问题原因

直接通过CreateDC(@"\\.\DISPLAY2")获取的设备上下文(DC)未正确关联第二屏幕的显示缓冲区,导致绘制时错误调用主屏幕的背景数据。

解决方法

需先获取第二屏幕的设备信息,正确初始化DC,并通过内存位图先捕获第二屏幕当前背景,再完成文本绘制后输出到屏幕,避免背景异常。以下是修正后的完整代码:

1. 导入Win32 API及定义结构体

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

public class ScreenDrawingHelper
{
    [DllImport("gdi32.dll")]
    private static extern IntPtr CreateDC(string lpszDriver, string lpszDevice, string lpszOutput, IntPtr lpInitData);

    [DllImport("user32.dll")]
    private static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip, MonitorEnumProc lpfnEnum, IntPtr dwData);

    [DllImport("gdi32.dll")]
    private static extern bool DeleteDC(IntPtr hdc);

    private delegate bool MonitorEnumProc(IntPtr hMonitor, IntPtr hdcMonitor, ref RECT lprcMonitor, IntPtr dwData);

    [StructLayout(LayoutKind.Sequential)]
    private struct RECT
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
    }

    private static RECT _secondScreenRect;
    private static IntPtr _secondScreenHdc;

2. 枚举显示器获取第二屏幕的DC与区域

public static void InitializeSecondScreen()
    {
        int monitorIndex = 0;
        EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, (hMonitor, hdcMonitor, ref lprcMonitor, dwData) =>
        {
            monitorIndex++;
            if (monitorIndex == 2)
            {
                _secondScreenRect = lprcMonitor;
                _secondScreenHdc = CreateDC(@"\\.\DISPLAY2", "", "", IntPtr.Zero);
                return false;
            }
            return true;
        }, IntPtr.Zero);
    }

3. 正确绘制文本到第二屏幕

public static void DrawTextOnSecondScreen(string text, Font font, Color textColor)
    {
        if (_secondScreenHdc == IntPtr.Zero)
            return;

        using (var bitmap = new Bitmap(_secondScreenRect.Right - _secondScreenRect.Left, _secondScreenRect.Bottom - _secondScreenRect.Top))
        {
            using (var g = Graphics.FromImage(bitmap))
            {
                // 捕获第二屏幕当前背景
                g.CopyFromScreen(_secondScreenRect.Left, _secondScreenRect.Top, 0, 0, bitmap.Size);
                
                // 在内存位图上绘制文本
                using (var brush = new SolidBrush(textColor))
                {
                    g.DrawString(text, font, brush, new PointF(100, 100));
                }
            }

            // 将绘制好的位图输出到第二屏幕
            using (var screenGraphics = Graphics.FromHdc(_secondScreenHdc))
            {
                screenGraphics.DrawImage(bitmap, _secondScreenRect.Left, _secondScreenRect.Top);
            }
        }
    }

    public static void Cleanup()
    {
        if (_secondScreenHdc != IntPtr.Zero)
            DeleteDC(_secondScreenHdc);
    }
}

使用示例

class Program
{
    static void Main(string[] args)
    {
        ScreenDrawingHelper.InitializeSecondScreen();
        ScreenDrawingHelper.DrawTextOnSecondScreen("第二屏幕测试文本", new Font("Arial", 24), Color.Red);
        
        Console.WriteLine("绘制完成,按任意键退出...");
        Console.ReadKey();
        
        ScreenDrawingHelper.Cleanup();
    }
}

关键说明

  • 避免直接用CreateDC返回的DC绘制,先通过CopyFromScreen获取第二屏幕真实背景,在内存位图完成绘制后再输出,彻底解决背景异常问题。
  • 若显示器排序不同,需调整monitorIndex == 2的判断逻辑,确保定位到目标屏幕。
  • 程序结束时必须调用Cleanup释放DC资源,防止内存泄漏。

内容的提问来源于stack exchange,提问作者Mahmoud Mostafa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 09:27:29