在 Spy++ 中獲取到目標控件的 Control ID (如 0x00002EE5),嘗試用 GetDlgItem(IntPtr.Zero, id) 獲取句柄,返回 0 (失敗)。
GetDlgItem(hParent, nID) 需要 父窗口句柄 hParent,而非 IntPtr.Zero (桌面窗口)。0x00120ABC)。
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr GetDlgItem(IntPtr hDlg, int nIDDlgItem);
// 已知父窗口句柄 (從 Spy++ 獲取或通過 FindWindow 找到)
IntPtr hParent = new IntPtr(0x00120ABC); // 示例值,實際需動態獲取
int controlId = 0x2EE5; // Spy++ 顯示的 Control ID (十六進制)
IntPtr hControl = GetDlgItem(hParent, controlId);
if (hControl != IntPtr.Zero) {
// 成功獲取控件句柄
// 可發送消息、獲取文本等
StringBuilder sb = new StringBuilder(256);
GetWindowText(hControl, sb, sb.Capacity);
Console.WriteLine($"控件文本: {sb}");
} else {
int error = Marshal.GetLastWin32Error();
Console.WriteLine($"獲取失敗, 錯誤碼: {error}");
// 常見錯誤: 1400 (ERROR_INVALID_WINDOW_HANDLE) 父句柄無效
// 1428 (ERROR_CONTROL_ID_NOT_FOUND) ID 在父窗口中不存在
}
不能硬編碼父句柄,需通過窗口類名/標題查找:
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
// 查找主窗口 (如類名 "#32770" 為標準對話框,或具體類名)
IntPtr hMainWnd = FindWindow(null, "目標窗口標題"); // 或按類名
if (hMainWnd == IntPtr.Zero) {
// 嘗試枚舉頂層窗口匹配進程 ID 等
}
// 若控件在嵌套子窗口中,逐層 FindWindowEx
IntPtr hChild1 = FindWindowEx(hMainWnd, IntPtr.Zero, "Button", "確定"); // 類名/標題可為 null
// ... 直到找到直接父窗口 hParent
// 最後 GetDlgItem(hParent, controlId)
Win32 API 繁瑣且脆弱。UI Automation (System.Windows.Automation) 更穩健:
using System.Windows.Automation;
// 根據 AutomationId、Name、ControlType 查找
Condition cond = new AndCondition(
new PropertyCondition(AutomationElement.AutomationIdProperty, "myButton"),
new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button)
);
AutomationElement mainWnd = AutomationElement.RootElement.FindFirst(TreeScope.Children,
new PropertyCondition(AutomationElement.NameProperty, "窗口標題"));
AutomationElement btn = mainWnd.FindFirst(TreeScope.Descendants, cond);
if (btn != null) {
// 獲取原生句柄 (若需互操作)
object hWndObj = btn.GetCurrentPropertyValue(AutomationElement.NativeWindowHandleProperty);
IntPtr hWnd = (IntPtr)hWndObj;
// 或直接調用模式
InvokePattern invoke = btn.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern;
invoke?.Invoke();
}
GetDlgItem 參數 hParent 必須是 直接父窗口句柄,不可為 Zero。FindWindow -> FindWindowEx 鏈式調用 -> GetDlgItem。