2011-04-09 60 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

相关问题