为啥我用delphi编程获取窗口句柄不成功?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为啥我用delphi编程获取窗口句柄不成功?相关的知识,希望对你有一定的参考价值。

非常简单的一段代码,或是却不能正确获取窗口句柄,想请教高手。
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;

type
TForm1 = class(TForm)

private
Private declarations

public
Public declarations
end;

var
Form1: TForm1;
hw:HWND;
Pid:Dword;
h:Thandle;
tt:Cardinal;
ss:string;

implementation

$R *.nfm
begin
hw:=Findwindow('QQ.exe',nil);
if hw = 0 then showmessage('未发现QQ')
else
showmessage('发现QQ');
GetWindowThreadProcessId(hw,Pid);
h := OpenProcess(PROCESS_ALL_ACCESS, false, pid);
if h=0 then exit;
closehandle(h);

end.

end.

这个函数hw:=Findwindow('QQ.exe',nil)我改成hw:=Findwindow('QQ',nil)等,换成其他的窗口也不能成功,请问如何才能正确获取窗口名柄啊!
非常谢谢,但是如果不是想获取QQ句柄,而是想获取其他程序句柄,该如何处理?另外spy++哪有下载的?

我是用VC的,delphi不是很懂,不过API还是一样的,说说我的意见。

Findwindow()的第一个参数是表示类名的字符串,第二个参数是表示窗口标题的字符串,你的第一个参数设置错了,QQ主窗口的类是对话框,应该用"#32770"表示,你可以用Spy++查看的。第二个参数也不对,如果设置成nil,那么任意标题的"#32770"类的窗口都会匹配,而它返回的只是找到的第一个窗口的句柄,不一定是QQ。QQ主窗口的标题是空字符串。

但实际上,你即使用FindWindow("#32770","")找到了相应的句柄,它也不一定是QQ的。因为参数里没有任何QQ特有的信息,而系统中存在大量"#32770"的对话框,它们的标题也各种各样,很可能就有空字符串,而它返回的是找到的第一个窗口的句柄,不能保证一定是QQ。所以这个办法很差。较为可行的方法是枚举系统当前的所有进程,从中查找模块名为"QQ"的进程,从进程中查找属于该进程的窗口,当然也不排除存在其他的名为QQ的进程,但这个可能性应该比较小。

我曾经做过针对QQ的一个插件,这是做的过程中的一些体会。
参考技术A 例子:
function FindQQWindow: THandle;

function GetSpecialButtonHandle(hwnd: HWND; lParam: LPARAM):Boolean; stdcall;
var
cName: array[0..128] of Char;
wName: array[0..128] of Char;
begin
result := true;
GetClassName(hwnd, cName, 128);
if StrPas(cName) = 'Button' then
begin
GetWindowText(hwnd, wName, 128);
if StrPas(wName) = '软键盘'then
begin
FQQVersion := 'V2004Beta';
PInteger(lParam)^ := hwnd;
result := false;
end;
if StrPas(wName) = '注册向导' then
begin
FQQVersion := 'V2003';
PInteger(lParam)^ := hwnd;
result := false;
end;
end;
end;

function EnumWindowsProc(hwnd: HWND; lParam: LPARAM): boolean; stdcall;
var
eName: array[0..180] of Char;
begin
Result := true;
if hwnd = 0 then Exit;
GetClassName(hwnd, eName, 32);

If CompareText('#32770', StrPas(eName))<>0 Then Exit;

EnumChildWindows(hwnd, @GetSpecialButtonHandle, Integer(@HSpecialHandle));
if HSpecialHandle <> 0 then
Begin
QQHandle:= hwnd;
Result := False;
End;
end;
begin
QQHandle:= 0;
EnumWindows(@EnumWindowsProc, 0);
Result:= QQHandle;
end;

-------------------------------------------------------------------------------
说明: 取得QQ窗口的各个编辑框以及登陆按钮的句柄
-------------------------------------------------------------------------------
procedure GetQQHandle;
Var
eHandle: THandle;
begin
eHandle:= FindQQWindow;
if eHandle<>0 then
begin
HPasswordEdit:= FindWindowEx(eHandle, 0, 'Edit', nil);
HNumberEdit:= FindWindowEx(eHandle, 0, 'Combobox', nil);
HLoginButton:= FindWindowEx(eHandle, 0, 'Button', '登录');
end;
end;

-------------------------------------------------------------------------------
说明: 启动QQ后,计时器开始检测QQ窗口的存在,
检测到了,发送用户名密码到指定编辑框再模拟点击QQ登陆按钮完成登陆
-------------------------------------------------------------------------------
procedure TQQLogin.FTimerTimer(Sender: TObject);
var
i: integer;
begin
GetQQHandle;

If (HNumberEdit=0) or (HPasswordEdit=0) or (HLoginButton=0) Then Exit;

SendMessage(HNumberEdit, WM_SETTEXT, 0, Integer(FUserId));

if FQQVersion = 'V2004Beta' then
begin
For I:= 1 To Length(FPassword) Do
SendMessage(HPasswordEdit, WM_USER+513, Integer(FPassword[I]), 0);
end
else
begin
For I:= 1 To Length(FPassword) Do
begin
SendMessage(HPasswordEdit, WM_CHAR, Integer(FPassword[I]), 0);
end;
end;

SendMessage(HLoginButton, WM_LBUTTONDOWN, 0, 0);
SendMessage(HLoginButton, WM_LBUTTONUP, 0, 0);

FTimer.Enabled := False;
Free;
end;

vb如何获取到窗口的句柄

如果我用getwindow找到窗口的hdc属性,但是我想要它的hwnd,怎么办呢?
求教。。

参考技术A 获取句柄不一定要用 FindWindow ,还可以枚举:

Private Declare Function GetWindow Lib "user32" (ByVal hwnd As Long, ByVal wCmd As Long) As Long
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long

Private Const GW_HWNDFIRST = 0
Private Const GW_HWNDNEXT = 2

Private Sub Command1_Click()
Dim lngHwnd As Long, ret As Long
Dim s As String * 255
Dim sName As String

lngHwnd = GetWindow(Me.hwnd, GW_HWNDFIRST)
Do While lngHwnd
ret = GetWindowText(lngHwnd, s, 255)
sName = Blank(s)
If InStr(sName, "记事本") <> 0 Then '这里“记事本”替换成程序标题相同的部分
'这里写 将句柄加入数组的相关代码
End If
lngHwnd = GetWindow(lngHwnd, GW_HWNDNEXT)
Loop
End Sub

Public Function Blank(ByVal szString As String) As String
Dim l As Integer

l = InStr(szString, Chr(0))
If l > 0 Then
Blank = Left(szString, l - 1)
Else
Blank = szString
End If
End Function
参考技术B GetWindow怎么会找到hdc呢?他的返回值就是hwnd啊。
============
话说回来,如果你已知一个hdc想要找他的hwnd,用WindowFromDC函数。本回答被提问者采纳

以上是关于为啥我用delphi编程获取窗口句柄不成功?的主要内容,如果未能解决你的问题,请参考以下文章

DELPHI 通過窗口句柄或窗口标题得到进程句柄

delphi 知道路径和进程如何获取窗口句柄?

delphi中如何编程获取其它程序窗口的大小?

Delphi取所有窗口句柄

delphi 获取自身句柄

C++中如何获取当前窗口句柄?