如何通过用户选择窗口(可以是任何其他应用程序的窗口)通过单击鼠标来将窗口的句柄传递给Delphi。在我的Delphi应用程序中,我可以使用用户单击的按钮来启动此检测过程,以及在Delphi应用程序中显示单击窗口标题的标签。当用户满意时,他选择了正确的窗口,他可以点击我的Delphi应用程序中的按钮(这将是模态的)来停止选择过程,让我的应用程序开始向另一个窗口做它需要做什么...
答案 0 :(得分:5)
评论中概述的用户STATUS_ACCESS_DENIED的方法可能是最简单的方法。我建议使用鼠标捕获而不是挂钩,因为它实现起来有点简单。
以下是对所涉及内容的更详细的概述:
首先要改变选择过程的工作方式。而不是让用户单击您的应用程序上的按钮来启动该过程,然后单击目标窗口,最后再次单击以确认;如果用户单击应用程序上的特定区域,然后将拖动到目标窗口,然后在目标上方放开鼠标按钮,则实现起来要容易得多。这是因为Windows认为点击另一个应用程序属于该应用程序,您必须做额外的工作来拦截它。但是有一种简单的方法 - 称为鼠标捕获 - 来获取有关拖动/释放的信息,如果它只是点击你自己的应用程序。
这也是Windows SDK Spy ++工具使用的方法;所以通过这种方式,你也可以与一个众所周知的工具保持一致。 (间谍++ here图片 - 注意对话框中的十字准线工具 - 这就是你点击并拖动到目标的东西。如果你以前没有这样做,强烈建议下载Windows SDK并使用这个工具;它也是一种非常有用的方式,可以看到其他应用程序如何构建得如Windows API学习工具一样出色。)
涉及的步骤:
请注意,您将在拖动过程中获得鼠标移动事件,并且如果用户恰好将鼠标指针移动到您的控件上,也可能是在去往其他控件的路上。分别告诉这两种情况的最简单方法是在控件中使用一个标记,当你将鼠标按下时设置,当你设置鼠标时清除它,并且只有在设置了该标志时才处理鼠标移动事件。
上面根据您从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 :(得分: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;
我使用此代码检查我的应用程序是否已启动并正在运行。但它可以用于任何已启动的应用程序。
答案 2 :(得分:1)
编辑:它已经消失了,但你曾经能够从delphipages.com下载Eddie Shipman的Delphi Window Spy,它已经变成了一堆无用的linkbait。