截取qq2005消息问题,请帮忙看看(附源码) ( 积分: 100 )

  • 主题发起人 主题发起人 lhandyl
  • 开始时间 开始时间
L

lhandyl

Unregistered / Unconfirmed
GUEST, unregistred user!
这段程序能够找到QQ聊天窗口的句柄,但是却找不到文本框的句柄,是不是qq2005的消息框又改了?

function GetWndText(hWnd: HWND): String;
Var
Ret:LongInt;
mText:PChar;
Buf:Integer;
begin
Ret:=SendMessage(hWnd,WM_GETTEXTLENGTH,0,0)+1;
GetMem(mText,Ret);
try
Buf:=LongInt(mText);
SendMessage(hWnd,WM_GETTEXT,Ret,Buf);
Result:=StrPas(mText);
finally
FreeMem(mText,Ret);
end;
end;

function GetQQWnd: HWND;
var
hCurrentWindow: HWnd;
WndText:String;
begin
hCurrentWindow := GetWindow(Application.Handle, GW_HWNDFIRST);
while hCurrentWindow <> 0 do
begin
WndText:=GetWndText(hCurrentWindow);
if (Pos('聊天中',WndText)>0) or (Pos('发送消息',WndText)>0) then
begin
Result:=hCurrentWindow;
Exit;
end;
hCurrentWindow := GetWindow(hCurrentWindow, GW_HWNDNEXT);
end;
Result:=0;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
qqWnd,txtWnd,btnWnd:HWND;
Msg:String;
begin
qqWnd:=GetQQWnd;
if qqWnd=0 then
begin
memo1.Lines.Add('没有找到窗口!');
Exit;
end;
txtWnd:=Findhwd(qqWnd);
if (txtWnd=0) then
begin
memo1.Lines.Add('没有找到文本框!');
Exit;
end;
Msg:=GetWndText(txtWnd);
memo1.Lines.Add(Msg);
end;
 
这段程序能够找到QQ聊天窗口的句柄,但是却找不到文本框的句柄,是不是qq2005的消息框又改了?

function GetWndText(hWnd: HWND): String;
Var
Ret:LongInt;
mText:PChar;
Buf:Integer;
begin
Ret:=SendMessage(hWnd,WM_GETTEXTLENGTH,0,0)+1;
GetMem(mText,Ret);
try
Buf:=LongInt(mText);
SendMessage(hWnd,WM_GETTEXT,Ret,Buf);
Result:=StrPas(mText);
finally
FreeMem(mText,Ret);
end;
end;

function GetQQWnd: HWND;
var
hCurrentWindow: HWnd;
WndText:String;
begin
hCurrentWindow := GetWindow(Application.Handle, GW_HWNDFIRST);
while hCurrentWindow <> 0 do
begin
WndText:=GetWndText(hCurrentWindow);
if (Pos('聊天中',WndText)>0) or (Pos('发送消息',WndText)>0) then
begin
Result:=hCurrentWindow;
Exit;
end;
hCurrentWindow := GetWindow(hCurrentWindow, GW_HWNDNEXT);
end;
Result:=0;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
qqWnd,txtWnd,btnWnd:HWND;
Msg:String;
begin
qqWnd:=GetQQWnd;
if qqWnd=0 then
begin
memo1.Lines.Add('没有找到窗口!');
Exit;
end;
txtWnd:=Findhwd(qqWnd);
if (txtWnd=0) then
begin
memo1.Lines.Add('没有找到文本框!');
Exit;
end;
Msg:=GetWndText(txtWnd);
memo1.Lines.Add(Msg);
end;
 
自己用SPY++分析一下QQ的聊天窗口就清楚了:
-----#32770—“与 xxxx 交谈中” ---------&amp;#61664;聊天窗体,即GetForegroundWindow
|----#32770 ------&amp;#61664;这个就是代码中的mainhwnd
|----RichEdit20A ------&amp;#61664;显示消息的窗体
|----AfxWnd42 -------&amp;#61664;这个是第一个texthwnd
| |----RICHEDIT ------&amp;#61664;我们要找的输入框了即texthwnd


自己写的QQ尾巴的部分代码,楼主看看吧

uses
Windows,SysUtils,Messages,Registry,ShlObj,Types,Classes;
const
LLKHF_ALTDOWN =KF_ALTDOWN shr 8;
WH_KEYBOARD_LL=13; //钩子种类,表示是低级键盘钩子

