Delphi 控制外部程序

最近做一个项目,需要从外部控制挰序,好比做一个外挂,要获取游戏里各个控件的句柄,然后对它进行操作。在网上查了查,这方面的例子无一例外都是C++的,找不到Delphi的,在几个网站上问了,回答的人都说不知道,并且推荐我用C++进行开发,难道Delphi真的不能对外部程序操作?

经过一天的努力,我证明了Delphi也是可以做到的,并且比C++做起来更方便,我把它做成一个控件,以便随时拖出来就用。

unit RaOuterControls;

interface

uses
SysUtils, Classes, Windows, TlHelp32;

type
TProcessInfo = record
pHandle: Cardinal;
pClassName: string;
pText: string;
end;

type
TOnSendMessage = procedure(Sender: TObject; SndMsgResult: Cardinal) of object;
TOnWindowChange = procedure(Sender: TObject) of object;

type
TRaOuterControls = class(TComponent)
private
fProcessHandle: THandle;
fTextList: TStringList;
fHandleList: TStringList;
fClassList: TStringList;
fWindowCaption: string;
fSM: Cardinal;
fSLP: Cardinal;
fSWP: Cardinal;
fSMH: THandle;
fOnSendMessage: TOnSendMessage;
fOnWindowChange: TOnWindowChange;
procedure SetProcessHandle(const Value: THandle);
procedure SetWindowCaption(const Value: string);
protected
//function FindExeHandle(AExeName: string): THandle;
public
constructor Create(AOwner: TComponent); override;
function GetProcessControlInfo(index: Integer): TProcessInfo;
procedure SendMessageToControl; overload;
procedure SendMessageToControl(hWnd: THandle; Msg: Cardinal; WParam: Cardinal; LParam: Cardinal); overload;
published
property OnSendMessage: TOnSendMessage read fOnSendMessage write fOnSendMessage;
property OnWindowChange: TOnWindowChange read fOnWindowChange write fOnWindowChange;
property SndMsgHandle: THandle read fSMH write fSMH;
property SndMessage: Cardinal read fSM write fSM;
property SndLParam: Cardinal read fSLP write fSLP;
property SndWParam: Cardinal read fSWP write fSWP;
property ProcessHandle: THandle read fProcessHandle write SetProcessHandle;
property HandleList: TStringList read fHandleList;
property ClassList: TStringList read fClassList;
property TextList: TStringList read fTextList;
property WindowCaption: string read fWindowCaption write SetWindowCaption;
end;

var
IHandleList: TStringList;
IClassList: TStringList;
ITextList: TStringList;

function EnumChildWndProc(AhWnd: LongInt; AlParam: LParam): boolean; stdcall;

procedure Register;

implementation

procedure Register;
begin
RegisterComponents('Rarnu Components', [TRaOuterControls]);
end;

function EnumChildWndProc(AhWnd: LongInt;
AlParam: LParam): boolean; stdcall;
var
WndClassName: array[0..511] of Char;
WndCaption: array[0..511] of Char;
begin
GetClassName(AhWnd, WndClassName, 512); //获取控件名称
GetWindowText(AhWnd, WndCaption, 512); //获取控件标题
IHandleList.Add(IntToStr(AhWnd));
IClassList.Add(string(WndClassName));
ITextList.Add(string(WndCaption));
result := true;
end;

{ TRaOuterControls }

constructor TRaOuterControls.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
fTextList := TStringList.Create;
fTextList.Clear;
fHandleList := TStringList.Create;
fHandleList.Clear;
fClassList := TStringList.Create;
fClassList.Clear;
IHandleList := TStringList.Create;
IHandleList.Clear;
IClassList := TStringList.Create;
IClassList.Clear;
ITextList := TStringList.Create;
ITextList.Clear;
end;

function TRaOuterControls.GetProcessControlInfo(
index: Integer): TProcessInfo;
var
piInfo: TProcessInfo;
begin
piInfo.pHandle := 0;
piInfo.pClassName := '';
piInfo.pText := '';
if fHandleList.Count - 1 < index then
begin
result := piInfo;
Exit;
end;
piInfo.pHandle := StrToInt(fHandleList.Strings[index]);
piInfo.pClassName := fClassList.Strings[index];
piInfo.pText := fTextList.Strings[index];
result := piInfo;
end;

