2011-04-09 62 views
1

如何通過點擊窗口(點擊窗口)來選擇窗口(可以是任何其他應用程序的窗口),將窗口的句柄傳遞給Delphi鼠標就可以了。在我的Delphi應用程序中,我可以有一個用戶點擊的按鈕,啓動這個檢測過程,以及一個標籤,顯示在Delphi應用程序中點擊窗口標題。當用戶滿意時,他選擇了正確的窗口,他可以點擊我的Delphi應用程序中的按鈕(這將是模式),以停止選擇過程,讓我的應用程序開始做另一個窗口它需要做什麼...如何通過鼠標點擊將另一個應用程序的窗口句柄傳遞給Delphi

+1

鼠標捕獲或窗口掛鉤,既會工作。取決於你想要它的方式。當鼠標按鈕被按下時(例如在窗口上的按鈕上),開始捕捉過程,然後在釋放按鈕時結束鼠標捕捉。在你的應用程序之間會收到有關鼠標位置的信息,所以一個足以找出你懸停的窗口。 – 0xC0000022L 2011-04-09 23:12:21

+0

感謝您的回覆,我是delphi的新手,對winapi非常非常非常新,所以如果您能夠詳細闡述一下代碼示例,我會非常感激。 – georgelappies 2011-04-09 23:52:55

+0

-1,@George - 你已經接受了一個不回答問題的答案,而不是其他答案。這表明你想實現的目標與你提出的問題沒有多大關係。 – 2011-04-10 13:02:21

回答

4

如果你知道是在窗口的標題是什麼文字,這段代碼就可以了你:

var 
    WindowList: TList; 

function GetHandle (windowtitle: string): HWND; 
var 
    h, TopWindow: HWND; 
    Dest: array[0..80] of char; 
    i: integer; 
    s: string; 

    function getWindows(Handle: HWND; Info: Pointer): BOOL; stdcall; 
    begin 
     Result:= True; 
     WindowList.Add(Pointer(Handle)); 
    end; 

begin 
    result:= 0; 

    try 
    WindowList:= TList.Create; 
    TopWindow:= Application.Handle; 
    EnumWindows(@getWindows, Longint(@TopWindow)); 
    i:= 0; 
    while (i < WindowList.Count) and (result = 0) do 
     begin 
     GetWindowText(HWND(WindowList[i]), Dest, sizeof(Dest) - 1); 
     s:= dest; 
     if length(s) > 0 then 
      begin 
      if (Pos(UpperCase(Windowtitle), UpperCase(s)) >= 1) then 
       begin 
       h:= HWND(WindowList[i]); 
       if IsWindow(h) then 
        result:= h 
      end 
      end; 
     inc(i) 
     end 
    finally 
     WindowList.Free; 
    end; 
end; 

使用在你的榜樣(記事本把在窗口標題打開的文件的名稱):

h:= getHandle('text.txt'); 
if (h = 0) 
    // Oops not found 
else 
    begin 
    // you got the handle! 
    end; 

我用這段代碼來檢查我的應用程序是否是alrea加入並運行。但它可以用於任何啓動的應用程序。

+0

謝謝,我現在可以通過讓用戶通過使用ShellExecute procudre在我的應用程序中打開文件來使用它嗎?我會通過掃描標題來獲得處理? – georgelappies 2011-04-10 08:34:31

+0

是的,這是主意。 – ToonVo 2011-04-10 11:11:10

1

編輯:它不見了,但你曾經可以通過delphipages.com的Eddie Shipman下載Delphi Window Spy,它已經變成了一堆無用的linkbait。

+0

那裏沒有下載鏈接! – Joe 2014-08-04 14:56:13

+0

鏈接腐爛,它現在消失了。我無法在互聯網上的任何地方找到它。 – 2014-08-07 14:45:12

+0

