通過指點操作獲得窗口句柄

通過指點操作獲得窗口句柄

趙砥:
    我用VB的sendkeys編寫了一個向其他程序模擬鍵盤發送字符的工具,因VB編的程序體積太大,
    我想用Delphi重寫,使用SendMessage等API函數,但我想找到一個用鼠標點一下其他進程的
    窗口便可獲得該窗口的線程id和窗口句柄的方法,請指點一下。(使用findwindow獲得窗口
    句柄要輸入窗口標題,不好。)
回答:
    首先需要說明要在Delphi 實現Sendkeys功能,應該使用Journal Playback鉤子(hook)函數,
    而不是使用SendMessage函數。下面我們來介紹如何利用鼠標移動讓用戶選擇窗口,而程序
    進一步得到窗口的句柄。Windows API中有一個函數WindowFromPoint,只要知道鼠標的位置
    (屏幕座標),就可以得到該位置所屬的窗口的句柄,有了句柄,就可以利用其他的函數得到
    更多的信息。如果鼠標在程序的窗口中移動,可以得到MouseMove事件。要想鼠標在窗口外部
    移動時,仍能得到鼠標事件,必須使用SetCapture函數。下面這個例子就是利用這兩個函數
    來實現你所要求的功能。
    
    type
     TForm1 = class(TForm)
     …………
    public
     procedure InvertTracker(hwndDest : Integer);
     end;
     …………
    var
     Form1: TForm1;
     mlngHwndCaptured: Integer;
     hWndLast: Integer;
     …………
    procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
     Y: Integer);
    var pt : TPoint;
    begin
     if GetCapture() <> 0 then // 處於捕捉狀態
     begin
     pt.X := X;
     pt.Y := Y;
     ClientToScreen(pt); // 獲得鼠標的屏幕位置
     // 獲得窗口句柄
     mlngHwndCaptured := WindowFromPoint(pt);
    
     if hWndLast <> mlngHwndCaptured then
     begin
     if hWndLast <> 0 then // 使窗口邊框加粗
     InvertTracker(hWndLast);
     InvertTracker(mlngHwndCaptured);
     hWndLast := mlngHwndCaptured;
     end
     end;
     // 顯示座標和窗口句柄
     Caption := 'X: ' + IntToStr(x) + ', Y: ' + IntToStr(y)
     + ', hWnd: ' + IntToStr(mlngHwndCaptured);
    end;
    
    procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
     Shift: TShiftState; X, Y: Integer);
    begin
     if SetCapture(handle) <> 0 then // 開始捕捉
     Cursor := crUpArrow;
    end;
    
    procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
     Shift: TShiftState; X, Y: Integer);
    var strCaption: PChar;
    begin
     If mlngHwndCaptured <> 0 Then
     begin // 獲得窗口標題
     strCaption := StrAlloc(1000);
     GetWindowText(mlngHwndCaptured, strCaption, 1000);
     Caption := StrPas(strCaption);
     InvalidateRect(0, PRect(0), True);
     mlngHwndCaptured := 0;
     Cursor := crDefault;
     ReleaseCapture;
     StrDispose(strCaption);
     hWndLast := 0;
     end
    end;
    // 使窗口邊框變粗
    procedure TForm1.InvertTracker(hwndDest: Integer);
    var
     hdcDest, hPen, hOldPen, hOldBrush : Integer;
     cxBorder, cxFrame, cyFrame, cxScreen, cyScreen, cr : Integer;
     rc : TRect;
    Const NULL_BRUSH = 5;
    Const R2_NOT = 6;
    Const PS_INSIDEFRAME = 6;
    begin
     cxScreen := GetSystemMetrics(0);
     cyScreen := GetSystemMetrics(1);
     cxBorder := GetSystemMetrics(5);
     cxFrame := GetSystemMetrics(32);
     cyFrame := GetSystemMetrics(33);
     GetWindowRect(hwndDest, rc);
    
     hdcDest := GetWindowDC(hwndDest);
    
     SetROP2(hdcDest, R2_NOT);
     cr := clBlack;
     hPen := CreatePen(PS_INSIDEFRAME, 3 * cxBorder, cr);
    
     hOldPen := SelectObject(hdcDest, hPen);
     hOldBrush := SelectObject(hdcDest, GetStockObject(NULL_BRUSH));
     Rectangle(hdcDest, 0, 0, rc.Right - rc.Left, rc.Bottom - rc.Top);
     SelectObject(hdcDest, hOldBrush);
     SelectObject(hdcDest, hOldPen);
    
     ReleaseDC(hwndDest, hdcDest);
     DeleteObject(hPen);
    end;
    // 將窗口移動到左上角,並減少窗口高度,便於操作
    procedure TForm1.FormCreate(Sender: TObject);
    begin
     Left := 0;
     Top :=0;
     ClientHeight := 76;
    end;
    
    運行該程序時,先在程序窗口內點一下,然後按住鼠標左鍵不放,移動鼠標,這時你會
    看到程序窗口的標題位置不斷顯示鼠標的當前位置(窗口座標)和鼠標所在位置的窗口句柄。
    同時,被選中的窗口邊框加粗,一旦放開左鍵,則程序窗口的標題就改爲所選中窗口的標題。
    相信許多人對這種操作方式都會感到熟悉,因爲象Spy++(Visual C++)、Magic Mouse、
    Capture Professional等很多軟件都是採用類似的操作來選擇窗口的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章