procedure TRaOuterControls.SendMessageToControl;
var
SndResult: Cardinal;
begin
SndResult := SendMessage(fSMH, fSM, fSWP, fSLP);
if Assigned(OnSendMessage) then
OnSendMessage(self, SndResult);
end;

procedure TRaOuterControls.SendMessageToControl(hWnd: THandle; Msg, WParam,
LParam: Cardinal);
var
SndResult: Cardinal;
begin
SndResult := SendMessage(hWnd, Msg, WParam, LParam);
if Assigned(OnSendMessage) then
OnSendMessage(self, SndResult);
end;

procedure TRaOuterControls.SetProcessHandle(const Value: THandle);
begin
fProcessHandle := Value;
IHandleList.Clear;
IClassList.Clear;
ITextList.Clear;
if fProcessHandle <> 0 then EnumChildWindows(fProcessHandle, @EnumChildWndProc, 0);
fTextList := ITextList;
fHandleList := IHandleList;
fClassList := IClassList;
if Assigned(OnWindowChange) then
OnWindowChange(self);
end;

procedure TRaOuterControls.SetWindowCaption(const Value: string);
begin
fWindowCaption := Value;
ProcessHandle := FindWindow(nil, PChar(fWindowCaption));
end;

end.









相信你一定看明白了,EnumChildWndProc其实是一个回调函数,它本身就拥有递归的性质,result:=true表明它可以继续回调,直到条件不成立为止。利用内置API可以方便的完成类名和控件标题的获取,而用C++的话,此时必须先对记录进行声明,这个声明将花费大量的代码。

控件做完后,就开始做一个实例,很简单,我想把我输入在Memo里面的文本直接移动到记事本里,实现代码如下:

unit Unit1;

interface

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

type
TForm1 = class(TForm)
RaOuterControls1: TRaOuterControls;
Label1: TLabel;
Timer1: TTimer;
Label2: TLabel;
Memo1: TMemo;
Button1: TButton;
procedure Timer1Timer(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
NotePadHandle:THandle;

implementation

{$R *.dfm}

procedure TForm1.Timer1Timer(Sender: TObject);
begin
NotePadHandle:=FindWindow(nil,'无标题 - 记事本');
if NotePadHandle<>0 then
self.Label1.Caption:='新记事本已打开'
else
self.Label1.Caption:='请打开一个空的记事本';
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
self.Timer1Timer(self);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
i:integer;
begin
if NotePadHandle=0 then
begin
ShowMessage('请打开一个新的记事本');
Exit;
end;
self.RaOuterControls1.ProcessHandle:=NotePadHandle;
//self.ListBox1.Items:=self.RaOuterControls1.ClassList;
for i:=0 to self.RaOuterControls1.ClassList.Count-1 do
begin
if self.RaOuterControls1.ClassList.Strings[i]='Edit' then
begin
self.RaOuterControls1.SendMessageToControl
(StrToInt(RaOuterControls1.HandleList.Strings[i]),WM_SETTEXT,
0,Cardinal(PChar(memo1.Lines.Text)));
Exit;
end;
end;
end;

end.

除去大部分系统生成的代码外,几乎都是对控件的操作,这里提一下,虽然PCHAR保留过程返回的值是AnsiString,但是却可以用数值形转换,这里用Cardinal进行了转换,但是实际用中,个人认为还是用LongInt转换比较好,LongInt可以与其他开发平台兼容,而Cardinal仅局限于delphi中。它的原理是把文本转成整型数组的形式存到内存中,然后通过SendMessage函数进行发送。

在遍历中,由于事先知道控件的名称,所以直接用了判断,如果不知道的话还需进一步判断。我在这个控件中封装了GetProcessControlInfo函数,它返回选中的一个记录,使用起来会更加的方便。

测试一下做好的程序,果然,原来在窗体上的文本已经跑到记事本里面去了。

源码下载:http://rarnu.ys168.com/

Delphi技术目录内->外部程序操作.rar

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值