简单问题,建立内存共享文件出错与几个关于HOOK的小问题 (200分)

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

LeonSu

Unregistered / Unconfirmed
GUEST, unregistred user!
我做了一个HOOK,用WH_CallProc拦截到了WM_Command消息,
然后把消息内容写一个记录变量(PMessageData),变量声明如下:
type
PMessageData=^TMessageData;
TMessageData = Record
EventStr: PChar;
wParam: Integer;
lParam: Integer;
end;
有一过程GetMessageData(var AMessageData: PMessageData)用来读取变量的值。
当Wh_CallProc拦截到一个WM_Command消息时,就会把消息内容写入变量中,然后向主程序
发送一条自定义消息,主程序得到自定义消息后,通过刚才那个过程去读取消息内容。
结果,自定义消息正常发出,消息内容也保存了,但只要主程序一调用GetMessageData就
会出错。
GetMessageData过程已经导出。过程内容如下:
var
MessageData: PMessageData;
...
procedure GetMessageData(var AMessageData: PMessageData)
stdcall;
begin
AMessageData:=MessageData;
end;

主程序中出错的地方是:
procedure TForm1.MyMessage(var MyMsg: TMessage);
var
MessageData:PMessageData;
begin
GetMessageData(MessageData);//就是这一条出错!!!!
end;

另外:
当我们用HOOK时,一般都会导出三个过程,如:
procedure StartReceive
stdcall
external "XXXX.dll";
procedure StartHook
stdcall
external "XXXX.dll";
procedure StopHook
stdcall
external "XXXX.dll";
后面两个用来开始与结束HOOK的,主程序中要用;但第一个呢,主要是在SetWindowsHookEx
函数中用的,为什么也要导出呢,主程序中根本没有用到它,同时,我看了许多人写的HOOK
中全是这样写的,原因何在,特请都之?
谢谢!
 
nobody knows?
 
将 borlndmm 放入你的程序。大概又是一个用 String 变量作 DLL 调用的人。
 
又是你!小雨哥。
你错了,我的MessageData的声明是这样的:
PMessageData = ^TMessageData;
TMessageData = record
EventStr: PChar;// 这里不是String,而是PChar
wParam: integer;
lParam: integer;
end;
我并没有用String,而是用PChar。在《开发人员指南》上有说,如果用String的话,
就要用ShareMem,同时,COPY Borlndmm.dll到程序目录中,如果不想这样做,就要用
Pchar类型替代String。
我是用的PChar类型呀!!!!!
 
我就是不要EventStr这个东东也会出错,
而且就在调用GetMessageData这个过程时,
全部的源代码如下:
DLL文件:
library MouseHook;

uses
ShareMem,
windows,
Messages;
// Dialogs;

const
WM_LeonSuMessage=WM_User+7777;
HOOK_MEM_FILENAME='LeonSu_FILE';

{$I typedata.inc}

var
NextHookProc : hHook;
ProcSaveExit : Pointer;
MessageData: PMessageData;
MapHandle: THandle;//,HookMutex
MainHandle: THandle;

procedure OpenShareData;
var
Size: Integer;
begin
// 通过建立内存映象文件以共享内存
Size:=Sizeof(TMessageData);
MapHandle:=OpenFileMapping(FILE_MAP_WRITE,False,HOOK_MEM_FILENAME)
//打开内存映射文件
If Maphandle=0 then
MapHandle:=CreateFileMapping(DWord(-1),nil,PAGE_READWRITE,0,Size,HOOK_MEM_FILENAME);
MessageData:=MapViewOfFile(MapHandle,FILE_MAP_ALL_ACCESS,0,0,Size);
end;

{procedure CloseShareData;
begin
UnMapViewOfFile(LeonSuMessage);
CloseHandle(MapHandle);
end;}

function SetReceive(icode:integer;wparam:wparam;lparam:lparam):lresult;stdcall;
var
pp: PCWPStruct;
begin
Result:=0;
if icode<0 then
begin
Result:=CallNextHookEx(NextHookProc,iCode,wParam,lParam);
exit;
end;
pp:=PCWPStruct(lParam);
With pp^ do
begin
if (message=WM_COMMAND) then// or (message=WM_SYSCOMMAND) then
begin
{ Case message of
WM_Command:MessageData^.EventStr:='Command';
WM_SysCommand:MessageData^.EventStr:='SysCommand';
end;}
MessageData^.wParam:=0;
MessageData^.lParam:=0;
SendMessage(MainHandle,WM_LeonSuMessage,0,0);
end;
end;
end;

function StartHook: BOOL;
begin
Result := False;
if NextHookProc <> 0 then Exit;
// 挂上 WH_KEYBOARD 这型的 HOOK, 同时, 传回值必须保留下
// 来, 免得 HOOK 呼叫链结断掉 WH_CallWNDPROC
RegisterWindowMessage(PChar(WM_LeonSuMessage));

MainHandle:=FindWindow(nil,'LeonSu');
// NextHookProc := SetWindowsHookEx(WH_GetMessage, SetReceive, HInstance, 0);
NextHookProc := SetWindowsHookEx(WH_CALLWNDPROC, SetReceive, HInstance, 0);
Result := NextHookProc <> 0;
end;

function StopHook: Bool;
begin
if NextHookProc<>0 then
begin
UnHookWindowsHookEx(NextHookProc);
NextHookProc:=0;
end;

UnMapViewOfFile(MessageData)
// 释放内存映象文件
CloseHandle(MapHandle)
// 关闭映象文件