謝謝:(但任何猜測在這個http://stackoverflow.com/questions/25189447/getting-the-components-on-a--delphi-form-from-a-windows-handle – Joe 2014-08-07 18:21:24

5

評論中概述的用戶STATUS_ACCESS_DENIED可能是最簡單的方法。我建議使用鼠標捕捉來掛鉤,因爲它實現起來更簡單。

這裏是什麼是參與一個稍微詳細的大綱:

首先要改變這種選擇過程的工作方式。而不是讓用戶單擊應用程序上的按鈕來啓動該過程,然後單擊目標窗口,最後再次單擊以確認;如果用戶單擊應用程序上的特定區域,然後將拖動到目標窗口,然後在目標上放開鼠標按鈕,實現起來會更容易。這是因爲窗戶認爲點擊另一個應用程序屬於該應用程序,並且您必須做額外的工作才能截取它。但是,有一種簡單的方法 - 稱爲鼠標捕獲 - 以獲取有關拖動/釋放的信息,如果它以您自己的應用程序上的點擊開始。

這也是Windows SDK Spy ++工具使用的方法;所以通過這樣做,你也可以與一個着名的工具保持一致。 (Pic of Spy ++ here - 注意對話框中的十字線查找工具 - 這就是你點擊並拖動到目標的地方。如果你以前沒有這樣做,強烈建議下載Windows SDK並使用這個工具;這也是一個非常棒的看到如何其他應用程序的有效方式是這樣構造的大作爲Windows API的學習工具)

涉及的步驟:

  • 有一定的控制在你的應用程序,響應鼠標按下事件(在Win32中WM_LBUTTONDOWN/C,OnMouseDown在delphi中)。您可能需要在此處繪製十字線圖標或類似圖標,以便用戶知道點擊的位置。
  • 當您將鼠標放下時,使用SetCapture'捕捉'鼠標。這意味着控件將在鼠標移動時接收所有鼠標消息 - 直到用戶釋放按鈕 - 即使它移出控件。
  • 設置的圖標看起來像一個十字線,使用戶知道他們在拖曳模式
  • 當用戶移動鼠標時,你會得到WM_MOUSEMOVE消息(的OnMouseMove在Delphi)具有指針座標。您需要使用ClientToScreen將它們轉換爲屏幕座標,然後使用WindowFromPoint在該點查找窗口。 (請注意,此時可以找到最內層的窗口,如果需要,可以使用從桌面窗口開始的ChildWindowFromPoint來獲取頂層窗口。)由您決定是否要每隔一段時間更新一次UI鼠標在整個拖動中移動,或者在用戶釋放鼠標按鈕時移動。
  • 當用戶釋放鼠標按鈕時,您將得到一個WM_LBUTTONUP/OnMouseUp;在那個階段,通過調用ReleaseCapture並將光標恢復到正常形狀來包裝。

請注意,您將在拖動過程中獲得鼠標移動事件,並且如果用戶恰好將鼠標指針移動到您的控件上,可能正在前往某個其他控件的路上。將這兩種情況區分開來的最簡單方法是在控件中使用一個標誌,當您將鼠標放下時您將設置一個標誌,並且在您將鼠標移開時清除,並且只有在設置該標誌時才處理鼠標移動事件。

以上描述了您將從C/C++調用的純Win32 API的過程;但它看起來像Delphi提供了對大多數或全部的直接支持。

編輯:可能Delphi實現:

type 
    TForm1 = class(TForm) 
    Label1: TLabel; 
    procedure FormMouseDown(Sender: TObject; Button: TMouseButton; 
     Shift: TShiftState; X, Y: Integer); 
    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); 
    procedure FormPaint(Sender: TObject); 
    procedure FormMouseUp(Sender: TObject; Button: TMouseButton; 
     Shift: TShiftState; X, Y: Integer); 
    private 
    FCacheWnd: HWND; 
    FCaptured: Boolean; 
    public 
    end; 

var 
    Form1: TForm1; 

implementation 

{$R *.dfm} 

const // the first item, the place where the crosshair is 
    ClickRect: TRect = (Left: 10; Top: 10; Right: 44; Bottom: 44); 

procedure TForm1.FormPaint(Sender: TObject); 
begin 
    // draw the control and the crosshair if no capturing 
    if GetCapture <> Handle then begin 
    DrawFrameControl(Canvas.Handle, ClickRect, 0, DFCS_BUTTONPUSH); 
    DrawIcon(Canvas.Handle, ClickRect.Left, ClickRect.Top, 
       Screen.Cursors[crCross]); 
    end; 
end; 

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; 
    Shift: TShiftState; X, Y: Integer); 
begin 
    if (Button = mbLeft) and (Shift = [ssLeft]) 
     and PtInRect(ClickRect, Point(X, Y)) then begin 
    // the second item, draw the control pressed, 
    // set the flag and the capture. FCacheWnd is used not to get 
    // window information for every mouse move - if the window under the 
    // mouse is not changed. 
    DrawFrameControl(Canvas.Handle, ClickRect, 0, DFCS_PUSHED); 
    FCacheWnd := 0; 
    FCaptured := True; 
    SetCapture(Handle); 
    Screen.Cursor := crCross; // the third item, set the cursor to crosshair. 
    end; 
end; 

function GetWndFromClientPoint(ClientWnd: HWND; Pt: TPoint): HWND; 
begin 
    MapWindowPoints(ClientWnd, GetDesktopWindow, Pt, 1); 
    Result := WindowFromPoint(Pt); 
end; 

function GetWndInfo(Wnd: HWND): string; 
var 
    ClassName: array [0..256] of Char; 
begin 
    Result := ''; 
    if IsWindow(Wnd) then begin 
    GetClassName(Wnd, ClassName, 256); 
    Result := Format('Window: %x [%s]', [Wnd, ClassName]); 
    if (GetWindowLong(Wnd, GWL_STYLE) and WS_CHILD) = WS_CHILD then begin 
     Wnd := GetAncestor(Wnd, GA_ROOT); 
     GetClassName(Wnd, ClassName, 256); 
     Result := Format(Result + sLineBreak + 'Top level: %x [%s]', [Wnd, ClassName]); 
    end; 
    end; 
end; 

procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X, 
    Y: Integer); 
var 
    Wnd: HWND; 
begin 
    if FCaptured then begin 
    // fourth item, convert coordinates and find the window under the cursor 
    Wnd := GetWndFromClientPoint(Handle, Point(X, Y)); 
    if Wnd <> FCacheWnd then 
     Label1.Caption := GetWndInfo(Wnd); 
    FCacheWnd := Wnd; 
    end; 
end; 

procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton; 
    Shift: TShiftState; X, Y: Integer); 
begin 
    if FCaptured then begin 
    // fifth item 
    FCaptured := False; 
    ReleaseCapture; 
    InvalidateRect(Handle, @ClickRect, False); // invalidate pressed look 
    Screen.Cursor := crDefault; 
    end; 
end; 
+1

我已經編輯了你的答案,包括一個樣本,因爲OP說他是Delphi的新手,在他對這個問題的評論中。你.. – 2011-04-10 04:32:16

+0

@塞爾塔克 - 感謝編輯! – BrendanMcK 2011-04-10 04:38:40

+0

非常感謝你,我非常感謝你的努力和巨大的幫助。 – georgelappies 2011-04-10 08:17:45

相關問題