我們來詳細學習如何使用?user32.dll
,它是 Windows 系統中負責用戶界面交互的核心 DLL,包含窗口管理、消息處理、鍵盤鼠標輸入等功能。下面從基礎到進階,一步一步教你調用其中的常用函數。
在 C# 中調用?user32.dll
?需要使用?DllImport
?特性,這需要引入?System.Runtime.InteropServices
?命名空間。所有示例都基于這個前提,先創建一個控制臺應用程序(或 Windows 應用程序),并在代碼開頭添加:
using System;
using System.Runtime.InteropServices; // 必須引入,用于DllImport
第一步:調用最基礎的函數 —— 顯示消息框(MessageBox)
MessageBox
?是?user32.dll
?中最常用的函數之一,用于顯示系統風格的彈窗。
步驟 1:聲明函數
首先需要在 C# 中聲明?user32.dll
?中的?MessageBox
?函數,函數定義要和 DLL 中的原生接口一致:
// 聲明 user32.dll 中的 MessageBox 函數
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int MessageBox(IntPtr hWnd, // 父窗口句柄(null表示無父窗口)string lpText, // 彈窗內容string lpCaption, // 彈窗標題uint uType // 彈窗樣式(按鈕、圖標組合)
);
CharSet = CharSet.Unicode:確保中文等字符正常顯示。
返回值 int:表示用戶點擊的按鈕(如 1 = 確定,2 = 取消)。
步驟 2:調用函數
在?Main
?方法中調用聲明好的函數,測試不同樣式的彈窗:
static void Main(string[] args)
{// 示例1:基礎彈窗(只有"確定"按鈕)int result1 = MessageBox(IntPtr.Zero, // 無父窗口"這是一個簡單的消息框", // 內容"基礎示例", // 標題0x00000000 // 樣式:只有"確定"按鈕(0));Console.WriteLine($"用戶點擊了按鈕:{result1}"); // 點擊"確定"會輸出 1// 示例2:帶"確定"和"取消"按鈕 + 警告圖標int result2 = MessageBox(IntPtr.Zero,"是否繼續操作?","確認提示",0x00000003 | 0x00000030 // 0x3=確定+取消;0x30=警告圖標(組合用 |));Console.WriteLine($"用戶點擊了按鈕:{result2}"); // 確定=1,取消=2
}
運行效果
第一個彈窗只有 “確定” 按鈕,點擊后控制臺輸出 1。
第二個彈窗有 “確定”“取消” 按鈕和警告圖標,點擊對應按鈕會輸出 1 或 2。
第二步:獲取屏幕分辨率(GetSystemMetrics)
GetSystemMetrics
?函數可以獲取系統相關的尺寸信息,比如屏幕寬度、高度。
步驟 1:聲明函數
// 聲明獲取系統尺寸的函數
[DllImport("user32.dll")]
public static extern int GetSystemMetrics(int nIndex);
參數 nIndex:指定要獲取的信息(比如 0 = 屏幕寬度,1 = 屏幕高度)。
步驟 2:調用函數
static void Main(string[] args)
{// 獲取屏幕寬度(參數 0 表示 SM_CXSCREEN)int screenWidth = GetSystemMetrics(0);// 獲取屏幕高度(參數 1 表示 SM_CYSCREEN)int screenHeight = GetSystemMetrics(1);Console.WriteLine($"屏幕分辨率:{screenWidth} × {screenHeight}");// 額外示例:獲取任務欄高度(參數 29 表示 SM_CYCAPTION)int taskbarHeight = GetSystemMetrics(29);Console.WriteLine($"任務欄高度:{taskbarHeight} 像素");
}
運行效果
控制臺會輸出你的屏幕分辨率(如?1920 × 1080
)和任務欄高度。
第三步:查找窗口并操作(FindWindow + SetWindowText)
FindWindow:根據窗口標題或類名查找窗口句柄(類似窗口的 “身份證”)。
SetWindowText:修改窗口的標題。
// 查找窗口(根據類名和窗口名)
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);// 修改窗口標題
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern bool SetWindowText(IntPtr hWnd, string lpString);
步驟 2:調用函數(實戰:修改記事本窗口標題)
先手動打開一個記事本(Notepad),標題默認為 “無標題 - 記事本”。
運行以下代碼:
static void Main(string[] args)
{// 查找記事本窗口(類名"Notepad",標題"無標題 - 記事本")IntPtr notepadWnd = FindWindow("Notepad", "無標題 - 記事本");if (notepadWnd != IntPtr.Zero){// 找到窗口后,修改標題bool success = SetWindowText(notepadWnd, "被C#修改過的標題 - 記事本");if (success){Console.WriteLine("記事本標題修改成功!");}else{Console.WriteLine("標題修改失敗");}}else{Console.WriteLine("未找到記事本窗口,請先打開記事本");}
}
運行效果
如果記事本已打開且標題正確,它的標題會被改為 “被 C# 修改過的標題 - 記事本”。
四、移動鼠標:SetCursorPos
?函數
SetCursorPos
?可以直接設置鼠標指針在屏幕上的位置,非常直觀。
步驟 1:聲明函數
using System;
using System.Runtime.InteropServices;class User32Demo
{// 聲明 SetCursorPos 函數:設置鼠標位置[DllImport("user32.dll")]public static extern extern bool SetCursorPos(int X, int Y);// 參數:X(水平坐標)、Y(垂直坐標),返回值:是否成功
}
步驟 2:使用函數移動鼠標
static void Main(string[] args)
{// 1. 移動鼠標到屏幕左上角(0, 0)bool success1 = SetCursorPos(0, 0);Console.WriteLine($"移動到左上角:{ (success1 ? "成功" : "失敗") }");// 等待1秒,讓你看清效果System.Threading.Thread.Sleep(1000);// 2. 移動鼠標到屏幕中心(假設屏幕分辨率是1920×1080)int screenWidth = 1920; // 可通過前面學的 GetSystemMetrics(0) 獲取實際寬度int screenHeight = 1080; // 可通過 GetSystemMetrics(1) 獲取實際高度bool success2 = SetCursorPos(screenWidth / 2, screenHeight / 2);Console.WriteLine($"移動到中心:{ (success2 ? "成功" : "失敗") }");// 等待1秒System.Threading.Thread.Sleep(1000);// 3. 移動鼠標到右下角bool success3 = SetCursorPos(screenWidth - 10, screenHeight - 10);Console.WriteLine($"移動到右下角:{ (success3 ? "成功" : "失敗") }");
}
運行效果
鼠標會依次移動到屏幕左上角 → 中心 → 右下角,每次移動后會在控制臺顯示結果。
五、發送窗口消息:SendMessage
?函數
SendMessage
?是?user32.dll
?中非常強大的函數,它可以向指定窗口發送各種消息(如點擊按鈕、輸入文本、關閉窗口等),實現對窗口的精細控制。
先理解:什么是 “窗口消息”?
Windows 系統中,所有窗口交互都是通過 “消息” 機制實現的。例如:
點擊按鈕 → 窗口收到 WM_LBUTTONDOWN(左鍵按下)消息
鍵盤輸入 → 窗口收到 WM_CHAR(字符輸入)消息
窗口關閉 → 窗口收到 WM_CLOSE 消息
SendMessage 就是手動給窗口發送這些消息,模擬用戶操作。
步驟 1:聲明函數和常用消息常量
class User32Demo
{// 聲明 SendMessage 函數:發送消息到窗口[DllImport("user32.dll", CharSet = CharSet.Unicode)]public static extern IntPtr SendMessage(IntPtr hWnd, // 目標窗口句柄(通過 FindWindow 獲取)uint Msg, // 消息類型(如 WM_CLOSE 表示關閉窗口)IntPtr wParam, // 消息參數1(根據消息類型變化)string lParam // 消息參數2(字符串類型,如輸入的文本));// 常用消息常量(可在微軟文檔中查詢更多)public const uint WM_CLOSE = 0x0002; // 關閉窗口消息public const uint WM_SETTEXT = 0x000C; // 設置窗口文本(如輸入框內容)public const uint WM_LBUTTONDOWN = 0x0201; // 鼠標左鍵按下public const uint WM_LBUTTONUP = 0x0202; // 鼠標左鍵釋放(模擬點擊)
}
步驟 2:實戰 1:關閉指定窗口(發送?WM_CLOSE
?消息)
以關閉記事本為例:
static void Main(string[] args)
{// 1. 先找到記事本窗口(確保已打開,標題為"無標題 - 記事本")IntPtr notepadWnd = FindWindow("Notepad", "無標題 - 記事本");if (notepadWnd == IntPtr.Zero){Console.WriteLine("未找到記事本窗口");return;}// 2. 發送關閉窗口消息(WM_CLOSE)SendMessage(notepadWnd, User32Demo.WM_CLOSE, IntPtr.Zero, null);Console.WriteLine("已發送關閉消息,記事本應該會關閉");
}// 注意:需要先聲明前面學過的 FindWindow 函數
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
運行效果
如果記事本已打開,會收到關閉消息并彈出保存提示(和手動點擊關閉按鈕效果一致)。
步驟 3:實戰 2:向記事本輸入文本(發送?WM_SETTEXT
?消息)
記事本的編輯區域是一個子窗口(類名?"Edit"
),需要先找到它的句柄,再發送輸入消息:
static void Main(string[] args)
{// 1. 找到記事本主窗口IntPtr notepadWnd = FindWindow("Notepad", null); // 忽略標題,找所有記事本if (notepadWnd == IntPtr.Zero){Console.WriteLine("請先打開一個記事本");return;}// 2. 找到記事本的編輯區域子窗口(類名"Edit",無標題)IntPtr editWnd = FindWindowEx(notepadWnd, IntPtr.Zero, "Edit", null);if (editWnd == IntPtr.Zero){Console.WriteLine("未找到編輯區域");return;}// 3. 發送輸入文本消息(WM_SETTEXT)SendMessage(editWnd, User32Demo.WM_SETTEXT, IntPtr.Zero, "這是通過 SendMessage 輸入的文本!");Console.WriteLine("已向記事本輸入文本");
}// 額外聲明 FindWindowEx 函數(用于查找子窗口)
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindowEx(IntPtr hWndParent, // 父窗口句柄IntPtr hWndChildAfter, // 起始子窗口(null表示從第一個開始)string lpClassName, // 子窗口類名string lpWindowName // 子窗口標題
);
運行效果
記事本的編輯區域會自動填入文本 “這是通過 SendMessage 輸入的文本!”。