type
PKBDLLHOOKSTRUCT=^KBDLLHOOKSTRUCT;
{这个结构包含了一个低级键盘钩子的输入事件,
可以捕获键盘输入,具体查看MSDN}
KBDLLHOOKSTRUCT=record
vkCode:DWORD; //虚拟键码
scanCode:DWORD; //扫描码
flags:DWORD; //标志
time:DWORD;
dwExtraInfo:DWORD; //一些附加信息
end;

//------------------发送消息的过程-------------------//
Procedure SendText;
var
mainhwnd:THandle; //聊天主窗体句柄
texhwnd:THandle; //输入框句柄
begin
mainhwnd:=0;
//查找当前的工作状态的窗体,#32770是窗口类
mainhwnd:=FindWindowEx(GetForegroundWindow,mainhwnd,'#32770',nil);
if mainhwnd<>0 then
begin
//查找输入框的句柄
texhwnd:=FindWindowEx(mainhwnd,0,'AfxWnd42',nil);
texhwnd:=FindWindowEx(texhwnd,0,'RICHEDIT',nil);
//如果输入框里没有消息就取消发送
if SendMessage(texhwnd,WM_GETTEXTLENGTH,0,0)<1 then exit;
//取消输入框中文本的选中
SendMessage(texhwnd,EM_SetSel,-1,-1);
//向输入框中加入尾巴
SendMessage(texhwnd,EM_ReplaceSel,1,integer(pchar(' '+'QQ尾巴 by Sirius!')));
end;
end;//----------------------------end.

//-------------------钩子的回调函数----------------//
function KeyHookFunc(nCode:Integer;w_Param:WPARAM;l_Param:LPARAM):LRESULT;stdcall;
const VK_S=83; //Alt+S中的S的虚拟键码,在虚拟键码表上可以查看
var
bGetMsg:Boolean; //判断是否截获指定的消息
pk:PKBDLLHOOKSTRUCT; //键盘钩子的结构体
begin
bGetMsg:=False;
if nCode=HC_ACTION then
begin
case w_Param of //要截获的消息标识符,包括KeyDown和KeyUp
WM_KEYDOWN, {MSDN中有详细说明}
WM_SYSKEYDOWN,
WM_KEYUP,
WM_SYSKEYUP:
begin
//将消息包含的数据装入pk
pk:=PKBDLLHOOKSTRUCT(l_Param);
// 进行按键过滤
bGetMsg :=(((pk^.vkCode = VK_S) and
((pk^.flags and LLKHF_ALTDOWN) <> 0)) or
//上面截获的是Alt+S
((pk^.vkCode = VK_RETURN) and
((GetKeyState(VK_CONTROL) and $8000) <> 0)));
//上面截获的是Ctrl+Enter
end;
end;
end;
if bGetMsg then
begin
SendText; //截获消息后向输入框里加上尾巴
Result:=0; //将消息返回,尾巴就和别人输入的数据一起发送出去了
end
//如果没有截获指定消息就将向下传递
else Result:=CallNextHookEx(0,nCode,w_Param,l_Param);
end;//----------------------------end.

//-------------------------下钩子
KeyHook:=SetWindowsHookEx(WH_KEYBOARD_LL,
@KeyHookFunc,
HInstance,0);
 
谢谢!
你的分先记下了,还有一个问题希望也能帮帮忙。
如何在 “与 xxxx 聊天中” 窗口关闭前,执行我的一个过程;
既怎么样拦截wm_close?
给点例子看看!谢谢
 
这个倒是没有做过,帮你想想看吧
 
呵呵,基本搞定了,用WH_CBT钩子可以,大体上可以了,可能还有点小问题

这个是Dll的代码:
library MsgHook;

uses
Windows,SysUtils,Messages;
var
HookHandle:HHook;
FrmHandle:THandle;

Function MsgHookProc(nCode:integer;WPARAM:wParam;LPARAM:lParam):LRESULT;Stdcall;
begin
if nCode=HCBT_DESTROYWND then
begin
//这个就是QQ聊天窗体的句柄
FrmHandle:=FindWindowEx(GetForegroundWindow,0,'#32770',nil);
if wParam=FrmHandle then
begin
Messagebox(0,'捕获到关闭消息!','',MB_OK);
Result:=0; //改为1则不会关闭
end
else Result:=CallNextHookEx(HookHandle,nCode,WParam,LParam);
end
else Result:=CallNextHookEx(HookHandle,nCode,WParam,LParam);
end;

Function InstallHook:boolean;stdcall;export;
begin
Result:=True;
if HookHandle=0 then
SetWindowsHookEx(WH_CBT,@MsgHookProc,HInstance,0)
else Result:=False;
end;

