相同的代码,用来Hook窗口显示。
D7编译出来的,不管怎么测试,都是正常的。Delphi2007编译出来的,挂钩后,运行也都正常,但在卸钩后,会导致资源管理器或者任务管理器错误。
出现错误的测试过程:
先打开任务管理器(别关掉),执行主程序,挂钩,打开一个有窗口的程序(别关掉),退出主程序。 
任务栏鼠标右键->任务管理器,出错。 我这里只要这么操作,就一定出错。
代码上传到download频道了,跟我下面贴的代码有一两行不一样。
http://download.csdn.net/source/651499 有兴趣的,下载下来帮忙看看。 
不过要注意,很可能会造成任务管理器和资源管理器崩溃。
实际工程内容比较多,想在D7下重新改写已经不太现实了。就想知道Delphi2007下,应该怎么解决。谢谢
不懂的,不能回答的,就别顶了,我会自己关注帖子,自己提前的,谢谢合作
Dll部分代码:
library makeErr;uses
  Messages,
  Classes,
  SysUtils,
  Windows,
  Dialogs,
  ComServ,
  theMain in 'theMain.pas';exports
  DllGetClassObject,
  DllCanUnloadNow,
  DllRegisterServer,
  DllUnregisterServer;{$R *.RES}
const
  HookMemFileName = 'DllHookMemFile.DTA';var
  PShare: PShareMem;
  MapHandle: THandle;function CallWndProc(nCode: Integer; WParam: WPARAM; LParam: LPARAM): LRESULT; stdcall;
var winStruct: TCWPStruct;
begin
  winStruct := PCWPSTRUCT(LParam)^;
  if nCode >= 0 then
  begin
    if winStruct.message = WM_SHOWWINDOW then
    begin
      SaveInfo('发现窗口创建:::' + inttostr(winStruct.hwnd));
    end;
  end;  Result:= CallNextHookEx(0, nCode, WParam, LParam);
end;procedure StartHook; stdcall;
begin
  if PShare^.HookHandle = 0 then
  begin
    PShare^.HookHandle := SetWindowsHookEx(WH_CALLWNDPROC, PShare^.HookProc, HInstance, 0);
    SaveInfo('钩子启动完毕,钩子句柄:::' + inttostr(PShare^.HookHandle));
  end;
end;procedure StopHook; stdcall;
var unhookResult: Boolean;
begin
  if PShare^.HookHandle <> 0 then
  begin
    unhookResult := UnhookWindowsHookEx(PShare^.HookHandle);
    if unhookResult then
    begin
      PShare^.HookHandle := 0;
      SaveInfo('钩子卸载完毕');    end
    else
      SaveInfo('钩子卸载失败');
  end
  else
    SaveInfo('PShare^.HookHandle为空:::' + inttostr(PShare^.HookHandle));
end;procedure DllEntry(dwReason: DWORD);
begin
  case dwReason of
    DLL_PROCESS_DETACH:
      begin
        saveinfo('dll 卸载,MapHandle:::' + inttostr(MapHandle));
        UnmapViewOfFile(PShare);
        closehandle(MapHandle);
        SaveInfo('共享内存关闭');
      end;
//    else;
  end;end;
exports StartHook, StopHook;
begin
  saveinfo('dll 入口执行,MapHandle:::' + inttostr(MapHandle));
  MapHandle := OpenFileMapping(FILE_MAP_ALL_ACCESS, False, pchar(HookMemFileName));
  saveinfo('得到共享内存句柄:::' + inttostr(MapHandle));  if MapHandle = 0 then
  begin
    MapHandle := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0,
                                   SizeOf(TShareMem), pchar(HookMemFileName));
    SaveInfo('共享内存创建:::' + inttostr(MapHandle));
  end;  PShare := MapViewOfFile(MapHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0);//  FillChar(PShare^, SizeOf(TShareMem), 0);
  PShare^.HookProc := @CallWndProc;  DllProc := @DllEntry;
