透過 Win32 API 設定視窗擴充樣式:
WS_EX_LAYERED (0x80000):啟用分層視窗,支援透明度WS_EX_TRANSPARENT (0x20):啟用滑鼠穿透,點擊事件傳遞給下層視窗SetLayeredWindowAttributes:設定透明度 (Alpha 值 0-255)using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public class ClickThroughForm : Form {
// Win32 API 簽名
private const int GWL_EXSTYLE = -20;
private const int WS_EX_LAYERED = 0x80000;
private const int WS_EX_TRANSPARENT = 0x20;
private const int LWA_ALPHA = 0x2;
[DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", SetLastError = true)]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool SetLayeredWindowAttributes(IntPtr hWnd, int crKey, byte bAlpha, int dwFlags);
public ClickThroughForm() {
// 必須設為無邊框,否則標題列會擋住穿透效果
this.FormBorderStyle = FormBorderStyle.None;
this.BackColor = Color.Black; // 任意顏色,配合 Alpha 顯示
}
///
/// 啟用滑鼠穿透與透明度
///
/// 0=完全透明, 255=不透明
public void EnableClickThrough(byte alpha = 100) {
// 1. 取得目前擴充樣式
int exStyle = GetWindowLong(this.Handle, GWL_EXSTYLE);
// 2. 加入 LAYERED + TRANSPARENT
SetWindowLong(this.Handle, GWL_EXSTYLE, exStyle | WS_EX_LAYERED | WS_EX_TRANSPARENT);
// 3. 設定透明度
SetLayeredWindowAttributes(this.Handle, 0, alpha, LWA_ALPHA);
}
///
/// 還原正常視窗 (取消穿透)
///
public void DisableClickThrough() {
int exStyle = GetWindowLong(this.Handle, GWL_EXSTYLE);
// 移除 LAYERED 與 TRANSPARENT 旗標
SetWindowLong(this.Handle, GWL_EXSTYLE, exStyle & ~WS_EX_LAYERED & ~WS_EX_TRANSPARENT);
this.FormBorderStyle = FormBorderStyle.Sizable; // 或原本的樣式
}
protected override void OnHandleDestroyed(EventArgs e) {
DisableClickThrough(); // 確保資源釋放時還原
base.OnHandleDestroyed(e);
}
}
// 程式進入點
static class Program {
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var form = new ClickThroughForm();
form.Size = new Size(400, 300);
form.StartPosition = FormStartPosition.CenterScreen;
form.EnableClickThrough(128); // 半透明 + 穿透
Application.Run(form);
}
}
| 問題 | 解決 |
|---|---|
| 啟用穿透後無法關閉視窗 | 需保留熱鍵 (如 Esc) 呼叫 DisableClickThrough() 或 Close() |
| WPF 視窗 | 同樣原理,但需在 SourceInitialized 事件中取得 WindowInteropHelper.Handle |
| 多顯示器 DPI 縮放 | 設定 SetProcessDpiAwareness 或在 manifest 標註 DPI Aware |
| ClickOnce 部署 | 需 FullTrust 權限才能呼叫 SetWindowLong |