TO:kaimen
呵呵,在IDE中调试hook当然不一定会当掉,这跟你使用的是哪种hook有关系的。
看一看下面的:
用Delphi实现程序间的数据传递
在实际应用中,我们经常需要多个程序相互配合来完成某些特定功能。
例如两个应用程序间的同步、互斥;应用程序在起第二份实例时的参数
自动传递…。要实现这些功能,就必须能实现程序间的数据传递。
有些特殊的高级技术可在不同的程序间传递数据,如剪贴板、动态数据
交换以及OLE自动化,但有条件限制并且相对较复杂。这里,我介绍三种
有效的底层技术,希望对编程爱好者有所帮助。
利用WM_COPYDATA消息
使用该消息涉及一个TcopyDataStruct结构类型的指针。该结构中有三个成员:
dwData 是一个32位的附加参数
cbData 表示要传递的数据区的大小
lpData 表示要传递的数据区的指针
下面举个例子。该例子由两个程序构成,分别为SendData和GetData。
SendData程序向GetData程序发送消息,并传递edit1中的字符串;GetData
在收到消息后,把SendData发送的字符串接受下来,并显示在相应的edit1中。
SendData程序:
……
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
var
ds: TCopyDataStruct;
hd: THandle;
begin
ds.cbData := Length (Edit1.Text) + 1;
GetMem (ds.lpData, ds.cbData ); //为传递的数据区分配内存
StrCopy (ds.lpData, PChar (Edit1.Text));
Hd := FindWindow (nil, 'Form2'); // 获得接受窗口的句柄
if Hd <> 0 then
SendMessage (Hd, WM_COPYDATA, Handle,
Cardinal(@ds)) // 发送WM_COPYDATA消息
else
ShowMessage ('目标窗口没找到!');
FreeMem (ds.lpData); //释放资源
end;
GetData程序:
TForm2 = class(TForm)
Edit1: TEdit;
private
{ Private declarations }
public
procedure Mymessage(var t:TWmCopyData);message WM_COPYDATA;
{ Public declarations }
end;
var
Form2: TForm2;
implementation
procedure TForm2.Mymessage(var t:TWmCopyData);
begin
Edit1.text:=StrPas(t.CopyDataStruct^.lpData);//接受数据并显示。
end;
使用这种方法是WIN32应用程序进行交互的最简单的方法。
使用全局原子
Win32系统中,为了实现信息共享,系统维护了一张全局原子表。
每个原子中存放了一些共享数据。关于对原子的操作,有一组专门的API函数:
GlobalAddAtom 在表中增加全局原子
GlobalDeleteAtom 在表中删除全局原子
GlobalFindAtom 在表中搜索全局原子
GlobalGetAtomName 从表中获取全局原子
笔者用这种方法实现了避免程序二次启动,但把第二次启动所带的
参数传到第一个实例中以进行相应的处理的程序。基本处理如下:
在工程文件中:
program Pvdde;
uses
Forms,shellapi,Windows,dialogs,dde in 'dde.pas' {Form1};
{$R *.RES}
begin
if GlobalFindAtom(PChar('PDDE_IS_RUNNING')) = 0 then
//避免二次启动
begin
K:=GlobalAddAtom(PChar('PDDE_IS_RUNNING'));
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end
else
begin
//传递二次启动时的参数到第一个实例
H := FindWindow(PChar('TForm1'), PChar('资料保密 严禁外传'));
if ParamCount > 0 then
begin
L := GlobalAddAtom(PChar(ParamStr(1)));
if H<>0 then
SendMessage(H, WM_MYMESSAGE, 0, L);
{ 传递原子句柄 }
GlobalDeleteAtom(L); { 使用后释放 }
end;
Application.Terminate;
end;
end.
在相应的窗口单元dde.pas增加对自定义消息WM_MYMESSAGE的处理:
procedure TForm1.MyMessage(var T:TMessage);
{对 WM_MYMESSAGE消息进行处理 }
var
P:Array [0..255] of char;
begin
GlobalGetAtomName(T.LParam, P,255); { 接受数据到p数组中 }
。。。
end;
使用存储映象文件
这种方法相对较复杂一些。
当Win95与Winows Nt向内存中装载文件时,使用了特殊的全局内存区。
在该区域内,应用程序的虚拟内存地址和文件中的相应位置一一对应。
由于所有进程共享了一个用于存储映象文件的全局内存区域,因而当
两个进程装载相同模块(应用程序或DLL文件)时,它们实际可以在
内存中共享其执行代码。
笔者通过调用一个带有特殊参数的CreateFileMapping函数,来间接达到
程序间共享内存的目的。下面简要解释一下该函数。
HANDLE CreateFileMapping(
HANDLE hFile, //文件句柄
LPSECURITY_ATTRIBUTES lpFileMappingAttributes, // 可选安全属性
DWORD flProtect, // 映象文件保护方式
DWORD dwMaximumSizeHigh, // 映象文件区域的底值
DWORD dwMaximumSizeLow, // 映象文件区域的顶值
LPCTSTR lpName // 映象文件的名字
);
如果hFile是0xFFFFFFFF,在调用程序中必须指定dwMaximumSizeHigh
和dwMaximumSizeLow参数的值以确定映象文件的大小。通过这样的参数
指定,该函数就创建了一个由操作系统页文件支持的特殊逻辑映象文件,
而不是由实际操作系统的文件支持的逻辑映象文件。这个逻辑映象文件
可以通过复制、继承或者按名字来达到共享。至于其它参数的详细说明,
请参看在线帮助。
在建立了映象文件之后,我们可以通过调用另外一个API函数MapViewOfFile
来访问它的内存,该函数会返回一个指向共享内存块的特定指针。
LPVOID MapViewOfFile(
HANDLE hFileMappingObject, // 映象文件句柄
DWORD dwDesiredAccess, // 访问方式
DWORD dwFileOffsetHigh, // 映象文件区域的底值
DWORD dwFileOffsetLow, // 映象文件区域的顶值
DWORD dwNumberOfBytesToMap // 映射字节数
);
如果 dwNumberOfBytesToMap 是0,映射整个文件。
以下举例说明:
private
hMapFile: THandle;
MapFilePointer: Pointer;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
begin
hMapFile := CreateFileMapping (
$FFFFFFFF, // 特殊内存映射句柄
nil, page_ReadWrite, 0,10000,
'DdhDemoMappedFile'); // 文件名
if hMapFile <> 0 then
MapFilePointer := MapViewOfFile (
hMapFile, // 上面映象文件的句柄
File_Map_All_Access,
0, 0, 0) // 访问整个映象文件
else
ShowMessage ('hMapFile = 0');
if MapFilePointer = nil then
ShowMessage ('MapFilePointer = nil');
end;
procedure TForm1.BtnWriteClick(Sender: TObject);
begin
StrCopy (PChar (MapFilePointer),
PChar (EditWrite.Text));//把内容写入共享内存
end;
procedure TForm1.BtnReadClick(Sender: TObject);
var
S: string;
begin
S := PChar (MapFilePointer);//从共享内存读出内容
EditRead.Text := S;
end;
用这种方法,不但可以在不同的程序之间共享数据,还可以在同一程序的
不同实例间共享数据。为了及时通知其它进程共享数据的变化,可以自定义
一条用户消息,通过发消息来实现,这里不再赘述。
利用以上三种方法均可以有效地实现数据传递、共享,所有的例子程序均
在Delphi 3.0,4.0下调试通过。如需源码,写信至wj_email@yahoo.com索