ALT thunk

unit WindowScanner; interface uses System.Classes, System.SysUtils, Winapi.Windows, Winapi.Messages, Vcl.Forms, Vcl.Graphics, System.Types, Winapi.Psapi; type TControlInfo = record Handle: THandle; WinClassName: string; Caption: string; Rect: TRect; ControlType: string; IsEnabled: Boolean; IsVisible: Boolean; end; TWindowInfo = record Handle: THandle; Caption: string; WinClassName: string; Rect: TRect; IsVisible: Boolean; ProcessName: string; Controls: array of TControlInfo; CloseBtnRect: TRect; end; PWindowInfo = ^TWindowInfo; TWindowScanCallback = procedure(const WindowInfo: TWindowInfo) of object; { TWindowScanner } TWindowScanner = class(TObject) private FCallback: TWindowScanCallback; public // 這些方法必須是 Public,以便全域回呼函數可以存取 function GetProcessName(hWnd: HWND): string; function GetControlType(const WinClassName: string): string; function GetCloseButtonRect(hWnd: HWND): TRect; constructor Create(ACallback: TWindowScanCallback); procedure ScanAllWindows; end; implementation // GetTitleBarInfo 所需的常數和記錄 const CCHILD_TITLEBAR_CLOSE = 5; STATE_SYSTEM_INVISIBLE = $8000; STATE_SYSTEM_UNAVAILABLE = $1; type TITLEBARINFO = record cbSize: DWORD; rcTitleBar: TRect; rgstate: array[0..CCHILD_TITLEBAR_CLOSE] of DWORD; end; PTITLEBARINFO = ^TITLEBARINFO; // 聲明 GetTitleBarInfo 函數原型 function GetTitleBarInfo(hwnd: HWND; pti: PTITLEBARINFO): BOOL; stdcall; external 'user32.dll'; // "Thunk" 記錄 type TCallbackThunk = record Scanner: TWindowScanner; Info: PWindowInfo; end; PTCallbackThunk = ^TCallbackThunk; // 全域的回呼函數 function GlobalEnumChildProc(hWnd: HWND; lParam: LPARAM): BOOL; stdcall; var Thunk: PTCallbackThunk; Scanner: TWindowScanner; WindowInfo: PWindowInfo; CtrlInfo: TControlInfo; Caption, WinClassName: string; CtrlRect: TRect; Style: DWORD; Len: Integer; begin Result := True; Thunk := PTCallbackThunk(lParam); if not Assigned(Thunk) then Exit; Scanner := Thunk.Scanner; WindowInfo := Thunk.Info; if not Assigned(Scanner) or not Assigned(WindowInfo) then Exit; ZeroMemory(@CtrlInfo, SizeOf(TControlInfo)); CtrlInfo.Handle := hWnd; SetLength(Caption, 256); Len := GetWindowText(hWnd, PChar(Caption), 256); SetLength(Caption, Len); CtrlInfo.Caption := Caption; SetLength(WinClassName, 256); Len := GetClassName(hWnd, PChar(WinClassName), 256); SetLength(WinClassName, Len); CtrlInfo.WinClassName := WinClassName; CtrlInfo.ControlType := Scanner.GetControlType(CtrlInfo.WinClassName); GetWindowRect(hWnd, CtrlRect); CtrlInfo.Rect := CtrlRect; Style := GetWindowLongPtr(hWnd, GWL_STYLE); CtrlInfo.IsEnabled := (Style and WS_DISABLED) = 0; CtrlInfo.IsVisible := IsWindowVisible(hWnd); SetLength(WindowInfo^.Controls, Length(WindowInfo^.Controls) + 1); WindowInfo^.Controls[High(WindowInfo^.Controls)] := CtrlInfo; end; // 全域的頂層回呼函數 function GlobalEnumWindowsProc(hWnd: HWND; lParam: LPARAM): BOOL; stdcall; var Scanner: TWindowScanner; WindowInfo: TWindowInfo; IsWindowVisible: BOOL; Len: Integer; Thunk: TCallbackThunk; ChildLParam: LPARAM; begin Result := True; Scanner := TWindowScanner(lParam); if not Assigned(Scanner) then Exit; IsWindowVisible := Winapi.Windows.IsWindowVisible(hWnd); if not IsWindowVisible then Exit; ZeroMemory(@WindowInfo, SizeOf(TWindowInfo)); WindowInfo.Handle := hWnd; WindowInfo.IsVisible := IsWindowVisible; SetLength(WindowInfo.Caption, 256); Len := GetWindowText(hWnd, PChar(WindowInfo.Caption), 256); SetLength(WindowInfo.Caption, Len); SetLength(WindowInfo.WinClassName, 256); Len := GetClassName(hWnd, PChar(WindowInfo.WinClassName), 256); SetLength(WindowInfo.WinClassName, Len); GetWindowRect(hWnd, WindowInfo.Rect); WindowInfo.ProcessName := Scanner.GetProcessName(hWnd); WindowInfo.CloseBtnRect := Scanner.GetCloseButtonRect(hWnd); Thunk.Scanner := Scanner; Thunk.Info := @WindowInfo; // 【關鍵修正】 // 1. 先將類型轉換賦值給變數 ChildLParam := LPARAM(@Thunk); // 2. 再將變數傳遞給函數 EnumChildWindows(hWnd, @GlobalEnumChildProc, ChildLParam); if Assigned(Scanner.FCallback) then Scanner.FCallback(WindowInfo); end; { TWindowScanner } constructor TWindowScanner.Create(ACallback: TWindowScanCallback); begin inherited Create; FCallback := ACallback; end; function TWindowScanner.GetProcessName(hWnd: HWND): string; var ProcessId: DWORD; hProcess: THandle; Buffer: array[0..MAX_PATH] of Char; begin Result := ''; GetWindowThreadProcessId(hWnd, ProcessId); if ProcessId = 0 then Exit; hProcess := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, ProcessId); if hProcess <> 0 then try if Winapi.Psapi.GetModuleBaseName(hProcess, 0, Buffer, MAX_PATH) > 0 then Result := Buffer; finally CloseHandle(hProcess); end; end; function TWindowScanner.GetControlType(const WinClassName: string): string; begin Result := '未知控件'; if WinClassName = 'BUTTON' then Result := '按钮' else if WinClassName = 'EDIT' then Result := '输入框' else if WinClassName = 'STATIC' then Result := '静态文本' else if WinClassName = 'LISTBOX' then Result := '列表框' else if WinClassName = 'COMBOBOX' then Result := '下拉框' else if WinClassName = 'CHECKBOX' then Result := '复选框' else if WinClassName = 'RADIOBUTTON' then Result := '单选按钮' else if WinClassName = 'SCROLLBAR' then Result := '滚动条' else if WinClassName = 'DIALOG' then Result := '对话框' else if Pos('MENU', UpperCase(WinClassName)) > 0 then Result := '菜单'; end; function TWindowScanner.GetCloseButtonRect(hWnd: HWND): TRect; var tbInfo: TITLEBARINFO; lRes: LRESULT; x, y: Integer; bFound: Boolean; begin Result := Rect(0, 0, 0, 0); tbInfo.cbSize := SizeOf(TITLEBARINFO); if not GetTitleBarInfo(hWnd, @tbInfo) then Exit; if (tbInfo.rgstate[CCHILD_TITLEBAR_CLOSE] and STATE_SYSTEM_INVISIBLE <> 0) or (tbInfo.rgstate[CCHILD_TITLEBAR_CLOSE] and STATE_SYSTEM_UNAVAILABLE <> 0) then Exit; bFound := False; y := tbInfo.rcTitleBar.Top + (tbInfo.rcTitleBar.Bottom - tbInfo.rcTitleBar.Top) div 2; for x := tbInfo.rcTitleBar.Right - 1 downto tbInfo.rcTitleBar.Left do begin lRes := SendMessage(hWnd, WM_NCHITTEST, 0, MakeLParam(x, y)); if (lRes = HTCLOSE) and not bFound then begin Result.Right := x; bFound := True; end else if (lRes <> HTCLOSE) and bFound then begin Result.Left := x + 1; Break; end; end; if not bFound then Exit; x := Result.Left + (Result.Right - Result.Left) div 2; bFound := False; for y := tbInfo.rcTitleBar.Top to tbInfo.rcTitleBar.Bottom - 1 do begin lRes := SendMessage(hWnd, WM_NCHITTEST, 0, MakeLParam(x, y)); if (lRes = HTCLOSE) and not bFound then begin Result.Top := y; bFound := True; end else if (lRes <> HTCLOSE) and bFound then begin Result.Bottom := y - 1; Break; end; end; if bFound and (Result.Bottom = 0) then Result.Bottom := tbInfo.rcTitleBar.Bottom -1; end; procedure TWindowScanner.ScanAllWindows; begin EnumWindows(@GlobalEnumWindowsProc, LPARAM(Self)); end; end. 代碼如上
10-30
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值