[{"data":1,"prerenderedAt":2846},["ShallowReactive",2],{"page-\u002Fcsharp\u002Fwpf\u002F平台调用gdi32实现屏幕捕获等任务":3},{"id":4,"title":5,"body":6,"description":19,"extension":2840,"meta":2841,"navigation":666,"path":2842,"seo":2843,"stem":2844,"__hash__":2845},"content\u002Fcsharp\u002FWPF\u002F平台调用gdi32实现屏幕捕获等任务.md","平台调用gdi32实现屏幕捕获等任务",{"type":7,"value":8,"toc":2806},"minimark",[9,20,32,37,42,49,53,81,85,90,105,110,124,128,132,139,143,148,194,198,235,239,258,262,265,292,295,321,324,353,356,366,370,398,402,431,439,469,473,497,501,531,535,538,1391,1395,1399,1437,1441,1453,1457,1485,1489,1502,1505,1508,1871,1875,1878,2398,2402,2406,2426,2430,2450,2454,2474,2478,2498,2501,2505,2533,2537,2565,2569,2584,2587,2590,2643,2646,2703,2706,2747,2750,2799,2802],[10,11,16],"pre",{"className":12,"code":14,"language":15},[13],"language-text","捕获屏幕信息很多，windows上你可以用平台调用的方式去Dllimport gdi32.dll 来实现功能。你也可以使用DXGI 交互，以及WGC的方式。\n","text",[17,18,14],"code",{"__ignoreMap":19},"",[21,22,23,24,27,28,31],"p",{},"​\tWindows Graphics Capture (WGC) 是一个非常明智的决定。它是在现代 Windows 平台上进行高性能屏幕采集的最佳方式。而直接调用 ",[17,25,26],{},"gdi32.dll"," 中的 Win32 API 来进行屏幕采集，是了解底层工作原理的最佳方式。这正是 ",[17,29,30],{},"System.Drawing.Graphics.CopyFromScreen"," 在幕后所做的事情。",[33,34,36],"h2",{"id":35},"平台调用-pinvoke-详解","平台调用 (P\u002FInvoke) 详解",[38,39,41],"h3",{"id":40},"什么是平台调用","什么是平台调用？",[21,43,44,48],{},[45,46,47],"strong",{},"平台调用 (Platform Invocation Services, P\u002FInvoke)"," 是 .NET Framework 和 .NET Core\u002F.NET 5+ 提供的一种机制，允许托管代码（如 C#）调用非托管代码（如 Windows API、C\u002FC++ 库等）。",[38,50,52],{"id":51},"pinvoke-的工作原理","P\u002FInvoke 的工作原理",[54,55,56,63,69,75],"ol",{},[57,58,59,62],"li",{},[45,60,61],{},"托管到非托管的桥接","：P\u002FInvoke 在托管代码和非托管代码之间建立桥梁",[57,64,65,68],{},[45,66,67],{},"数据封送 (Marshaling)","：自动处理数据类型转换和内存管理",[57,70,71,74],{},[45,72,73],{},"调用约定处理","：处理不同的函数调用约定（如 stdcall、cdecl 等）",[57,76,77,80],{},[45,78,79],{},"异常处理","：将非托管异常转换为托管异常",[38,82,84],{"id":83},"pinvoke-的优势和劣势","P\u002FInvoke 的优势和劣势",[21,86,87],{},[45,88,89],{},"优势：",[91,92,93,96,99,102],"ul",{},[57,94,95],{},"直接访问 Windows API 和系统功能",[57,97,98],{},"性能开销相对较小",[57,100,101],{},"可以调用现有的 C\u002FC++ 库",[57,103,104],{},"提供对底层系统功能的完全控制",[21,106,107],{},[45,108,109],{},"劣势：",[91,111,112,115,118,121],{},[57,113,114],{},"需要手动管理非托管资源",[57,116,117],{},"容易出现内存泄漏",[57,119,120],{},"跨平台兼容性差",[57,122,123],{},"调试困难，错误信息不够友好",[33,125,127],{"id":126},"gdi-graphics-device-interface-详解","GDI (Graphics Device Interface) 详解",[38,129,131],{"id":130},"什么是-gdi","什么是 GDI？",[21,133,134,135,138],{},"​\t",[45,136,137],{},"GDI (Graphics Device Interface)"," 是 Windows 操作系统的核心图形子系统，负责处理所有图形输出操作。它是 Windows 图形架构的基础层。",[38,140,142],{"id":141},"gdi-的核心概念","GDI 的核心概念",[144,145,147],"h4",{"id":146},"_1-设备上下文-device-context-dc","1. 设备上下文 (Device Context, DC)",[91,149,150,156,162],{},[57,151,152,155],{},[45,153,154],{},"定义","：DC 是 Windows 中表示绘图表面的抽象概念",[57,157,158,161],{},[45,159,160],{},"作用","：提供绘图操作的接口，包括画笔、画刷、字体等",[57,163,164,167,168],{},[45,165,166],{},"类型","：\n",[91,169,170,176,182,188],{},[57,171,172,175],{},[45,173,174],{},"屏幕 DC","：直接绘制到屏幕",[57,177,178,181],{},[45,179,180],{},"内存 DC","：在内存中创建虚拟绘图表面",[57,183,184,187],{},[45,185,186],{},"打印机 DC","：用于打印输出",[57,189,190,193],{},[45,191,192],{},"位图 DC","：用于位图操作",[144,195,197],{"id":196},"_2-句柄-handle","2. 句柄 (Handle)",[91,199,200,205],{},[57,201,202,204],{},[45,203,154],{},"：Windows 中用于标识系统资源的唯一标识符",[57,206,207,167,209],{},[45,208,166],{},[91,210,211,217,223,229],{},[57,212,213,216],{},[17,214,215],{},"HDC","：设备上下文句柄",[57,218,219,222],{},[17,220,221],{},"HBITMAP","：位图句柄",[57,224,225,228],{},[17,226,227],{},"HPEN","：画笔句柄",[57,230,231,234],{},[17,232,233],{},"HBRUSH","：画刷句柄",[144,236,238],{"id":237},"_3-位图-bitmap","3. 位图 (Bitmap)",[91,240,241,246,252],{},[57,242,243,245],{},[45,244,154],{},"：存储像素数据的图形对象",[57,247,248,251],{},[45,249,250],{},"格式","：支持多种颜色深度（1位、4位、8位、16位、24位、32位）",[57,253,254,257],{},[45,255,256],{},"操作","：创建、选择、复制、删除",[38,259,261],{"id":260},"gdi-函数分类","GDI 函数分类",[144,263,264],{"id":264},"设备上下文管理",[91,266,267,277,286],{},[57,268,269,272,273,276],{},[17,270,271],{},"GetDC()"," \u002F ",[17,274,275],{},"ReleaseDC()","：获取\u002F释放设备上下文",[57,278,279,272,282,285],{},[17,280,281],{},"CreateCompatibleDC()",[17,283,284],{},"DeleteDC()","：创建\u002F删除兼容 DC",[57,287,288,291],{},[17,289,290],{},"SelectObject()","：选择 GDI 对象到 DC",[144,293,294],{"id":294},"位图操作",[91,296,297,303,309,315],{},[57,298,299,302],{},[17,300,301],{},"CreateCompatibleBitmap()","：创建兼容位图",[57,304,305,308],{},[17,306,307],{},"BitBlt()","：位块传输，执行像素复制",[57,310,311,314],{},[17,312,313],{},"GetDIBits()","：获取位图像素数据",[57,316,317,320],{},[17,318,319],{},"DeleteObject()","：删除 GDI 对象",[144,322,323],{"id":323},"绘图操作",[91,325,326,335,344],{},[57,327,328,272,331,334],{},[17,329,330],{},"SetPixel()",[17,332,333],{},"GetPixel()","：设置\u002F获取像素颜色",[57,336,337,272,340,343],{},[17,338,339],{},"LineTo()",[17,341,342],{},"MoveToEx()","：绘制直线",[57,345,346,272,349,352],{},[17,347,348],{},"Rectangle()",[17,350,351],{},"Ellipse()","：绘制几何图形",[33,354,355],{"id":355},"屏幕捕获的核心原理",[21,357,358,359,362,363,365],{},"我们将通过 ",[45,360,361],{},"P\u002FInvoke (Platform Invocation Services)"," 来调用 ",[17,364,26],{}," 中的原生函数。整个流程可以概括为：",[38,367,369],{"id":368},"_1-获取屏幕的设备上下文-dc","1. 获取屏幕的设备上下文 (DC)",[91,371,372,378,388],{},[57,373,374,377],{},[45,375,376],{},"原理","：DC 是 Windows 中表示绘图表面的抽象概念，可以理解为指向一个绘图表面的\"画笔\"或\"句柄\"",[57,379,380,383,384,387],{},[45,381,382],{},"实现","：使用 ",[17,385,386],{},"GetDC(IntPtr.Zero)"," 获取整个屏幕的设备上下文",[57,389,390,393,394,397],{},[45,391,392],{},"注意","：",[17,395,396],{},"IntPtr.Zero"," 表示获取整个屏幕的 DC，而不是特定窗口的 DC",[38,399,401],{"id":400},"_2-创建内存中的-dc-和位图","2. 创建内存中的 DC 和位图",[91,403,404,409,425],{},[57,405,406,408],{},[45,407,376],{},"：在内存中创建一个与屏幕兼容的\"画布\"(Memory DC) 和\"画纸\"(Bitmap)",[57,410,411,167,413],{},[45,412,382],{},[91,414,415,420],{},[57,416,417,419],{},[17,418,281],{}," 创建兼容的内存 DC",[57,421,422,424],{},[17,423,301],{}," 创建与屏幕兼容的位图",[57,426,427,430],{},[45,428,429],{},"优势","：内存操作比直接屏幕操作更快，且不会影响屏幕显示",[38,432,434,435,438],{"id":433},"_3-执行位块传输-bitblt","3. 执行位块传输 (",[17,436,437],{},"BitBlt",")",[91,440,441,446,453],{},[57,442,443,445],{},[45,444,376],{},"：将屏幕 DC 的内容，通过\"位块传输\"的方式，完整地复制到内存 DC 上的位图中",[57,447,448,393,450,452],{},[45,449,382],{},[17,451,307],{}," 函数执行像素级的复制操作",[57,454,455,167,458],{},[45,456,457],{},"参数说明",[91,459,460,463,466],{},[57,461,462],{},"目标 DC、目标坐标、尺寸",[57,464,465],{},"源 DC、源坐标",[57,467,468],{},"光栅操作码 (ROP)",[38,470,472],{"id":471},"_4-提取像素数据","4. 提取像素数据",[91,474,475,484,491],{},[57,476,477,479,480,483],{},[45,478,376],{},"：从内存中的 GDI 位图对象中，提取出原始的像素数据到一个 C# 的字节数组 (",[17,481,482],{},"byte[]",") 中",[57,485,486,383,488,490],{},[45,487,382],{},[17,489,313],{}," 函数获取位图像素数据",[57,492,493,496],{},[45,494,495],{},"数据格式","：通常使用 32 位 BGRA 格式（蓝、绿、红、透明度）",[38,498,500],{"id":499},"_5-释放资源","5. 释放资源",[91,502,503,512],{},[57,504,505,393,508,511],{},[45,506,507],{},"重要性",[45,509,510],{},"（最重要的一步）"," 必须手动释放所有申请的 GDI 资源句柄，否则会造成严重的内存泄漏",[57,513,514,167,517],{},[45,515,516],{},"释放顺序",[54,518,519,522,525,528],{},[57,520,521],{},"恢复原始位图选择",[57,523,524],{},"删除位图对象",[57,526,527],{},"删除内存 DC",[57,529,530],{},"释放屏幕 DC",[33,532,534],{"id":533},"pinvoke-函数声明详解","P\u002FInvoke 函数声明详解",[21,536,537],{},"首先我们需要进行平台调用来导入 dll。以下是详细的函数声明和说明：",[10,539,543],{"className":540,"code":541,"language":542,"meta":19,"style":19},"language-csharp shiki shiki-themes github-light github-dark","public static class ColorClass\n{\n    \u002F\u002F ========== GDI32.dll 函数声明 ==========\n    \n    \u002F\u002F\u002F \u003Csummary>\n    \u002F\u002F\u002F 位块传输函数 - 执行像素复制操作\n    \u002F\u002F\u002F \u003C\u002Fsummary>\n    \u002F\u002F\u002F \u003Cparam name=\"hdcDest\">目标设备上下文句柄\u003C\u002Fparam>\n    \u002F\u002F\u002F \u003Cparam name=\"nXDest\">目标矩形左上角X坐标\u003C\u002Fparam>\n    \u002F\u002F\u002F \u003Cparam name=\"nYDest\">目标矩形左上角Y坐标\u003C\u002Fparam>\n    \u002F\u002F\u002F \u003Cparam name=\"nWidth\">复制区域的宽度\u003C\u002Fparam>\n    \u002F\u002F\u002F \u003Cparam name=\"nHeight\">复制区域的高度\u003C\u002Fparam>\n    \u002F\u002F\u002F \u003Cparam name=\"hdcSrc\">源设备上下文句柄\u003C\u002Fparam>\n    \u002F\u002F\u002F \u003Cparam name=\"nXSrc\">源矩形左上角X坐标\u003C\u002Fparam>\n    \u002F\u002F\u002F \u003Cparam name=\"nYSrc\">源矩形左上角Y坐标\u003C\u002Fparam>\n    \u002F\u002F\u002F \u003Cparam name=\"dwRop\">光栅操作码，定义如何组合源和目标像素\u003C\u002Fparam>\n    \u002F\u002F\u002F \u003Creturns>成功返回true，失败返回false\u003C\u002Freturns>\n    [DllImport(\"gdi32.dll\")]\n    public static extern bool BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, uint dwRop);\n\n    \u002F\u002F\u002F \u003Csummary>\n    \u002F\u002F\u002F 创建与指定设备上下文兼容的位图\n    \u002F\u002F\u002F \u003C\u002Fsummary>\n    \u002F\u002F\u002F \u003Cparam name=\"hdc\">设备上下文句柄\u003C\u002Fparam>\n    \u002F\u002F\u002F \u003Cparam name=\"nWidth\">位图宽度（像素）\u003C\u002Fparam>\n    \u002F\u002F\u002F \u003Cparam name=\"nHeight\">位图高度（像素）\u003C\u002Fparam>\n    \u002F\u002F\u002F \u003Creturns>成功返回位图句柄，失败返回IntPtr.Zero\u003C\u002Freturns>\n    [DllImport(\"gdi32.dll\")]\n    public static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight);\n\n    \u002F\u002F\u002F \u003Csummary>\n    \u002F\u002F\u002F 创建与指定设备上下文兼容的内存设备上下文\n    \u002F\u002F\u002F \u003C\u002Fsummary>\n    \u002F\u002F\u002F \u003Cparam name=\"hdc\">参考设备上下文句柄\u003C\u002Fparam>\n    \u002F\u002F\u002F \u003Creturns>成功返回内存DC句柄，失败返回IntPtr.Zero\u003C\u002Freturns>\n    [DllImport(\"gdi32.dll\")]\n    public static extern IntPtr CreateCompatibleDC(IntPtr hdc);\n\n    \u002F\u002F\u002F \u003Csummary>\n    \u002F\u002F\u002F 删除指定的设备上下文\n    \u002F\u002F\u002F \u003C\u002Fsummary>\n    \u002F\u002F\u002F \u003Cparam name=\"hdc\">要删除的设备上下文句柄\u003C\u002Fparam>\n    \u002F\u002F\u002F \u003Creturns>成功返回true，失败返回false\u003C\u002Freturns>\n    [DllImport(\"gdi32.dll\")]\n    public static extern bool DeleteDC(IntPtr hdc);\n\n    \u002F\u002F\u002F \u003Csummary>\n    \u002F\u002F\u002F 删除GDI对象（位图、画笔、画刷等）\n    \u002F\u002F\u002F \u003C\u002Fsummary>\n    \u002F\u002F\u002F \u003Cparam name=\"hObject\">要删除的GDI对象句柄\u003C\u002Fparam>\n    \u002F\u002F\u002F \u003Creturns>成功返回true，失败返回false\u003C\u002Freturns>\n    [DllImport(\"gdi32.dll\")]\n    public static extern bool DeleteObject(IntPtr hObject);\n\n    \u002F\u002F\u002F \u003Csummary>\n    \u002F\u002F\u002F 将GDI对象选择到指定的设备上下文中\n    \u002F\u002F\u002F \u003C\u002Fsummary>\n    \u002F\u002F\u002F \u003Cparam name=\"hdc\">设备上下文句柄\u003C\u002Fparam>\n    \u002F\u002F\u002F \u003Cparam name=\"hgdiobj\">要选择的GDI对象句柄\u003C\u002Fparam>\n    \u002F\u002F\u002F \u003Creturns>返回之前选择的同类型对象句柄\u003C\u002Freturns>\n    [DllImport(\"gdi32.dll\")]\n    public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);\n\n    \u002F\u002F\u002F \u003Csummary>\n    \u002F\u002F\u002F 获取位图的像素数据\n    \u002F\u002F\u002F \u003C\u002Fsummary>\n    \u002F\u002F\u002F \u003Cparam name=\"hdc\">设备上下文句柄\u003C\u002Fparam>\n    \u002F\u002F\u002F \u003Cparam name=\"hbmp\">位图句柄\u003C\u002Fparam>\n    \u002F\u002F\u002F \u003Cparam name=\"uStartScan\">开始扫描的行号\u003C\u002Fparam>\n    \u002F\u002F\u002F \u003Cparam name=\"cScanLines\">要扫描的行数\u003C\u002Fparam>\n    \u002F\u002F\u002F \u003Cparam name=\"lpvBits\">接收像素数据的缓冲区\u003C\u002Fparam>\n    \u002F\u002F\u002F \u003Cparam name=\"lpbi\">位图信息结构\u003C\u002Fparam>\n    \u002F\u002F\u002F \u003Cparam name=\"uUsage\">颜色表使用方式\u003C\u002Fparam>\n    \u002F\u002F\u002F \u003Creturns>成功返回扫描行数，失败返回0\u003C\u002Freturns>\n    [DllImport(\"gdi32.dll\")]\n    public static extern int GetDIBits(IntPtr hdc, IntPtr hbmp, uint uStartScan, uint cScanLines, [Out] byte[] lpvBits, ref BITMAPINFO lpbi, uint uUsage);\n\n    \u002F\u002F ========== USER32.dll 函数声明 ==========\n    \n    \u002F\u002F\u002F \u003Csummary>\n    \u002F\u002F\u002F 获取指定窗口的设备上下文\n    \u002F\u002F\u002F \u003C\u002Fsummary>\n    \u002F\u002F\u002F \u003Cparam name=\"hWnd\">窗口句柄，IntPtr.Zero表示整个屏幕\u003C\u002Fparam>\n    \u002F\u002F\u002F \u003Creturns>成功返回DC句柄，失败返回IntPtr.Zero\u003C\u002Freturns>\n    [DllImport(\"user32.dll\")]\n    public static extern IntPtr GetDC(IntPtr hWnd);\n\n    \u002F\u002F\u002F \u003Csummary>\n    \u002F\u002F\u002F 释放设备上下文\n    \u002F\u002F\u002F \u003C\u002Fsummary>\n    \u002F\u002F\u002F \u003Cparam name=\"hWnd\">窗口句柄\u003C\u002Fparam>\n    \u002F\u002F\u002F \u003Cparam name=\"hDC\">要释放的设备上下文句柄\u003C\u002Fparam>\n    \u002F\u002F\u002F \u003Creturns>成功返回1，失败返回0\u003C\u002Freturns>\n    [DllImport(\"user32.dll\")]\n    public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);\n\n    #region 常量和结构体定义\n    \n    \u002F\u002F\u002F \u003Csummary>\n    \u002F\u002F\u002F 光栅操作码 - 直接复制源到目标\n    \u002F\u002F\u002F \u003C\u002Fsummary>\n    public const uint SRCCOPY = 0x00CC0020;\n    \n    \u002F\u002F\u002F \u003Csummary>\n    \u002F\u002F\u002F DIB颜色表使用方式 - 使用RGB颜色值\n    \u002F\u002F\u002F \u003C\u002Fsummary>\n    public const uint DIB_RGB_COLORS = 0;\n\n    \u002F\u002F\u002F \u003Csummary>\n    \u002F\u002F\u002F 位图信息结构体\n    \u002F\u002F\u002F \u003C\u002Fsummary>\n    [StructLayout(LayoutKind.Sequential)]\n    public struct BITMAPINFO\n    {\n        public BITMAPINFOHEADER bmiHeader;  \u002F\u002F 位图头信息\n        public RGBQUAD bmiColors;           \u002F\u002F 颜色表（对于调色板位图）\n    }\n\n    \u002F\u002F\u002F \u003Csummary>\n    \u002F\u002F\u002F 位图头信息结构体\n    \u002F\u002F\u002F \u003C\u002Fsummary>\n    [StructLayout(LayoutKind.Sequential)]\n    public struct BITMAPINFOHEADER\n    {\n        public uint biSize;           \u002F\u002F 结构体大小\n        public int biWidth;           \u002F\u002F 位图宽度（像素）\n        public int biHeight;          \u002F\u002F 位图高度（像素，负数表示从上到下）\n        public ushort biPlanes;       \u002F\u002F 颜色平面数（必须为1）\n        public ushort biBitCount;     \u002F\u002F 每像素位数（1,4,8,16,24,32）\n        public uint biCompression;    \u002F\u002F 压缩方式（0=无压缩）\n        public uint biSizeImage;      \u002F\u002F 图像数据大小（字节）\n        public int biXPelsPerMeter;   \u002F\u002F 水平分辨率（像素\u002F米）\n        public int biYPelsPerMeter;   \u002F\u002F 垂直分辨率（像素\u002F米）\n        public uint biClrUsed;        \u002F\u002F 使用的颜色数\n        public uint biClrImportant;   \u002F\u002F 重要颜色数\n    }\n\n    \u002F\u002F\u002F \u003Csummary>\n    \u002F\u002F\u002F RGB颜色四元组结构体\n    \u002F\u002F\u002F \u003C\u002Fsummary>\n    [StructLayout(LayoutKind.Sequential)]\n    public struct RGBQUAD\n    {\n        public byte rgbBlue;      \u002F\u002F 蓝色分量\n        public byte rgbGreen;     \u002F\u002F 绿色分量\n        public byte rgbRed;       \u002F\u002F 红色分量\n        public byte rgbReserved;  \u002F\u002F 保留字段\n    }\n    #endregion\n}\n","csharp",[17,544,545,553,559,565,571,577,583,589,595,601,607,613,619,625,631,637,643,649,655,661,668,673,679,684,690,696,702,708,713,719,724,729,735,740,746,752,757,763,768,773,779,784,790,795,800,806,811,816,822,827,833,838,843,849,854,859,865,870,875,881,887,892,898,903,908,914,919,924,930,936,942,948,954,960,966,971,977,982,988,993,998,1004,1009,1015,1021,1027,1033,1038,1043,1049,1054,1060,1066,1072,1077,1083,1088,1094,1099,1104,1110,1115,1121,1126,1131,1137,1142,1148,1153,1158,1164,1169,1175,1181,1187,1193,1199,1205,1210,1215,1221,1226,1231,1237,1242,1248,1254,1260,1266,1272,1278,1284,1290,1296,1302,1308,1313,1318,1323,1329,1334,1339,1345,1350,1356,1362,1368,1374,1379,1385],{"__ignoreMap":19},[546,547,550],"span",{"class":548,"line":549},"line",1,[546,551,552],{},"public static class ColorClass\n",[546,554,556],{"class":548,"line":555},2,[546,557,558],{},"{\n",[546,560,562],{"class":548,"line":561},3,[546,563,564],{},"    \u002F\u002F ========== GDI32.dll 函数声明 ==========\n",[546,566,568],{"class":548,"line":567},4,[546,569,570],{},"    \n",[546,572,574],{"class":548,"line":573},5,[546,575,576],{},"    \u002F\u002F\u002F \u003Csummary>\n",[546,578,580],{"class":548,"line":579},6,[546,581,582],{},"    \u002F\u002F\u002F 位块传输函数 - 执行像素复制操作\n",[546,584,586],{"class":548,"line":585},7,[546,587,588],{},"    \u002F\u002F\u002F \u003C\u002Fsummary>\n",[546,590,592],{"class":548,"line":591},8,[546,593,594],{},"    \u002F\u002F\u002F \u003Cparam name=\"hdcDest\">目标设备上下文句柄\u003C\u002Fparam>\n",[546,596,598],{"class":548,"line":597},9,[546,599,600],{},"    \u002F\u002F\u002F \u003Cparam name=\"nXDest\">目标矩形左上角X坐标\u003C\u002Fparam>\n",[546,602,604],{"class":548,"line":603},10,[546,605,606],{},"    \u002F\u002F\u002F \u003Cparam name=\"nYDest\">目标矩形左上角Y坐标\u003C\u002Fparam>\n",[546,608,610],{"class":548,"line":609},11,[546,611,612],{},"    \u002F\u002F\u002F \u003Cparam name=\"nWidth\">复制区域的宽度\u003C\u002Fparam>\n",[546,614,616],{"class":548,"line":615},12,[546,617,618],{},"    \u002F\u002F\u002F \u003Cparam name=\"nHeight\">复制区域的高度\u003C\u002Fparam>\n",[546,620,622],{"class":548,"line":621},13,[546,623,624],{},"    \u002F\u002F\u002F \u003Cparam name=\"hdcSrc\">源设备上下文句柄\u003C\u002Fparam>\n",[546,626,628],{"class":548,"line":627},14,[546,629,630],{},"    \u002F\u002F\u002F \u003Cparam name=\"nXSrc\">源矩形左上角X坐标\u003C\u002Fparam>\n",[546,632,634],{"class":548,"line":633},15,[546,635,636],{},"    \u002F\u002F\u002F \u003Cparam name=\"nYSrc\">源矩形左上角Y坐标\u003C\u002Fparam>\n",[546,638,640],{"class":548,"line":639},16,[546,641,642],{},"    \u002F\u002F\u002F \u003Cparam name=\"dwRop\">光栅操作码，定义如何组合源和目标像素\u003C\u002Fparam>\n",[546,644,646],{"class":548,"line":645},17,[546,647,648],{},"    \u002F\u002F\u002F \u003Creturns>成功返回true，失败返回false\u003C\u002Freturns>\n",[546,650,652],{"class":548,"line":651},18,[546,653,654],{},"    [DllImport(\"gdi32.dll\")]\n",[546,656,658],{"class":548,"line":657},19,[546,659,660],{},"    public static extern bool BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, uint dwRop);\n",[546,662,664],{"class":548,"line":663},20,[546,665,667],{"emptyLinePlaceholder":666},true,"\n",[546,669,671],{"class":548,"line":670},21,[546,672,576],{},[546,674,676],{"class":548,"line":675},22,[546,677,678],{},"    \u002F\u002F\u002F 创建与指定设备上下文兼容的位图\n",[546,680,682],{"class":548,"line":681},23,[546,683,588],{},[546,685,687],{"class":548,"line":686},24,[546,688,689],{},"    \u002F\u002F\u002F \u003Cparam name=\"hdc\">设备上下文句柄\u003C\u002Fparam>\n",[546,691,693],{"class":548,"line":692},25,[546,694,695],{},"    \u002F\u002F\u002F \u003Cparam name=\"nWidth\">位图宽度（像素）\u003C\u002Fparam>\n",[546,697,699],{"class":548,"line":698},26,[546,700,701],{},"    \u002F\u002F\u002F \u003Cparam name=\"nHeight\">位图高度（像素）\u003C\u002Fparam>\n",[546,703,705],{"class":548,"line":704},27,[546,706,707],{},"    \u002F\u002F\u002F \u003Creturns>成功返回位图句柄，失败返回IntPtr.Zero\u003C\u002Freturns>\n",[546,709,711],{"class":548,"line":710},28,[546,712,654],{},[546,714,716],{"class":548,"line":715},29,[546,717,718],{},"    public static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight);\n",[546,720,722],{"class":548,"line":721},30,[546,723,667],{"emptyLinePlaceholder":666},[546,725,727],{"class":548,"line":726},31,[546,728,576],{},[546,730,732],{"class":548,"line":731},32,[546,733,734],{},"    \u002F\u002F\u002F 创建与指定设备上下文兼容的内存设备上下文\n",[546,736,738],{"class":548,"line":737},33,[546,739,588],{},[546,741,743],{"class":548,"line":742},34,[546,744,745],{},"    \u002F\u002F\u002F \u003Cparam name=\"hdc\">参考设备上下文句柄\u003C\u002Fparam>\n",[546,747,749],{"class":548,"line":748},35,[546,750,751],{},"    \u002F\u002F\u002F \u003Creturns>成功返回内存DC句柄，失败返回IntPtr.Zero\u003C\u002Freturns>\n",[546,753,755],{"class":548,"line":754},36,[546,756,654],{},[546,758,760],{"class":548,"line":759},37,[546,761,762],{},"    public static extern IntPtr CreateCompatibleDC(IntPtr hdc);\n",[546,764,766],{"class":548,"line":765},38,[546,767,667],{"emptyLinePlaceholder":666},[546,769,771],{"class":548,"line":770},39,[546,772,576],{},[546,774,776],{"class":548,"line":775},40,[546,777,778],{},"    \u002F\u002F\u002F 删除指定的设备上下文\n",[546,780,782],{"class":548,"line":781},41,[546,783,588],{},[546,785,787],{"class":548,"line":786},42,[546,788,789],{},"    \u002F\u002F\u002F \u003Cparam name=\"hdc\">要删除的设备上下文句柄\u003C\u002Fparam>\n",[546,791,793],{"class":548,"line":792},43,[546,794,648],{},[546,796,798],{"class":548,"line":797},44,[546,799,654],{},[546,801,803],{"class":548,"line":802},45,[546,804,805],{},"    public static extern bool DeleteDC(IntPtr hdc);\n",[546,807,809],{"class":548,"line":808},46,[546,810,667],{"emptyLinePlaceholder":666},[546,812,814],{"class":548,"line":813},47,[546,815,576],{},[546,817,819],{"class":548,"line":818},48,[546,820,821],{},"    \u002F\u002F\u002F 删除GDI对象（位图、画笔、画刷等）\n",[546,823,825],{"class":548,"line":824},49,[546,826,588],{},[546,828,830],{"class":548,"line":829},50,[546,831,832],{},"    \u002F\u002F\u002F \u003Cparam name=\"hObject\">要删除的GDI对象句柄\u003C\u002Fparam>\n",[546,834,836],{"class":548,"line":835},51,[546,837,648],{},[546,839,841],{"class":548,"line":840},52,[546,842,654],{},[546,844,846],{"class":548,"line":845},53,[546,847,848],{},"    public static extern bool DeleteObject(IntPtr hObject);\n",[546,850,852],{"class":548,"line":851},54,[546,853,667],{"emptyLinePlaceholder":666},[546,855,857],{"class":548,"line":856},55,[546,858,576],{},[546,860,862],{"class":548,"line":861},56,[546,863,864],{},"    \u002F\u002F\u002F 将GDI对象选择到指定的设备上下文中\n",[546,866,868],{"class":548,"line":867},57,[546,869,588],{},[546,871,873],{"class":548,"line":872},58,[546,874,689],{},[546,876,878],{"class":548,"line":877},59,[546,879,880],{},"    \u002F\u002F\u002F \u003Cparam name=\"hgdiobj\">要选择的GDI对象句柄\u003C\u002Fparam>\n",[546,882,884],{"class":548,"line":883},60,[546,885,886],{},"    \u002F\u002F\u002F \u003Creturns>返回之前选择的同类型对象句柄\u003C\u002Freturns>\n",[546,888,890],{"class":548,"line":889},61,[546,891,654],{},[546,893,895],{"class":548,"line":894},62,[546,896,897],{},"    public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);\n",[546,899,901],{"class":548,"line":900},63,[546,902,667],{"emptyLinePlaceholder":666},[546,904,906],{"class":548,"line":905},64,[546,907,576],{},[546,909,911],{"class":548,"line":910},65,[546,912,913],{},"    \u002F\u002F\u002F 获取位图的像素数据\n",[546,915,917],{"class":548,"line":916},66,[546,918,588],{},[546,920,922],{"class":548,"line":921},67,[546,923,689],{},[546,925,927],{"class":548,"line":926},68,[546,928,929],{},"    \u002F\u002F\u002F \u003Cparam name=\"hbmp\">位图句柄\u003C\u002Fparam>\n",[546,931,933],{"class":548,"line":932},69,[546,934,935],{},"    \u002F\u002F\u002F \u003Cparam name=\"uStartScan\">开始扫描的行号\u003C\u002Fparam>\n",[546,937,939],{"class":548,"line":938},70,[546,940,941],{},"    \u002F\u002F\u002F \u003Cparam name=\"cScanLines\">要扫描的行数\u003C\u002Fparam>\n",[546,943,945],{"class":548,"line":944},71,[546,946,947],{},"    \u002F\u002F\u002F \u003Cparam name=\"lpvBits\">接收像素数据的缓冲区\u003C\u002Fparam>\n",[546,949,951],{"class":548,"line":950},72,[546,952,953],{},"    \u002F\u002F\u002F \u003Cparam name=\"lpbi\">位图信息结构\u003C\u002Fparam>\n",[546,955,957],{"class":548,"line":956},73,[546,958,959],{},"    \u002F\u002F\u002F \u003Cparam name=\"uUsage\">颜色表使用方式\u003C\u002Fparam>\n",[546,961,963],{"class":548,"line":962},74,[546,964,965],{},"    \u002F\u002F\u002F \u003Creturns>成功返回扫描行数，失败返回0\u003C\u002Freturns>\n",[546,967,969],{"class":548,"line":968},75,[546,970,654],{},[546,972,974],{"class":548,"line":973},76,[546,975,976],{},"    public static extern int GetDIBits(IntPtr hdc, IntPtr hbmp, uint uStartScan, uint cScanLines, [Out] byte[] lpvBits, ref BITMAPINFO lpbi, uint uUsage);\n",[546,978,980],{"class":548,"line":979},77,[546,981,667],{"emptyLinePlaceholder":666},[546,983,985],{"class":548,"line":984},78,[546,986,987],{},"    \u002F\u002F ========== USER32.dll 函数声明 ==========\n",[546,989,991],{"class":548,"line":990},79,[546,992,570],{},[546,994,996],{"class":548,"line":995},80,[546,997,576],{},[546,999,1001],{"class":548,"line":1000},81,[546,1002,1003],{},"    \u002F\u002F\u002F 获取指定窗口的设备上下文\n",[546,1005,1007],{"class":548,"line":1006},82,[546,1008,588],{},[546,1010,1012],{"class":548,"line":1011},83,[546,1013,1014],{},"    \u002F\u002F\u002F \u003Cparam name=\"hWnd\">窗口句柄，IntPtr.Zero表示整个屏幕\u003C\u002Fparam>\n",[546,1016,1018],{"class":548,"line":1017},84,[546,1019,1020],{},"    \u002F\u002F\u002F \u003Creturns>成功返回DC句柄，失败返回IntPtr.Zero\u003C\u002Freturns>\n",[546,1022,1024],{"class":548,"line":1023},85,[546,1025,1026],{},"    [DllImport(\"user32.dll\")]\n",[546,1028,1030],{"class":548,"line":1029},86,[546,1031,1032],{},"    public static extern IntPtr GetDC(IntPtr hWnd);\n",[546,1034,1036],{"class":548,"line":1035},87,[546,1037,667],{"emptyLinePlaceholder":666},[546,1039,1041],{"class":548,"line":1040},88,[546,1042,576],{},[546,1044,1046],{"class":548,"line":1045},89,[546,1047,1048],{},"    \u002F\u002F\u002F 释放设备上下文\n",[546,1050,1052],{"class":548,"line":1051},90,[546,1053,588],{},[546,1055,1057],{"class":548,"line":1056},91,[546,1058,1059],{},"    \u002F\u002F\u002F \u003Cparam name=\"hWnd\">窗口句柄\u003C\u002Fparam>\n",[546,1061,1063],{"class":548,"line":1062},92,[546,1064,1065],{},"    \u002F\u002F\u002F \u003Cparam name=\"hDC\">要释放的设备上下文句柄\u003C\u002Fparam>\n",[546,1067,1069],{"class":548,"line":1068},93,[546,1070,1071],{},"    \u002F\u002F\u002F \u003Creturns>成功返回1，失败返回0\u003C\u002Freturns>\n",[546,1073,1075],{"class":548,"line":1074},94,[546,1076,1026],{},[546,1078,1080],{"class":548,"line":1079},95,[546,1081,1082],{},"    public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);\n",[546,1084,1086],{"class":548,"line":1085},96,[546,1087,667],{"emptyLinePlaceholder":666},[546,1089,1091],{"class":548,"line":1090},97,[546,1092,1093],{},"    #region 常量和结构体定义\n",[546,1095,1097],{"class":548,"line":1096},98,[546,1098,570],{},[546,1100,1102],{"class":548,"line":1101},99,[546,1103,576],{},[546,1105,1107],{"class":548,"line":1106},100,[546,1108,1109],{},"    \u002F\u002F\u002F 光栅操作码 - 直接复制源到目标\n",[546,1111,1113],{"class":548,"line":1112},101,[546,1114,588],{},[546,1116,1118],{"class":548,"line":1117},102,[546,1119,1120],{},"    public const uint SRCCOPY = 0x00CC0020;\n",[546,1122,1124],{"class":548,"line":1123},103,[546,1125,570],{},[546,1127,1129],{"class":548,"line":1128},104,[546,1130,576],{},[546,1132,1134],{"class":548,"line":1133},105,[546,1135,1136],{},"    \u002F\u002F\u002F DIB颜色表使用方式 - 使用RGB颜色值\n",[546,1138,1140],{"class":548,"line":1139},106,[546,1141,588],{},[546,1143,1145],{"class":548,"line":1144},107,[546,1146,1147],{},"    public const uint DIB_RGB_COLORS = 0;\n",[546,1149,1151],{"class":548,"line":1150},108,[546,1152,667],{"emptyLinePlaceholder":666},[546,1154,1156],{"class":548,"line":1155},109,[546,1157,576],{},[546,1159,1161],{"class":548,"line":1160},110,[546,1162,1163],{},"    \u002F\u002F\u002F 位图信息结构体\n",[546,1165,1167],{"class":548,"line":1166},111,[546,1168,588],{},[546,1170,1172],{"class":548,"line":1171},112,[546,1173,1174],{},"    [StructLayout(LayoutKind.Sequential)]\n",[546,1176,1178],{"class":548,"line":1177},113,[546,1179,1180],{},"    public struct BITMAPINFO\n",[546,1182,1184],{"class":548,"line":1183},114,[546,1185,1186],{},"    {\n",[546,1188,1190],{"class":548,"line":1189},115,[546,1191,1192],{},"        public BITMAPINFOHEADER bmiHeader;  \u002F\u002F 位图头信息\n",[546,1194,1196],{"class":548,"line":1195},116,[546,1197,1198],{},"        public RGBQUAD bmiColors;           \u002F\u002F 颜色表（对于调色板位图）\n",[546,1200,1202],{"class":548,"line":1201},117,[546,1203,1204],{},"    }\n",[546,1206,1208],{"class":548,"line":1207},118,[546,1209,667],{"emptyLinePlaceholder":666},[546,1211,1213],{"class":548,"line":1212},119,[546,1214,576],{},[546,1216,1218],{"class":548,"line":1217},120,[546,1219,1220],{},"    \u002F\u002F\u002F 位图头信息结构体\n",[546,1222,1224],{"class":548,"line":1223},121,[546,1225,588],{},[546,1227,1229],{"class":548,"line":1228},122,[546,1230,1174],{},[546,1232,1234],{"class":548,"line":1233},123,[546,1235,1236],{},"    public struct BITMAPINFOHEADER\n",[546,1238,1240],{"class":548,"line":1239},124,[546,1241,1186],{},[546,1243,1245],{"class":548,"line":1244},125,[546,1246,1247],{},"        public uint biSize;           \u002F\u002F 结构体大小\n",[546,1249,1251],{"class":548,"line":1250},126,[546,1252,1253],{},"        public int biWidth;           \u002F\u002F 位图宽度（像素）\n",[546,1255,1257],{"class":548,"line":1256},127,[546,1258,1259],{},"        public int biHeight;          \u002F\u002F 位图高度（像素，负数表示从上到下）\n",[546,1261,1263],{"class":548,"line":1262},128,[546,1264,1265],{},"        public ushort biPlanes;       \u002F\u002F 颜色平面数（必须为1）\n",[546,1267,1269],{"class":548,"line":1268},129,[546,1270,1271],{},"        public ushort biBitCount;     \u002F\u002F 每像素位数（1,4,8,16,24,32）\n",[546,1273,1275],{"class":548,"line":1274},130,[546,1276,1277],{},"        public uint biCompression;    \u002F\u002F 压缩方式（0=无压缩）\n",[546,1279,1281],{"class":548,"line":1280},131,[546,1282,1283],{},"        public uint biSizeImage;      \u002F\u002F 图像数据大小（字节）\n",[546,1285,1287],{"class":548,"line":1286},132,[546,1288,1289],{},"        public int biXPelsPerMeter;   \u002F\u002F 水平分辨率（像素\u002F米）\n",[546,1291,1293],{"class":548,"line":1292},133,[546,1294,1295],{},"        public int biYPelsPerMeter;   \u002F\u002F 垂直分辨率（像素\u002F米）\n",[546,1297,1299],{"class":548,"line":1298},134,[546,1300,1301],{},"        public uint biClrUsed;        \u002F\u002F 使用的颜色数\n",[546,1303,1305],{"class":548,"line":1304},135,[546,1306,1307],{},"        public uint biClrImportant;   \u002F\u002F 重要颜色数\n",[546,1309,1311],{"class":548,"line":1310},136,[546,1312,1204],{},[546,1314,1316],{"class":548,"line":1315},137,[546,1317,667],{"emptyLinePlaceholder":666},[546,1319,1321],{"class":548,"line":1320},138,[546,1322,576],{},[546,1324,1326],{"class":548,"line":1325},139,[546,1327,1328],{},"    \u002F\u002F\u002F RGB颜色四元组结构体\n",[546,1330,1332],{"class":548,"line":1331},140,[546,1333,588],{},[546,1335,1337],{"class":548,"line":1336},141,[546,1338,1174],{},[546,1340,1342],{"class":548,"line":1341},142,[546,1343,1344],{},"    public struct RGBQUAD\n",[546,1346,1348],{"class":548,"line":1347},143,[546,1349,1186],{},[546,1351,1353],{"class":548,"line":1352},144,[546,1354,1355],{},"        public byte rgbBlue;      \u002F\u002F 蓝色分量\n",[546,1357,1359],{"class":548,"line":1358},145,[546,1360,1361],{},"        public byte rgbGreen;     \u002F\u002F 绿色分量\n",[546,1363,1365],{"class":548,"line":1364},146,[546,1366,1367],{},"        public byte rgbRed;       \u002F\u002F 红色分量\n",[546,1369,1371],{"class":548,"line":1370},147,[546,1372,1373],{},"        public byte rgbReserved;  \u002F\u002F 保留字段\n",[546,1375,1377],{"class":548,"line":1376},148,[546,1378,1204],{},[546,1380,1382],{"class":548,"line":1381},149,[546,1383,1384],{},"    #endregion\n",[546,1386,1388],{"class":548,"line":1387},150,[546,1389,1390],{},"}\n",[38,1392,1394],{"id":1393},"pinvoke-声明要点解析","P\u002FInvoke 声明要点解析",[144,1396,1398],{"id":1397},"_1-dllimport-特性","1. DllImport 特性",[91,1400,1401,1406,1412],{},[57,1402,1403,1405],{},[45,1404,160],{},"：告诉 .NET 运行时从哪个 DLL 导入函数",[57,1407,1408,1411],{},[45,1409,1410],{},"参数","：DLL 文件名（如 \"gdi32.dll\"）",[57,1413,1414,167,1417],{},[45,1415,1416],{},"可选参数",[91,1418,1419,1425,1431],{},[57,1420,1421,1424],{},[17,1422,1423],{},"EntryPoint","：指定函数名（如果 C# 方法名与 DLL 函数名不同）",[57,1426,1427,1430],{},[17,1428,1429],{},"CallingConvention","：指定调用约定（默认是 Winapi）",[57,1432,1433,1436],{},[17,1434,1435],{},"CharSet","：指定字符集（默认是 Ansi）",[144,1438,1440],{"id":1439},"_2-extern-关键字","2. extern 关键字",[91,1442,1443,1448],{},[57,1444,1445,1447],{},[45,1446,160],{},"：声明这是一个外部函数，由非托管代码实现",[57,1449,1450],{},[45,1451,1452],{},"必须与 static 一起使用",[144,1454,1456],{"id":1455},"_3-数据类型映射","3. 数据类型映射",[91,1458,1459,1465,1471,1477],{},[57,1460,1461,1464],{},[45,1462,1463],{},"IntPtr","：对应 Windows 中的句柄类型（HDC、HBITMAP 等）",[57,1466,1467,1470],{},[45,1468,1469],{},"int","：对应 Windows 中的 32 位整数",[57,1472,1473,1476],{},[45,1474,1475],{},"uint","：对应 Windows 中的无符号 32 位整数",[57,1478,1479,1484],{},[45,1480,1481,1482],{},"byte",[546,1483],{},"：对应 Windows 中的字节数组缓冲区",[144,1486,1488],{"id":1487},"_4-结构体布局","4. 结构体布局",[91,1490,1491,1497],{},[57,1492,1493,1496],{},[45,1494,1495],{},"StructLayout(LayoutKind.Sequential)","：确保结构体成员按顺序排列",[57,1498,1499,1501],{},[45,1500,160],{},"：保证与 C\u002FC++ 结构体的内存布局一致",[33,1503,1504],{"id":1504},"屏幕捕获方法封装详解",[21,1506,1507],{},"然后是封装颜色获取方法，这里我们将详细分析每个步骤：",[10,1509,1511],{"className":540,"code":1510,"language":542,"meta":19,"style":19},"\u002F\u002F 方法封装\npublic static class ColorService\n{\n    public static byte[]? CaptureScreenPixels(out int width, out int height, out int stride)\n    {\n        \u002F\u002F 1. 获取屏幕尺寸\n        width = (int)SystemParameters.PrimaryScreenWidth;\n        height = (int)SystemParameters.PrimaryScreenHeight;\n        stride = 0;\n\n        \u002F\u002F GDI 句柄，必须在 finally 中释放\n        IntPtr screenDc = IntPtr.Zero;\n        IntPtr memDc = IntPtr.Zero;\n        IntPtr hBitmap = IntPtr.Zero;\n        IntPtr hOldBitmap = IntPtr.Zero;\n\n        try\n        {\n            \u002F\u002F 2. 获取屏幕DC\n            screenDc = GetDC(IntPtr.Zero);\n            if (screenDc == IntPtr.Zero) return null;\n\n            \u002F\u002F 3. 创建兼容的内存DC和位图\n            memDc = CreateCompatibleDC(screenDc);\n            if (memDc == IntPtr.Zero) return null;\n\n            hBitmap = CreateCompatibleBitmap(screenDc, width, height);\n            if (hBitmap == IntPtr.Zero) return null;\n\n            \u002F\u002F 4. 将位图选入内存DC\n            hOldBitmap = SelectObject(memDc, hBitmap);\n\n            \u002F\u002F 5. 将屏幕内容复制到内存DC\n            BitBlt(memDc, 0, 0, width, height, screenDc, 0, 0, SRCCOPY);\n\n            \u002F\u002F 6. 从GDI位图中提取像素数据\n            BITMAPINFOHEADER bmi = new BITMAPINFOHEADER\n            {\n                biSize = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADER)),\n                biWidth = width,\n                biHeight = -height, \u002F\u002F 使用负数高度，得到从上到下的“Top-Down”位图\n                biPlanes = 1,\n                biBitCount = 32, \u002F\u002F 32位 BGRA\n                biCompression = 0 \u002F\u002F BI_RGB\n            };\n\n            int bytesPerPixel = 4;\n            stride = width * bytesPerPixel;\n            byte[] pixels = new byte[stride * height];\n\n            var result = GetDIBits(memDc, hBitmap, 0, (uint)height, pixels,\n                ref Unsafe.As\u003CBITMAPINFOHEADER, BITMAPINFO>(ref bmi), DIB_RGB_COLORS);\n\n            return result > 0 ? pixels : null;\n        }\n        finally\n        {\n            \u002F\u002F 7. 关键：清理所有GDI资源，防止内存泄漏\n            if (hOldBitmap != IntPtr.Zero)\n            {\n                SelectObject(memDc, hOldBitmap);\n            }\n            if (hBitmap != IntPtr.Zero)\n            {\n                DeleteObject(hBitmap);\n            }\n            if (memDc != IntPtr.Zero)\n            {\n                DeleteDC(memDc);\n            }\n            if (screenDc != IntPtr.Zero)\n            {\n                ReleaseDC(IntPtr.Zero, screenDc);\n            }\n        }\n    }\n",[17,1512,1513,1518,1523,1527,1532,1536,1541,1546,1551,1556,1560,1565,1570,1575,1580,1585,1589,1594,1599,1604,1609,1614,1618,1623,1628,1633,1637,1642,1647,1651,1656,1661,1665,1670,1675,1679,1684,1689,1694,1699,1704,1709,1714,1719,1724,1729,1733,1738,1743,1748,1752,1757,1762,1766,1771,1776,1781,1785,1790,1795,1799,1804,1809,1814,1818,1823,1827,1832,1836,1841,1845,1850,1854,1859,1863,1867],{"__ignoreMap":19},[546,1514,1515],{"class":548,"line":549},[546,1516,1517],{},"\u002F\u002F 方法封装\n",[546,1519,1520],{"class":548,"line":555},[546,1521,1522],{},"public static class ColorService\n",[546,1524,1525],{"class":548,"line":561},[546,1526,558],{},[546,1528,1529],{"class":548,"line":567},[546,1530,1531],{},"    public static byte[]? CaptureScreenPixels(out int width, out int height, out int stride)\n",[546,1533,1534],{"class":548,"line":573},[546,1535,1186],{},[546,1537,1538],{"class":548,"line":579},[546,1539,1540],{},"        \u002F\u002F 1. 获取屏幕尺寸\n",[546,1542,1543],{"class":548,"line":585},[546,1544,1545],{},"        width = (int)SystemParameters.PrimaryScreenWidth;\n",[546,1547,1548],{"class":548,"line":591},[546,1549,1550],{},"        height = (int)SystemParameters.PrimaryScreenHeight;\n",[546,1552,1553],{"class":548,"line":597},[546,1554,1555],{},"        stride = 0;\n",[546,1557,1558],{"class":548,"line":603},[546,1559,667],{"emptyLinePlaceholder":666},[546,1561,1562],{"class":548,"line":609},[546,1563,1564],{},"        \u002F\u002F GDI 句柄，必须在 finally 中释放\n",[546,1566,1567],{"class":548,"line":615},[546,1568,1569],{},"        IntPtr screenDc = IntPtr.Zero;\n",[546,1571,1572],{"class":548,"line":621},[546,1573,1574],{},"        IntPtr memDc = IntPtr.Zero;\n",[546,1576,1577],{"class":548,"line":627},[546,1578,1579],{},"        IntPtr hBitmap = IntPtr.Zero;\n",[546,1581,1582],{"class":548,"line":633},[546,1583,1584],{},"        IntPtr hOldBitmap = IntPtr.Zero;\n",[546,1586,1587],{"class":548,"line":639},[546,1588,667],{"emptyLinePlaceholder":666},[546,1590,1591],{"class":548,"line":645},[546,1592,1593],{},"        try\n",[546,1595,1596],{"class":548,"line":651},[546,1597,1598],{},"        {\n",[546,1600,1601],{"class":548,"line":657},[546,1602,1603],{},"            \u002F\u002F 2. 获取屏幕DC\n",[546,1605,1606],{"class":548,"line":663},[546,1607,1608],{},"            screenDc = GetDC(IntPtr.Zero);\n",[546,1610,1611],{"class":548,"line":670},[546,1612,1613],{},"            if (screenDc == IntPtr.Zero) return null;\n",[546,1615,1616],{"class":548,"line":675},[546,1617,667],{"emptyLinePlaceholder":666},[546,1619,1620],{"class":548,"line":681},[546,1621,1622],{},"            \u002F\u002F 3. 创建兼容的内存DC和位图\n",[546,1624,1625],{"class":548,"line":686},[546,1626,1627],{},"            memDc = CreateCompatibleDC(screenDc);\n",[546,1629,1630],{"class":548,"line":692},[546,1631,1632],{},"            if (memDc == IntPtr.Zero) return null;\n",[546,1634,1635],{"class":548,"line":698},[546,1636,667],{"emptyLinePlaceholder":666},[546,1638,1639],{"class":548,"line":704},[546,1640,1641],{},"            hBitmap = CreateCompatibleBitmap(screenDc, width, height);\n",[546,1643,1644],{"class":548,"line":710},[546,1645,1646],{},"            if (hBitmap == IntPtr.Zero) return null;\n",[546,1648,1649],{"class":548,"line":715},[546,1650,667],{"emptyLinePlaceholder":666},[546,1652,1653],{"class":548,"line":721},[546,1654,1655],{},"            \u002F\u002F 4. 将位图选入内存DC\n",[546,1657,1658],{"class":548,"line":726},[546,1659,1660],{},"            hOldBitmap = SelectObject(memDc, hBitmap);\n",[546,1662,1663],{"class":548,"line":731},[546,1664,667],{"emptyLinePlaceholder":666},[546,1666,1667],{"class":548,"line":737},[546,1668,1669],{},"            \u002F\u002F 5. 将屏幕内容复制到内存DC\n",[546,1671,1672],{"class":548,"line":742},[546,1673,1674],{},"            BitBlt(memDc, 0, 0, width, height, screenDc, 0, 0, SRCCOPY);\n",[546,1676,1677],{"class":548,"line":748},[546,1678,667],{"emptyLinePlaceholder":666},[546,1680,1681],{"class":548,"line":754},[546,1682,1683],{},"            \u002F\u002F 6. 从GDI位图中提取像素数据\n",[546,1685,1686],{"class":548,"line":759},[546,1687,1688],{},"            BITMAPINFOHEADER bmi = new BITMAPINFOHEADER\n",[546,1690,1691],{"class":548,"line":765},[546,1692,1693],{},"            {\n",[546,1695,1696],{"class":548,"line":770},[546,1697,1698],{},"                biSize = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADER)),\n",[546,1700,1701],{"class":548,"line":775},[546,1702,1703],{},"                biWidth = width,\n",[546,1705,1706],{"class":548,"line":781},[546,1707,1708],{},"                biHeight = -height, \u002F\u002F 使用负数高度，得到从上到下的“Top-Down”位图\n",[546,1710,1711],{"class":548,"line":786},[546,1712,1713],{},"                biPlanes = 1,\n",[546,1715,1716],{"class":548,"line":792},[546,1717,1718],{},"                biBitCount = 32, \u002F\u002F 32位 BGRA\n",[546,1720,1721],{"class":548,"line":797},[546,1722,1723],{},"                biCompression = 0 \u002F\u002F BI_RGB\n",[546,1725,1726],{"class":548,"line":802},[546,1727,1728],{},"            };\n",[546,1730,1731],{"class":548,"line":808},[546,1732,667],{"emptyLinePlaceholder":666},[546,1734,1735],{"class":548,"line":813},[546,1736,1737],{},"            int bytesPerPixel = 4;\n",[546,1739,1740],{"class":548,"line":818},[546,1741,1742],{},"            stride = width * bytesPerPixel;\n",[546,1744,1745],{"class":548,"line":824},[546,1746,1747],{},"            byte[] pixels = new byte[stride * height];\n",[546,1749,1750],{"class":548,"line":829},[546,1751,667],{"emptyLinePlaceholder":666},[546,1753,1754],{"class":548,"line":835},[546,1755,1756],{},"            var result = GetDIBits(memDc, hBitmap, 0, (uint)height, pixels,\n",[546,1758,1759],{"class":548,"line":840},[546,1760,1761],{},"                ref Unsafe.As\u003CBITMAPINFOHEADER, BITMAPINFO>(ref bmi), DIB_RGB_COLORS);\n",[546,1763,1764],{"class":548,"line":845},[546,1765,667],{"emptyLinePlaceholder":666},[546,1767,1768],{"class":548,"line":851},[546,1769,1770],{},"            return result > 0 ? pixels : null;\n",[546,1772,1773],{"class":548,"line":856},[546,1774,1775],{},"        }\n",[546,1777,1778],{"class":548,"line":861},[546,1779,1780],{},"        finally\n",[546,1782,1783],{"class":548,"line":867},[546,1784,1598],{},[546,1786,1787],{"class":548,"line":872},[546,1788,1789],{},"            \u002F\u002F 7. 关键：清理所有GDI资源，防止内存泄漏\n",[546,1791,1792],{"class":548,"line":877},[546,1793,1794],{},"            if (hOldBitmap != IntPtr.Zero)\n",[546,1796,1797],{"class":548,"line":883},[546,1798,1693],{},[546,1800,1801],{"class":548,"line":889},[546,1802,1803],{},"                SelectObject(memDc, hOldBitmap);\n",[546,1805,1806],{"class":548,"line":894},[546,1807,1808],{},"            }\n",[546,1810,1811],{"class":548,"line":900},[546,1812,1813],{},"            if (hBitmap != IntPtr.Zero)\n",[546,1815,1816],{"class":548,"line":905},[546,1817,1693],{},[546,1819,1820],{"class":548,"line":910},[546,1821,1822],{},"                DeleteObject(hBitmap);\n",[546,1824,1825],{"class":548,"line":916},[546,1826,1808],{},[546,1828,1829],{"class":548,"line":921},[546,1830,1831],{},"            if (memDc != IntPtr.Zero)\n",[546,1833,1834],{"class":548,"line":926},[546,1835,1693],{},[546,1837,1838],{"class":548,"line":932},[546,1839,1840],{},"                DeleteDC(memDc);\n",[546,1842,1843],{"class":548,"line":938},[546,1844,1808],{},[546,1846,1847],{"class":548,"line":944},[546,1848,1849],{},"            if (screenDc != IntPtr.Zero)\n",[546,1851,1852],{"class":548,"line":950},[546,1853,1693],{},[546,1855,1856],{"class":548,"line":956},[546,1857,1858],{},"                ReleaseDC(IntPtr.Zero, screenDc);\n",[546,1860,1861],{"class":548,"line":962},[546,1862,1808],{},[546,1864,1865],{"class":548,"line":968},[546,1866,1775],{},[546,1868,1869],{"class":548,"line":973},[546,1870,1204],{},[33,1872,1874],{"id":1873},"viewmodel-调用实现","ViewModel 调用实现",[21,1876,1877],{},"最后是函数调用，这里展示如何在 MVVM 模式中使用屏幕捕获功能：",[10,1879,1881],{"className":540,"code":1880,"language":542,"meta":19,"style":19},"using CommunityToolkit.Mvvm.Input;\nusing CommunityToolkit.Mvvm.ComponentModel;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Animation.Services;\nusing Wpf.Ui;\nusing System.Windows;\nusing System.Windows.Media;\n\nnamespace Animation.Pages.ColorCollecter;\n\n\u002F\u002F\u002F \u003Csummary>\n\u002F\u002F\u002F 颜色采集器 ViewModel\n\u002F\u002F\u002F 演示如何使用 GDI32 进行屏幕捕获和颜色提取\n\u002F\u002F\u002F \u003C\u002Fsummary>\npublic partial class ColorCollecterViewModel : ViewModel\n{\n    #region 属性定义\n    \n    \u002F\u002F\u002F \u003Csummary>\n    \u002F\u002F\u002F 采集到的颜色画刷\n    \u002F\u002F\u002F \u003C\u002Fsummary>\n    [ObservableProperty]\n    private SolidColorBrush _collectedColor = new SolidColorBrush(Colors.LightGray);\n\n    \u002F\u002F\u002F \u003Csummary>\n    \u002F\u002F\u002F 颜色信息文本\n    \u002F\u002F\u002F \u003C\u002Fsummary>\n    [ObservableProperty]\n    private string _colorInfo = \"点击采集颜色\";\n    \n    #endregion\n\n    #region 命令实现\n    \n    \u002F\u002F\u002F \u003Csummary>\n    \u002F\u002F\u002F 执行颜色采集命令\n    \u002F\u002F\u002F 演示屏幕捕获和像素数据解析的完整流程\n    \u002F\u002F\u002F \u003C\u002Fsummary>\n    [RelayCommand]\n    public void ExcuteColorCollecter()\n    {\n        Console.WriteLine(\"开始颜色采集...\");\n        \n        try\n        {\n            \u002F\u002F ========== 第一步：调用屏幕捕获服务 ==========\n            var pixels = ColorService.CaptureScreenPixels(out int width, out int height, out int stride);\n            \n            if (pixels != null)\n            {\n                \u002F\u002F ========== 第二步：选择采样点 ==========\n                \u002F\u002F 示例：获取屏幕中央像素的颜色\n                int x = width \u002F 2;   \u002F\u002F 屏幕中央 X 坐标\n                int y = height \u002F 2;  \u002F\u002F 屏幕中央 Y 坐标\n\n                \u002F\u002F ========== 第三步：计算像素索引 ==========\n                \u002F\u002F 像素格式是 BGRA (Blue, Green, Red, Alpha)\n                \u002F\u002F 每个像素占用 4 字节，按行存储\n                int index = (y * stride) + (x * 4);\n\n                \u002F\u002F ========== 第四步：提取颜色分量 ==========\n                byte blue = pixels[index];      \u002F\u002F 蓝色分量\n                byte green = pixels[index + 1]; \u002F\u002F 绿色分量\n                byte red = pixels[index + 2];   \u002F\u002F 红色分量\n                byte alpha = pixels[index + 3]; \u002F\u002F 透明度分量\n\n                \u002F\u002F ========== 第五步：创建颜色对象 ==========\n                \u002F\u002F 注意：WPF 的 Color.FromArgb 参数顺序是 (Alpha, Red, Green, Blue)\n                CollectedColor = new SolidColorBrush(Color.FromArgb(alpha, red, green, blue));\n                \n                \u002F\u002F ========== 第六步：更新UI显示 ==========\n                ColorInfo = $\"RGB({red}, {green}, {blue}) | 位置: ({x}, {y})\";\n                \n                Console.WriteLine($\"成功采集颜色: R={red}, G={green}, B={blue}, A={alpha}\");\n                Console.WriteLine($\"屏幕尺寸: {width}x{height}, 步长: {stride}\");\n            }\n            else\n            {\n                \u002F\u002F ========== 错误处理 ==========\n                MessageBox.Show(\"屏幕捕获失败！请检查系统权限或重试。\", \"错误\", \n                    MessageBoxButton.OK, MessageBoxImage.Error);\n                Console.WriteLine(\"屏幕捕获失败\");\n            }\n        }\n        catch (Exception ex)\n        {\n            \u002F\u002F ========== 异常处理 ==========\n            MessageBox.Show($\"颜色采集过程中发生错误：{ex.Message}\", \"异常\", \n                MessageBoxButton.OK, MessageBoxImage.Warning);\n            Console.WriteLine($\"颜色采集异常: {ex.Message}\");\n        }\n    }\n\n    \u002F\u002F\u002F \u003Csummary>\n    \u002F\u002F\u002F 清空颜色命令\n    \u002F\u002F\u002F 重置UI状态到初始状态\n    \u002F\u002F\u002F \u003C\u002Fsummary>\n    [RelayCommand]\n    public void ClearColor()\n    {\n        CollectedColor = new SolidColorBrush(Colors.LightGray);\n        ColorInfo = \"点击采集颜色\";\n        Console.WriteLine(\"颜色已清空，UI状态已重置\");\n    }\n    \n    #endregion\n}\n",[17,1882,1883,1888,1893,1898,1903,1908,1913,1918,1923,1928,1933,1938,1942,1947,1951,1956,1961,1966,1971,1976,1980,1985,1989,1993,1998,2002,2007,2012,2016,2020,2025,2029,2033,2038,2042,2046,2050,2055,2059,2063,2068,2073,2077,2082,2087,2091,2096,2101,2105,2109,2114,2119,2124,2129,2133,2138,2143,2148,2153,2157,2162,2167,2172,2177,2181,2186,2191,2196,2201,2206,2210,2215,2220,2225,2230,2235,2240,2244,2249,2254,2258,2263,2267,2272,2277,2282,2287,2291,2295,2300,2304,2309,2314,2319,2324,2328,2332,2336,2340,2345,2350,2354,2358,2363,2367,2372,2377,2382,2386,2390,2394],{"__ignoreMap":19},[546,1884,1885],{"class":548,"line":549},[546,1886,1887],{},"using CommunityToolkit.Mvvm.Input;\n",[546,1889,1890],{"class":548,"line":555},[546,1891,1892],{},"using CommunityToolkit.Mvvm.ComponentModel;\n",[546,1894,1895],{"class":548,"line":561},[546,1896,1897],{},"using System;\n",[546,1899,1900],{"class":548,"line":567},[546,1901,1902],{},"using System.Collections.Generic;\n",[546,1904,1905],{"class":548,"line":573},[546,1906,1907],{},"using System.Linq;\n",[546,1909,1910],{"class":548,"line":579},[546,1911,1912],{},"using System.Text;\n",[546,1914,1915],{"class":548,"line":585},[546,1916,1917],{},"using System.Threading.Tasks;\n",[546,1919,1920],{"class":548,"line":591},[546,1921,1922],{},"using Animation.Services;\n",[546,1924,1925],{"class":548,"line":597},[546,1926,1927],{},"using Wpf.Ui;\n",[546,1929,1930],{"class":548,"line":603},[546,1931,1932],{},"using System.Windows;\n",[546,1934,1935],{"class":548,"line":609},[546,1936,1937],{},"using System.Windows.Media;\n",[546,1939,1940],{"class":548,"line":615},[546,1941,667],{"emptyLinePlaceholder":666},[546,1943,1944],{"class":548,"line":621},[546,1945,1946],{},"namespace Animation.Pages.ColorCollecter;\n",[546,1948,1949],{"class":548,"line":627},[546,1950,667],{"emptyLinePlaceholder":666},[546,1952,1953],{"class":548,"line":633},[546,1954,1955],{},"\u002F\u002F\u002F \u003Csummary>\n",[546,1957,1958],{"class":548,"line":639},[546,1959,1960],{},"\u002F\u002F\u002F 颜色采集器 ViewModel\n",[546,1962,1963],{"class":548,"line":645},[546,1964,1965],{},"\u002F\u002F\u002F 演示如何使用 GDI32 进行屏幕捕获和颜色提取\n",[546,1967,1968],{"class":548,"line":651},[546,1969,1970],{},"\u002F\u002F\u002F \u003C\u002Fsummary>\n",[546,1972,1973],{"class":548,"line":657},[546,1974,1975],{},"public partial class ColorCollecterViewModel : ViewModel\n",[546,1977,1978],{"class":548,"line":663},[546,1979,558],{},[546,1981,1982],{"class":548,"line":670},[546,1983,1984],{},"    #region 属性定义\n",[546,1986,1987],{"class":548,"line":675},[546,1988,570],{},[546,1990,1991],{"class":548,"line":681},[546,1992,576],{},[546,1994,1995],{"class":548,"line":686},[546,1996,1997],{},"    \u002F\u002F\u002F 采集到的颜色画刷\n",[546,1999,2000],{"class":548,"line":692},[546,2001,588],{},[546,2003,2004],{"class":548,"line":698},[546,2005,2006],{},"    [ObservableProperty]\n",[546,2008,2009],{"class":548,"line":704},[546,2010,2011],{},"    private SolidColorBrush _collectedColor = new SolidColorBrush(Colors.LightGray);\n",[546,2013,2014],{"class":548,"line":710},[546,2015,667],{"emptyLinePlaceholder":666},[546,2017,2018],{"class":548,"line":715},[546,2019,576],{},[546,2021,2022],{"class":548,"line":721},[546,2023,2024],{},"    \u002F\u002F\u002F 颜色信息文本\n",[546,2026,2027],{"class":548,"line":726},[546,2028,588],{},[546,2030,2031],{"class":548,"line":731},[546,2032,2006],{},[546,2034,2035],{"class":548,"line":737},[546,2036,2037],{},"    private string _colorInfo = \"点击采集颜色\";\n",[546,2039,2040],{"class":548,"line":742},[546,2041,570],{},[546,2043,2044],{"class":548,"line":748},[546,2045,1384],{},[546,2047,2048],{"class":548,"line":754},[546,2049,667],{"emptyLinePlaceholder":666},[546,2051,2052],{"class":548,"line":759},[546,2053,2054],{},"    #region 命令实现\n",[546,2056,2057],{"class":548,"line":765},[546,2058,570],{},[546,2060,2061],{"class":548,"line":770},[546,2062,576],{},[546,2064,2065],{"class":548,"line":775},[546,2066,2067],{},"    \u002F\u002F\u002F 执行颜色采集命令\n",[546,2069,2070],{"class":548,"line":781},[546,2071,2072],{},"    \u002F\u002F\u002F 演示屏幕捕获和像素数据解析的完整流程\n",[546,2074,2075],{"class":548,"line":786},[546,2076,588],{},[546,2078,2079],{"class":548,"line":792},[546,2080,2081],{},"    [RelayCommand]\n",[546,2083,2084],{"class":548,"line":797},[546,2085,2086],{},"    public void ExcuteColorCollecter()\n",[546,2088,2089],{"class":548,"line":802},[546,2090,1186],{},[546,2092,2093],{"class":548,"line":808},[546,2094,2095],{},"        Console.WriteLine(\"开始颜色采集...\");\n",[546,2097,2098],{"class":548,"line":813},[546,2099,2100],{},"        \n",[546,2102,2103],{"class":548,"line":818},[546,2104,1593],{},[546,2106,2107],{"class":548,"line":824},[546,2108,1598],{},[546,2110,2111],{"class":548,"line":829},[546,2112,2113],{},"            \u002F\u002F ========== 第一步：调用屏幕捕获服务 ==========\n",[546,2115,2116],{"class":548,"line":835},[546,2117,2118],{},"            var pixels = ColorService.CaptureScreenPixels(out int width, out int height, out int stride);\n",[546,2120,2121],{"class":548,"line":840},[546,2122,2123],{},"            \n",[546,2125,2126],{"class":548,"line":845},[546,2127,2128],{},"            if (pixels != null)\n",[546,2130,2131],{"class":548,"line":851},[546,2132,1693],{},[546,2134,2135],{"class":548,"line":856},[546,2136,2137],{},"                \u002F\u002F ========== 第二步：选择采样点 ==========\n",[546,2139,2140],{"class":548,"line":861},[546,2141,2142],{},"                \u002F\u002F 示例：获取屏幕中央像素的颜色\n",[546,2144,2145],{"class":548,"line":867},[546,2146,2147],{},"                int x = width \u002F 2;   \u002F\u002F 屏幕中央 X 坐标\n",[546,2149,2150],{"class":548,"line":872},[546,2151,2152],{},"                int y = height \u002F 2;  \u002F\u002F 屏幕中央 Y 坐标\n",[546,2154,2155],{"class":548,"line":877},[546,2156,667],{"emptyLinePlaceholder":666},[546,2158,2159],{"class":548,"line":883},[546,2160,2161],{},"                \u002F\u002F ========== 第三步：计算像素索引 ==========\n",[546,2163,2164],{"class":548,"line":889},[546,2165,2166],{},"                \u002F\u002F 像素格式是 BGRA (Blue, Green, Red, Alpha)\n",[546,2168,2169],{"class":548,"line":894},[546,2170,2171],{},"                \u002F\u002F 每个像素占用 4 字节，按行存储\n",[546,2173,2174],{"class":548,"line":900},[546,2175,2176],{},"                int index = (y * stride) + (x * 4);\n",[546,2178,2179],{"class":548,"line":905},[546,2180,667],{"emptyLinePlaceholder":666},[546,2182,2183],{"class":548,"line":910},[546,2184,2185],{},"                \u002F\u002F ========== 第四步：提取颜色分量 ==========\n",[546,2187,2188],{"class":548,"line":916},[546,2189,2190],{},"                byte blue = pixels[index];      \u002F\u002F 蓝色分量\n",[546,2192,2193],{"class":548,"line":921},[546,2194,2195],{},"                byte green = pixels[index + 1]; \u002F\u002F 绿色分量\n",[546,2197,2198],{"class":548,"line":926},[546,2199,2200],{},"                byte red = pixels[index + 2];   \u002F\u002F 红色分量\n",[546,2202,2203],{"class":548,"line":932},[546,2204,2205],{},"                byte alpha = pixels[index + 3]; \u002F\u002F 透明度分量\n",[546,2207,2208],{"class":548,"line":938},[546,2209,667],{"emptyLinePlaceholder":666},[546,2211,2212],{"class":548,"line":944},[546,2213,2214],{},"                \u002F\u002F ========== 第五步：创建颜色对象 ==========\n",[546,2216,2217],{"class":548,"line":950},[546,2218,2219],{},"                \u002F\u002F 注意：WPF 的 Color.FromArgb 参数顺序是 (Alpha, Red, Green, Blue)\n",[546,2221,2222],{"class":548,"line":956},[546,2223,2224],{},"                CollectedColor = new SolidColorBrush(Color.FromArgb(alpha, red, green, blue));\n",[546,2226,2227],{"class":548,"line":962},[546,2228,2229],{},"                \n",[546,2231,2232],{"class":548,"line":968},[546,2233,2234],{},"                \u002F\u002F ========== 第六步：更新UI显示 ==========\n",[546,2236,2237],{"class":548,"line":973},[546,2238,2239],{},"                ColorInfo = $\"RGB({red}, {green}, {blue}) | 位置: ({x}, {y})\";\n",[546,2241,2242],{"class":548,"line":979},[546,2243,2229],{},[546,2245,2246],{"class":548,"line":984},[546,2247,2248],{},"                Console.WriteLine($\"成功采集颜色: R={red}, G={green}, B={blue}, A={alpha}\");\n",[546,2250,2251],{"class":548,"line":990},[546,2252,2253],{},"                Console.WriteLine($\"屏幕尺寸: {width}x{height}, 步长: {stride}\");\n",[546,2255,2256],{"class":548,"line":995},[546,2257,1808],{},[546,2259,2260],{"class":548,"line":1000},[546,2261,2262],{},"            else\n",[546,2264,2265],{"class":548,"line":1006},[546,2266,1693],{},[546,2268,2269],{"class":548,"line":1011},[546,2270,2271],{},"                \u002F\u002F ========== 错误处理 ==========\n",[546,2273,2274],{"class":548,"line":1017},[546,2275,2276],{},"                MessageBox.Show(\"屏幕捕获失败！请检查系统权限或重试。\", \"错误\", \n",[546,2278,2279],{"class":548,"line":1023},[546,2280,2281],{},"                    MessageBoxButton.OK, MessageBoxImage.Error);\n",[546,2283,2284],{"class":548,"line":1029},[546,2285,2286],{},"                Console.WriteLine(\"屏幕捕获失败\");\n",[546,2288,2289],{"class":548,"line":1035},[546,2290,1808],{},[546,2292,2293],{"class":548,"line":1040},[546,2294,1775],{},[546,2296,2297],{"class":548,"line":1045},[546,2298,2299],{},"        catch (Exception ex)\n",[546,2301,2302],{"class":548,"line":1051},[546,2303,1598],{},[546,2305,2306],{"class":548,"line":1056},[546,2307,2308],{},"            \u002F\u002F ========== 异常处理 ==========\n",[546,2310,2311],{"class":548,"line":1062},[546,2312,2313],{},"            MessageBox.Show($\"颜色采集过程中发生错误：{ex.Message}\", \"异常\", \n",[546,2315,2316],{"class":548,"line":1068},[546,2317,2318],{},"                MessageBoxButton.OK, MessageBoxImage.Warning);\n",[546,2320,2321],{"class":548,"line":1074},[546,2322,2323],{},"            Console.WriteLine($\"颜色采集异常: {ex.Message}\");\n",[546,2325,2326],{"class":548,"line":1079},[546,2327,1775],{},[546,2329,2330],{"class":548,"line":1085},[546,2331,1204],{},[546,2333,2334],{"class":548,"line":1090},[546,2335,667],{"emptyLinePlaceholder":666},[546,2337,2338],{"class":548,"line":1096},[546,2339,576],{},[546,2341,2342],{"class":548,"line":1101},[546,2343,2344],{},"    \u002F\u002F\u002F 清空颜色命令\n",[546,2346,2347],{"class":548,"line":1106},[546,2348,2349],{},"    \u002F\u002F\u002F 重置UI状态到初始状态\n",[546,2351,2352],{"class":548,"line":1112},[546,2353,588],{},[546,2355,2356],{"class":548,"line":1117},[546,2357,2081],{},[546,2359,2360],{"class":548,"line":1123},[546,2361,2362],{},"    public void ClearColor()\n",[546,2364,2365],{"class":548,"line":1128},[546,2366,1186],{},[546,2368,2369],{"class":548,"line":1133},[546,2370,2371],{},"        CollectedColor = new SolidColorBrush(Colors.LightGray);\n",[546,2373,2374],{"class":548,"line":1139},[546,2375,2376],{},"        ColorInfo = \"点击采集颜色\";\n",[546,2378,2379],{"class":548,"line":1144},[546,2380,2381],{},"        Console.WriteLine(\"颜色已清空，UI状态已重置\");\n",[546,2383,2384],{"class":548,"line":1150},[546,2385,1204],{},[546,2387,2388],{"class":548,"line":1155},[546,2389,570],{},[546,2391,2392],{"class":548,"line":1160},[546,2393,1384],{},[546,2395,2396],{"class":548,"line":1166},[546,2397,1390],{},[38,2399,2401],{"id":2400},"viewmodel-实现解析","ViewModel 实现解析",[144,2403,2405],{"id":2404},"_1-mvvm-模式应用","1. MVVM 模式应用",[91,2407,2408,2414,2420],{},[57,2409,2410,2413],{},[45,2411,2412],{},"ObservableProperty","：使用 CommunityToolkit.Mvvm 的源生成器自动生成属性通知",[57,2415,2416,2419],{},[45,2417,2418],{},"RelayCommand","：自动生成命令实现，支持异步操作",[57,2421,2422,2425],{},[45,2423,2424],{},"数据绑定","：属性变化自动通知UI更新",[144,2427,2429],{"id":2428},"_2-屏幕捕获集成","2. 屏幕捕获集成",[91,2431,2432,2438,2444],{},[57,2433,2434,2437],{},[45,2435,2436],{},"服务调用","：调用 ColorService.CaptureScreenPixels 获取像素数据",[57,2439,2440,2443],{},[45,2441,2442],{},"错误处理","：完整的异常处理和用户友好的错误提示",[57,2445,2446,2449],{},[45,2447,2448],{},"日志记录","：详细的控制台输出便于调试",[144,2451,2453],{"id":2452},"_3-像素数据解析","3. 像素数据解析",[91,2455,2456,2462,2468],{},[57,2457,2458,2461],{},[45,2459,2460],{},"坐标计算","：计算屏幕中央像素的坐标",[57,2463,2464,2467],{},[45,2465,2466],{},"索引计算","：根据步长和坐标计算像素在字节数组中的索引",[57,2469,2470,2473],{},[45,2471,2472],{},"颜色提取","：按 BGRA 格式提取颜色分量",[144,2475,2477],{"id":2476},"_4-ui-更新机制","4. UI 更新机制",[91,2479,2480,2486,2492],{},[57,2481,2482,2485],{},[45,2483,2484],{},"颜色显示","：使用 SolidColorBrush 显示采集到的颜色",[57,2487,2488,2491],{},[45,2489,2490],{},"信息展示","：显示 RGB 值和坐标信息",[57,2493,2494,2497],{},[45,2495,2496],{},"状态管理","：提供清空功能重置UI状态",[38,2499,2500],{"id":2500},"扩展功能建议",[144,2502,2504],{"id":2503},"_1-多采样点支持","1. 多采样点支持",[10,2506,2508],{"className":540,"code":2507,"language":542,"meta":19,"style":19},"\u002F\u002F 可以扩展为支持多个采样点\npublic void SampleMultiplePoints(Point[] points)\n{\n    \u002F\u002F 实现多个点的颜色采样\n}\n",[17,2509,2510,2515,2520,2524,2529],{"__ignoreMap":19},[546,2511,2512],{"class":548,"line":549},[546,2513,2514],{},"\u002F\u002F 可以扩展为支持多个采样点\n",[546,2516,2517],{"class":548,"line":555},[546,2518,2519],{},"public void SampleMultiplePoints(Point[] points)\n",[546,2521,2522],{"class":548,"line":561},[546,2523,558],{},[546,2525,2526],{"class":548,"line":567},[546,2527,2528],{},"    \u002F\u002F 实现多个点的颜色采样\n",[546,2530,2531],{"class":548,"line":573},[546,2532,1390],{},[144,2534,2536],{"id":2535},"_2-颜色格式转换","2. 颜色格式转换",[10,2538,2540],{"className":540,"code":2539,"language":542,"meta":19,"style":19},"\u002F\u002F 支持不同颜色格式的转换\npublic string GetHexColor(Color color)\n{\n    return $\"#{color.R:X2}{color.G:X2}{color.B:X2}\";\n}\n",[17,2541,2542,2547,2552,2556,2561],{"__ignoreMap":19},[546,2543,2544],{"class":548,"line":549},[546,2545,2546],{},"\u002F\u002F 支持不同颜色格式的转换\n",[546,2548,2549],{"class":548,"line":555},[546,2550,2551],{},"public string GetHexColor(Color color)\n",[546,2553,2554],{"class":548,"line":561},[546,2555,558],{},[546,2557,2558],{"class":548,"line":567},[546,2559,2560],{},"    return $\"#{color.R:X2}{color.G:X2}{color.B:X2}\";\n",[546,2562,2563],{"class":548,"line":573},[546,2564,1390],{},[144,2566,2568],{"id":2567},"_3-历史记录功能","3. 历史记录功能",[10,2570,2572],{"className":540,"code":2571,"language":542,"meta":19,"style":19},"\u002F\u002F 保存颜色采集历史\npublic ObservableCollection\u003CColorHistoryItem> ColorHistory { get; set; }\n",[17,2573,2574,2579],{"__ignoreMap":19},[546,2575,2576],{"class":548,"line":549},[546,2577,2578],{},"\u002F\u002F 保存颜色采集历史\n",[546,2580,2581],{"class":548,"line":555},[546,2582,2583],{},"public ObservableCollection\u003CColorHistoryItem> ColorHistory { get; set; }\n",[33,2585,2586],{"id":2586},"总结与最佳实践",[38,2588,2589],{"id":2589},"关键技术要点",[54,2591,2592,2608,2624],{},[57,2593,2594,2597],{},[45,2595,2596],{},"P\u002FInvoke 平台调用",[91,2598,2599,2602,2605],{},[57,2600,2601],{},"正确声明外部函数和结构体",[57,2603,2604],{},"处理数据类型映射和内存布局",[57,2606,2607],{},"管理非托管资源的生命周期",[57,2609,2610,2613],{},[45,2611,2612],{},"GDI 图形编程",[91,2614,2615,2618,2621],{},[57,2616,2617],{},"理解设备上下文 (DC) 的概念",[57,2619,2620],{},"掌握位图操作和像素数据传输",[57,2622,2623],{},"正确处理 GDI 资源释放",[57,2625,2626,2629],{},[45,2627,2628],{},"屏幕捕获流程",[91,2630,2631,2634,2637,2640],{},[57,2632,2633],{},"获取屏幕设备上下文",[57,2635,2636],{},"创建兼容的内存 DC 和位图",[57,2638,2639],{},"执行位块传输操作",[57,2641,2642],{},"提取像素数据",[38,2644,2645],{"id":2645},"性能优化建议",[54,2647,2648,2668,2683],{},[57,2649,2650,2653],{},[45,2651,2652],{},"内存管理",[91,2654,2655,2658,2665],{},[57,2656,2657],{},"及时释放 GDI 资源，避免内存泄漏",[57,2659,2660,2661,2664],{},"使用 ",[17,2662,2663],{},"Unsafe.As"," 进行高效的类型转换",[57,2666,2667],{},"考虑使用对象池减少内存分配",[57,2669,2670,2672],{},[45,2671,2442],{},[91,2673,2674,2677,2680],{},[57,2675,2676],{},"检查每个 GDI 函数的返回值",[57,2678,2679],{},"使用 try-finally 确保资源清理",[57,2681,2682],{},"提供用户友好的错误提示",[57,2684,2685,2688],{},[45,2686,2687],{},"多显示器支持",[91,2689,2690,2696],{},[57,2691,2660,2692,2695],{},[17,2693,2694],{},"SystemParameters.VirtualScreenWidth\u002FHeight"," 获取虚拟屏幕尺寸",[57,2697,2698,2699,2702],{},"考虑使用 ",[17,2700,2701],{},"EnumDisplayMonitors"," 枚举所有显示器",[38,2704,2705],{"id":2705},"安全注意事项",[54,2707,2708,2721,2734],{},[57,2709,2710,2713],{},[45,2711,2712],{},"权限要求",[91,2714,2715,2718],{},[57,2716,2717],{},"某些系统可能需要管理员权限",[57,2719,2720],{},"考虑使用 UAC 提示或权限提升",[57,2722,2723,2726],{},[45,2724,2725],{},"隐私保护",[91,2727,2728,2731],{},[57,2729,2730],{},"明确告知用户屏幕捕获的目的",[57,2732,2733],{},"避免在后台静默捕获屏幕内容",[57,2735,2736,2739],{},[45,2737,2738],{},"跨平台兼容性",[91,2740,2741,2744],{},[57,2742,2743],{},"GDI32 仅适用于 Windows 平台",[57,2745,2746],{},"考虑使用跨平台的替代方案（如 SkiaSharp）",[38,2748,2749],{"id":2749},"替代技术方案",[54,2751,2752,2768,2784],{},[57,2753,2754,2757],{},[45,2755,2756],{},"Windows Graphics Capture (WGC)",[91,2758,2759,2762,2765],{},[57,2760,2761],{},"更现代的屏幕捕获 API",[57,2763,2764],{},"更好的性能和功能支持",[57,2766,2767],{},"支持窗口级别的捕获",[57,2769,2770,2773],{},[45,2771,2772],{},"DirectX\u002FDXGI",[91,2774,2775,2778,2781],{},[57,2776,2777],{},"硬件加速的图形处理",[57,2779,2780],{},"更低的 CPU 占用率",[57,2782,2783],{},"支持更复杂的图形操作",[57,2785,2786,2788],{},[45,2787,30],{},[91,2789,2790,2793,2796],{},[57,2791,2792],{},".NET 内置的屏幕捕获方法",[57,2794,2795],{},"更简单的 API，但性能较低",[57,2797,2798],{},"适合简单的屏幕截图需求",[21,2800,2801],{},"这个完整的实现展示了如何使用 P\u002FInvoke 调用 GDI32 进行屏幕捕获，涵盖了从底层 API 调用到高级 MVVM 模式应用的完整技术栈。",[2803,2804,2805],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":19,"searchDepth":555,"depth":555,"links":2807},[2808,2813,2818,2826,2829,2830,2834],{"id":35,"depth":555,"text":36,"children":2809},[2810,2811,2812],{"id":40,"depth":561,"text":41},{"id":51,"depth":561,"text":52},{"id":83,"depth":561,"text":84},{"id":126,"depth":555,"text":127,"children":2814},[2815,2816,2817],{"id":130,"depth":561,"text":131},{"id":141,"depth":561,"text":142},{"id":260,"depth":561,"text":261},{"id":355,"depth":555,"text":355,"children":2819},[2820,2821,2822,2824,2825],{"id":368,"depth":561,"text":369},{"id":400,"depth":561,"text":401},{"id":433,"depth":561,"text":2823},"3. 执行位块传输 (BitBlt)",{"id":471,"depth":561,"text":472},{"id":499,"depth":561,"text":500},{"id":533,"depth":555,"text":534,"children":2827},[2828],{"id":1393,"depth":561,"text":1394},{"id":1504,"depth":555,"text":1504},{"id":1873,"depth":555,"text":1874,"children":2831},[2832,2833],{"id":2400,"depth":561,"text":2401},{"id":2500,"depth":561,"text":2500},{"id":2586,"depth":555,"text":2586,"children":2835},[2836,2837,2838,2839],{"id":2589,"depth":561,"text":2589},{"id":2645,"depth":561,"text":2645},{"id":2705,"depth":561,"text":2705},{"id":2749,"depth":561,"text":2749},"md",{},"\u002Fcsharp\u002Fwpf\u002F平台调用gdi32实现屏幕捕获等任务",{"description":19},"csharp\u002FWPF\u002F平台调用gdi32实现屏幕捕获等任务","HNQNdSOSqB_bqgakfYSyTpFJ7EyVIrsKWLLUY4UKeEY",1791042466422]