Function UnInStallHook:boolean;stdcall;export;
begin
Result:=True;
if HookHandle<>0 then
begin
UnHookWindowsHookEx(HookHandle);
HookHandle:= 0;
end
else Result:=False;
end;

exports
InstallHook,
UnInStallHook;

begin
end.

这个是主窗体的代码:
unit Main;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
Const MBOK=[MBOK];
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation
function UnInStallHook:Boolean;stdcall;external 'MsgHook.dll';
function InstallHook:Boolean;stdcall;external 'MsgHook.dll';
{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
if InstallHook then
MessageDlg('钩子安装成功!',mtInformation,MBOK,0)
else MessageDlg('请先撤销钩子再尝试!',mtWarning,MBOK,0);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
if UnInStallHook then
MessageDlg('钩子撤销成功!',mtInformation,MBOK,0)
else MessageDlg('还没有安装钩子!',mtWarning,MBOK,0);
end;

end.
 
太谢谢了。是有点小问题,但是自己已经搞定了。
希望能跟你多请教。如果方便的话,请留个MAIL或者其他。
 
接受答案了.
 
不好意思,新问题又出来了,现在可以捕获到关闭消息,但是在关闭之间我想把窗口里的文本保存下来,结果什么都没有保存。
再帮我看看。
谢谢,分另外再加100。

library MsgHook;

{ Important note about DLL memory management: ShareMem must be the
first unit in your library's USES clause AND your project's (select
Project-View Source) USES clause if your DLL exports any procedures or
functions that pass strings as parameters or function results. This
applies to all strings passed to and from your DLL--even those that
are nested in records and classes. ShareMem is the interface unit to
the BORLNDMM.DLL shared memory manager, which must be deployed along
with your DLL. To avoid using BORLNDMM.DLL, pass string information
using PChar or ShortString parameters. }
uses
Windows,SysUtils,Messages,Classes;
var
HookHandle:HHook;
FrmHandle:integer;

function GetWndText(hWnd: HWND): String;
Var
Ret:LongInt;
mText:PChar;
Buf:Integer;
begin
Ret:=SendMessage(hWnd,WM_GETTEXTLENGTH,0,0)+1;
GetMem(mText,Ret);
try
Buf:=LongInt(mText);
SendMessage(hWnd,WM_GETTEXT,Ret,Buf);
Result:=StrPas(mText);
finally
FreeMem(mText,Ret);
end;
end;

Procedure SendText;
var
mainhwnd:THandle; //聊天主窗体句柄
texhwnd:THandle; //输入框句柄
ss:TStringList;
begin
mainhwnd:=0;
//查找当前的工作状态的窗体,#32770是窗口类
mainhwnd:=FindWindowEx(GetForegroundWindow,mainhwnd,'#32770',nil);
if mainhwnd<>0 then
begin
texhwnd:=FindWindowEx(mainhwnd,0,'RICHEDIT20A',nil);
if texhwnd=0 then exit;
ss:=TStringList.Create;
ss.Text:=GetWndText(Texhwnd);
ss.SaveToFile('c:/'+Formatdatetime('YYYYMMDDHHNNSS',now)+'.txt');
end;
end;

function KeyHookFunc(nCode:Integer;w_Param:WPARAM;l_Param:LPARAM):LRESULT;stdcall;
const VK_S=83; //Alt+S中的S的虚拟键码,在虚拟键码表上可以查看
var
bGetMsg:Boolean; //判断是否截获指定的消息
pk:PKBDLLHOOKSTRUCT; //键盘钩子的结构体
begin
bGetMsg:=False;
if nCode=HC_ACTION then
begin
case w_Param of //要截获的消息标识符,包括KeyDown和KeyUp
WM_KEYDOWN, {MSDN中有详细说明}
WM_SYSKEYDOWN,
WM_KEYUP,
WM_SYSKEYUP:
begin
//将消息包含的数据装入pk
pk:=PKBDLLHOOKSTRUCT(l_Param);
// 进行按键过滤
bGetMsg :=(((pk^.vkCode = VK_S) and
((pk^.flags and LLKHF_ALTDOWN) <> 0)) or
//上面截获的是Alt+S
((pk^.vkCode = VK_RETURN) and
((GetKeyState(VK_CONTROL) and $8000) <> 0)));
//上面截获的是Ctrl+Enter
end;
end;
end;
if bGetMsg then
begin
SendText; //截获消息后向输入框里加上尾巴
Result:=0; //将消息返回,尾巴就和别人输入的数据一起发送出去了
end
//如果没有截获指定消息就将向下传递
else Result:=CallNextHookEx(0,nCode,w_Param,l_Param);
end;//----------------------------end.



Function MsgHookProc(nCode:integer;WPARAM:wParam;LPARAM:lParam):LRESULT;Stdcall;
begin
if nCode=HCBT_DESTROYWND then
begin
//这个就是QQ聊天窗体的句柄
FrmHandle:=FindWindowEx(GetForegroundWindow,0,'#32770',nil);
if wParam=FrmHandle then
begin
SendText;
Messagebox(0,'捕获到关闭消息!','',MB_OK);
Result:=0; //改为1则不会关闭
end
else Result:=CallNextHookEx(HookHandle,nCode,WParam,LParam);
end
else Result:=CallNextHookEx(HookHandle,nCode,WParam,LParam);
end;

Function InstallHook:boolean;stdcall;export;
begin
Result:=True;
if HookHandle=0 then
SetWindowsHookEx(WH_CBT,@MsgHookProc,HInstance,0)
else Result:=False;
end;

Function UnInStallHook:boolean;stdcall;export;
begin
Result:=True;
if HookHandle<>0 then
begin
UnHookWindowsHookEx(HookHandle);
HookHandle:= 0;
end
else Result:=False;
end;

exports
InstallHook,
UnInStallHook;

begin
end.


代码全贴出来了,文本文档打开之后里面都是空的。哪里有问题?
 
//不好意思,重新发一遍代码
library MsgHook;
uses
Windows,SysUtils,Messages,Classes;
var
HookHandle:HHook;
FrmHandle:integer;

function GetWndText(hWnd: HWND): String;
Var
Ret:LongInt;
mText:PChar;
Buf:Integer;
begin
Ret:=SendMessage(hWnd,WM_GETTEXTLENGTH,0,0)+1;
GetMem(mText,Ret);
try
Buf:=LongInt(mText);
SendMessage(hWnd,WM_GETTEXT,Ret,Buf);
Result:=StrPas(mText);
finally
FreeMem(mText,Ret);
end;
end;

Procedure SendText;
var
mainhwnd:THandle; //聊天主窗体句柄
texhwnd:THandle; //输入框句柄
ss:TStringList;
begin
mainhwnd:=0;
//查找当前的工作状态的窗体,#32770是窗口类
mainhwnd:=FindWindowEx(GetForegroundWindow,mainhwnd,'#32770',nil);
if mainhwnd<>0 then
begin
texhwnd:=FindWindowEx(mainhwnd,0,'RICHEDIT20A',nil);
if texhwnd=0 then exit;
ss:=TStringList.Create;
ss.Text:=GetWndText(Texhwnd);
ss.SaveToFile('c:/'+Formatdatetime('YYYYMMDDHHNNSS',now)+'.txt');
end;
end;

Function MsgHookProc(nCode:integer;WPARAM:wParam;LPARAM:lParam):LRESULT;Stdcall;
begin
if nCode=HCBT_DESTROYWND then
begin
//这个就是QQ聊天窗体的句柄
FrmHandle:=FindWindowEx(GetForegroundWindow,0,'#32770',nil);
if wParam=FrmHandle then
begin
SendText;
Messagebox(0,'捕获到关闭消息!','',MB_OK);
Result:=0; //改为1则不会关闭
end
else Result:=CallNextHookEx(HookHandle,nCode,WParam,LParam);
end
else Result:=CallNextHookEx(HookHandle,nCode,WParam,LParam);
end;

Function InstallHook:boolean;stdcall;export;
begin
Result:=True;
if HookHandle=0 then
SetWindowsHookEx(WH_CBT,@MsgHookProc,HInstance,0)
else Result:=False;
end;

Function UnInStallHook:boolean;stdcall;export;
begin
Result:=True;
if HookHandle<>0 then
begin
UnHookWindowsHookEx(HookHandle);
HookHandle:= 0;
end
else Result:=False;
end;

exports
InstallHook,
UnInStallHook;

begin
end.
 
我的想法是在窗口关闭之前把窗口里的文本保存下来。
 
帮你试试看

我的QQ:53297714,共同进步
 
mysirius:
前面的问题已经解决。
这个我会另外开贴给分。谢谢!
 
mysirius怎么不来了?
 
不好意思,这两天回学校有点事,有进展会尽快回复的
 
mysirius,还没有进展吗?我会另外开贴给分的。决不食言
 
后退
顶部