SetWindowRgn + CreatePolygonRgnWindows 允許視窗擁有非矩形區域(Region)。透過 gdi32.dll 的 CreatePolygonRgn 建立多邊形區域,再以 user32.dll 的 SetWindowRgn 套用至視窗控制代碼,即可實現任意形狀視窗。
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace IrregularFormDemo
{
public partial class Form1 : Form
{
[StructLayout(LayoutKind.Sequential)]
private struct POINT { public int X, Y; }
[DllImport("gdi32.dll")]
private static extern IntPtr CreatePolygonRgn(ref POINT lpPoint, int nCount, int nPolyFillMode);
[DllImport("user32.dll")]
private static extern int SetWindowRgn(IntPtr hWnd, IntPtr hRgn, ref bool bRedraw);
public Form1()
{
InitializeComponent();
CreateIrregularShape();
}
private void CreateIrregularShape()
{
POINT[] pts = new POINT[5];
pts[0] = new POINT { X = 90, Y = 90 };
pts[1] = new POINT { X = Width, Y = 0 };
pts[2] = new POINT { X = Width, Y = Height / 2 };
pts[3] = new POINT { X = Width / 2, Y = Height / 2 };
pts[4] = new POINT { X = 0, Y = Width }; // 注意:此處 Y=Width 可能為筆誤,建議改為 Height
bool redraw = true;
IntPtr hRgn = CreatePolygonRgn(ref pts[0], pts.Length, 1); // ALTERNATE 模式
SetWindowRgn(Handle, hRgn, ref redraw);
BackColor = Color.BurlyWood;
}
// 額外:置頂/取消置頂示範
[DllImport("user32.dll")]
private static extern int SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int y, int cx, int cy, int uFlags);
private void btnTopMost_Click(object sender, EventArgs e)
=> SetWindowPos(Handle, -1, 0, 0, 0, 0, 1); // HWND_TOPMOST
private void btnNormal_Click(object sender, EventArgs e)
=> SetWindowPos(Handle, -2, 0, 0, 0, 0, 0); // HWND_NOTOPMOST
}
}
CreatePolygonRgn 最後一個參數:1 = ALTERNATE(交替),2 = WINDING(繞數)。SetWindowRgn 成功後,系統擁有 Region,不可自行 DeleteObject,否則視窗會殘留舊區域。WM_NCHITTEST 回傳 HTTRANSPARENT。若要依據 PNG 透明通道生成 Region,可掃描每一行像素,將不透明區段加入 GraphicsPath,再 new Region(path) 套用至 Form.Region(Managed 方式),無需 P/Invoke。