//  DllEntry(DLL_PROCESS_ATTACH);
end.
theMain.pasunit theMain;interface
uses
  Windows,SysUtils;type
  THookProc = function(nCode: integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
  PShareMem = ^TShareMem;
  TShareMem = packed record
    Data: String[255];
    HookHandle:HHook;
    HookProc: THookProc;
  end;  procedure SaveInfo(str: string); stdcall;implementation
procedure SaveInfo(str: string); stdcall;
var
  f: textfile;
begin
  assignfile(f,'d:\Records.txt');  if FileExists('d:\Records.txt') = false then
    rewrite(f)
  else
    append(f);  writeln(f, str);
  closefile(f);
end;initializationfinalizationend.调用主程序MainForm.pas:
unit MainForm;interfaceuses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;type
  TForm1 = class(TForm)
    Button1: TButton;    procedure Button1Click(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private declarations }
    procedure SaveInfo(str: string); 
  public
    { Public declarations }
  end;//procedure StartHook; stdcall; external 'makeErr.dll' name 'StartHook';
//procedure StopHook; stdcall; external 'makeErr.dll' name 'StopHook';var
  Form1: TForm1;  StartHook:procedure; stdcall;
  StopHook :procedure; stdcall;
  moduleHandle : THandle;implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);
begin
  moduleHandle:= loadlibrary(pchar('makeErr.dll'));
  StartHook   := GetProcAddress(moduleHandle, 'StartHook');
  StopHook    := GetProcAddress(moduleHandle, 'StopHook');  if (@StartHook<>nil) then StartHook;
end;procedure TForm1.SaveInfo(str: string);
var
  f: textfile;
begin
  assignfile(f,'d:\Records.txt');  if FileExists('d:\Records.txt') = false then
    rewrite(f)
  else
    append(f);  writeln(f, str);
  closefile(f);
end;procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  SaveInfo('开始卸载钩子');
  if @StopHook<>nil then
    StopHook
  else
    SaveInfo('未找到卸载函数');  freelibrary(moduleHandle);  SaveInfo('关闭主程序');
end;end.用Delphi2009也试了一下,发现Hook也不正常,从日志文件里能看到莫名其妙的不停在发现窗口创建,就好像被挂钩很多次似的。不懂的,不能回答的,就别顶了,我会自己关注帖子,自己提前的,谢谢合作
明天加分到200.

解决方案 »

  1.   

    我在windows 2003 + SP2 的虚拟机当中测试一切正常
      

  2.   

    CodeGear™ RAD Studio 2007  Version 11.0.2902.10471
      

  3.   

    僵哥,是像我说的那样测试的吗?
    先打开任务管理器(别关掉),执行主程序,挂钩,打开一个有窗口的程序(别关掉),退出主程序。 
    任务栏鼠标右键->任务管理器,出错。 
    也用Delphi2007编译过吗?我的Delphi2007就是你给我的那个啊,一模一样啊,我RP有问题?
      

  4.   

    我虚拟机WinXP+sp2
    主机Win2003+sp2测试都有问题
      

  5.   

    要不你把你的程序,改一下那个记录文件写到c盘(我的虚拟机没有D盘)发我邮箱[email protected],顺便我也发你一份.
      

  6.   

    不过,我有点怀疑的是,可能还是上次说的写文件的地方可能会访问冲突,如果机器比较慢的话.建议使用互斥对象(CreateMutex)进行同步来写文件.
      

  7.   

    在DLL的Initilization节下添加如下代码IsMultiThread := true;
      

  8.   

    我所能想到的只有两种情况.
    1.文件访问失败,报异常,从而Hook释放失败,解决办法是在写文件的时候使用互斥,或者加try ... except
    2.由于使用到String对象,多线程导致内存访问违例,Hook释放失败.设置IsMultiThread 为True,强制内存管理器启用线程安全管理.
      

  9.   

    而对于情况1,应该在D7编译的版本当中也会出现,剩下的就只有第二种可能,D2007及之后使用的内存管理器与D7有本质的差别.
      

  10.   

    据说Delphi2007内置了ShareMem。
    但我试过,加了ShareMem,干脆加载不了Dll了
    IsMultiThread 我也试了,问题依旧
    看有人讨论FastMM,不知道这个跟我的问题是否有关系。
      

  11.   

    另外,很奇怪的是,相同的代码和程序,在你那里执行为什么就没问题呢
    Delphi2009我也试了,也是出现错误。