Result:=NextHookProc=0;
end;

procedure HookExit;far;
begin
if NextHookProc<>0 then StopHook;

// UnMapViewOfFile(MessageData)
// 释放内存映象文件
// CloseHandle(MapHandle)
// 关闭映象文件

ExitProc:=ProcSaveExit;
end;

procedure GetMessageData(var AMessageData: PMessageData)
stdcall;
begin
AMessageData:=MessageData

end;

exports
SetReceive,
StartHook,
StopHook,
GetMessageData;

begin
NextHookProc := 0;
// 以下这两列, 旨在确定 DLL UnLoad 时, 确定将 HOOK 解除

OpenShareData;

ProcSaveExit := ExitProc;
ExitProc := @HookExit;
end.

主程序中:
...
{$I typedata.inc}
...
private
procedure MyCommandMessage(var MyMsg: TMessage)
message WM_LeonSuMessage;
...
procedure GetMessageData(var MsgInfo: PMessageData)
external 'MouseHook.dll';
...
var
Form1: TForm1;
MessageData: PMessageData;
...
procedure TForm1.MyCommandMessage(var MyMsg: TMessage);
var
List: TListItem;
begin
If StartedHook then
begin
MessageBeep(1000);
GetMessageData(MessageData);//加上这句话就会出错
{ With MessageData^ do
begin
List:=ListView2.Items.Add;
List.Caption:=StrPas(EventStr);
List.SubItems.Add(IntToStr(wParam));//被操作对象的句柄
List.SubItems.Add(IntToStr(lParam));//lParam
end;}
end;
inherited;
end;

INC文件:
type

PMessageData=^TMessageData;
TMessageData=record
// EventStr: PChar;
wParam: LongInt;
lParam: LongInt;
end;

机器环境:
Win98+Delphi 6+Update 2
 
骗分么,还不积极踊跃点? :-) :-)
不过是我错了,帮你提前。
TMessageData 内存在主程序中分配了没有或去掉 var 试试。
 
问题我自己解决了,
你没有错,小雨哥。
经过了无数次的当机、重启之后发现:
当我加上ShareMem,并考贝Borlndmm.dll过来后,
再把TMessageData的EventStr的类型改为String[50],问题就得到了解决,一切OK了。
同时,当我改回PChar,并且不要ShareMem单元的时候,问题又出现了。所以,我在想,
会不会是《Delphi 5开发人员指南》这本书上写错了,干脆我把那段话打上来(还要我在
8年前就学会五笔了,要不然......),原话如下:
------ 开始 -------
警告 如果DLL中的导出函数或过程以字符串或动态数组作为参数或返回值,那么ShareMem
必须是DLL和项目的Uses子句中的第一单元。这应用于应用程序和DLL的一切字符串的传递,
甚至隐含在记录和类中的字符串。ShareMem是共享内存管理器Borlndmm.dll的接口单元,
Borlndmm.dll必须与DLL一起发布。要避免使用Borlndmm.dll,就得用PChar或者ShortString
来传递字符串信息。
只有当模块间传递字符串和动态数组并且需要传递内存和隶属关系时,才需要ShareMem
单元。将一个内部字符串强制类型转换为PChar并将其作为PChar传递给另一个模块时,不传递
字符串内存的隶属关系到模块,那么就不需要ShareMem单元了。
注意ShareMem单元只应用于Delphi/BCB DLL之间或其与Exe之间以字符串或动态数组
为传递参数时使用。反之,如果是在非Delphi的DLL或宿主应用程序之间的话,也就不需要
ShareMem单元了。
还有由于包与包之间的共享内存分配器是隐含的,所以包之间也不需要ShareMem。
------ 结束 -------

事实上,我试了一下用ShortString,结果还是一样出错。看来,是书上写得不完全正确。
暂时不想结贴,看看有没有其他的意见。
 
终于明白了,
应该用PChar没错,但给变量赋值之前,必须先用New来分配内存。
如果是动态数组,也应该用New吧!

结贴!
 
呵呵,我早看到你上一贴了,已经写了,怕别人倒不发言了,所以没写。
我看到你的源码时就知道是自己错了。看了 2 遍,好象是内存没有分配,
所以其实帖子 1343701 我都改了 2 次,大概你也没注意。哈哈哈哈,你还行。
 
其实还有一个小问题,就是我不知道该在哪里NEW,每次自定义消息是发出去了,两个参数
的值也正确了,但读的时候就不知道读到哪里去了。但又没出错。只有连先挂一次,释放
掉,然后再挂一次,所有的数都正常了。
我猜可能是调用DLL的地方不对吧,因为我是静态调用,想改为动态调用试一下。
另外,这个问题的解决其实是搜索了一下其他的贴子,之前不是没搜过,关键字不对,搜不
到我想要的。
要知道,这个问题烦了我至少3天时间了,每天10多个小时烦在这上面,这还没什么,最烦的
事是我在大富翁上提出了问题,分也很高,可就是没人来答,我也不是要完整代码,只想有
人稍稍指点一下,错的也没关系,但就是没人!!!!!!!!
你可以看一下我发的贴,最近的贴子基本上都被我编辑过(包括这个也是),有个贴子的标
题被我改成了“MM求救”,这是实在迫不得已(因为我是男的),这下知道我的痛苦点了吧!:)
在我提出的问题中,约占四成比例是我自己解决的,三成是网友提示了一下。
今晚想发点分出去,一口气结了3、4个,还有5个问题未结,不是我不想结,而是完全没办法结
想不想赚点分!:)
 
后退
顶部