Control.DrawToBitmap 僅能產生點陣圖,缺點明顯:檔案大、放大失真、難編輯。Windows Metafile (WMF/EMF) 記錄 GDI 命令序列,重播即可無損重建,適合文檔嵌入、報表輸出、設計編輯。
// 1. 取得螢幕 DC 建立 EMF 檔案
Graphics g1 = control.CreateGraphics();
IntPtr hdc = g1.GetHdc();
Metafile mf = new Metafile(hdc,
new Rectangle(0, 0, control.Width, control.Height),
MetafileFrameUnit.Pixel, EmfType.EmfOnly);
g1.ReleaseHdc(hdc);
g1.Dispose();
// 2. 從 EMF 建立 Graphics 物件
Graphics g2 = Graphics.FromImage(mf);
WinForms 控制項透過 OnPaint 繪製。使用 SendMessage 發送 WM_PRINT 讓控制項及其子控制項繪製到指定 Graphics(即 EMF 表面)。
const int WM_PRINT = 0x0317;
const int PRF_CHILDREN = 0x10, PRF_CLIENT = 0x04,
PRF_ERASEBKGND = 0x08, PRF_NONCLIENT = 0x02;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(HandleRef hWnd, int msg, IntPtr wParam, IntPtr lParam);
public static void DrawControl(Control control, Graphics g) {
if (!control.Created) control.CreateControl();
IntPtr hDc = g.GetHdc();
SendMessage(new HandleRef(control, control.Handle), WM_PRINT, hDc,
(IntPtr)(PRF_CHILDREN | PRF_CLIENT | PRF_ERASEBKGND | PRF_NONCLIENT));
g.ReleaseHdc(hDc);
}
支援直接貼上到 Word、Excel、CorelDRAW 等軟體編輯:
[DllImport("user32.dll")] static extern bool OpenClipboard(IntPtr hWnd);
[DllImport("user32.dll")] static extern bool EmptyClipboard();
[DllImport("user32.dll")] static extern IntPtr SetClipboardData(uint uFormat, IntPtr hMem);
[DllImport("user32.dll")] static extern bool CloseClipboard();
[DllImport("gdi32.dll")] static extern IntPtr CopyEnhMetaFile(IntPtr hemfSrc, IntPtr hNULL);
[DllImport("gdi32.dll")] static extern bool DeleteEnhMetaFile(IntPtr hemf);
public static bool PutEnhMetafileOnClipboard(IntPtr hWnd, Metafile mf) {
IntPtr hEMF = mf.GetHenhmetafile(); // 使 mf 失效
IntPtr hEMF2 = CopyEnhMetaFile(hEMF, IntPtr.Zero);
bool result = false;
if (OpenClipboard(hWnd)) {
if (EmptyClipboard()) {
IntPtr hRes = SetClipboardData(14 /*CF_ENHMETAFILE*/, hEMF2);
result = hRes == hEMF2;
CloseClipboard();
}
}
DeleteEnhMetaFile(hEMF);
return result;
}
此技術適用於報表產生器、UI 文檔自動化、設計工具整合等場景,讓 WinForms 介面無縫融入矢量工作流。