DLL工程文件
library wg;uses
  SysUtils,
  Classes,
  wgdll in 'wgdll.pas' {popform};
  {$R *.res}
exports
  SetHook,
  EndHook;begin
  hNextHookProc := 0;
  procSaveExit := ExitProc;
  ExitProc := @HotKeyHookExit;
end.WGDLL的PAS文件如下:
unit wgdll;interfaceuses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ComCtrls,WorkThread, StdCtrls, Buttons, ExtCtrls;type
  Tpopform = class(TForm)
  PageControl1: TPageControl;
  TabSheet1: TTabSheet;
  TabSheet2: TTabSheet;
  private
    { Private declarations }
  public
    { Public declarations }
  end;var
  hThread: Cardinal;
  popform: Tpopform;
  hNextHookProc : HHook;
  procSaveExit  : Pointer;
  GameWindow:HWND;
  function KeyboardProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM):LRESULT; stdcall;
  function SetHook: bool;
  function EndHook: bool;
  procedure HotKeyHookExit; far;implementation
{$R *.dfm}//------------------------------------------------------------------------------function KeyboardProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM):LRESULT; stdcall;
var
  title: pchar;
begin
  result :=0;
  if nCode < 0 then
  begin
    CallNextHookEx(hnexthookproc, nCode, wParam, lParam);
    result := 0;
    Exit;
  end;
  if ((lParam and $80000000) = 0) and (wParam = VK_F12) then
  begin
  //-------------------------------------------------------------------------
    if PopForm=nil then
      begin
        getmem(title,255);
        GameWindow := getforegroundwindow;
        getwindowtext(GameWindow, title, 255);
        if (title='1.txt - 记事本') then
          begin
            freemem(title);
            SuspendThread(hThread);
            PopForm:=TpopForm.CreateParented(GameWindow);
            PopForm.ShowModal;
            ResumeThread(hThread);
          end;
      end
    else
      if popform.Visible then popform.Close else popform.Show;
  //-------------------------------------------------------------------------
  end;
  result := CallNextHookEx(hnexthookproc, nCode, wParam, lParam);
end;//------------------------------------------------------------------------------
function SetHook: bool;export;
begin
  result := false;
  if hnexthookproc <> 0 then
    exit;
  hNextHookProc := SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, HInstance, 0);
  Result := hNextHookProc <> 0;
end;
//------------------------------------------------------------------------------
function EndHook: bool; export;
begin
  if hNextHookProc <> 0 then
  begin
    UnhookWindowshookEx(hNextHookProc); // 解除 Keyboard Hook
    hNextHookProc := 0;
  end;
  Result := hNextHookProc = 0;
end;
//------------------------------------------------------------------------------
procedure hotkeyhookexit;
begin
  if hNextHookProc <> 0 then endHook;
  ExitProc := procSaveExit;
end;
//------------------------------------------------------------------------------
end.调用DLL的EXE文件窗体中有一按钮,按下激活SETHOOK:
procedure TMainForm.Button1Click(Sender: TObject);
begin
SetHOOK;
end;
EXE窗体关闭时激活ENDHOOK:
procedure TMainForm.FormDestroy(Sender: TObject);
begin
EndHook;
end;
现在在记事本中实验,按F12外挂窗体能显示和关闭,但如果调用DLL的EXE文件在记事本没关闭前先关闭了,这时记事本就会报错(但记事本中的外挂窗口如果当时是显示的就会一起关闭不报错,如果外挂窗口是关闭的就会报错),用了POPFORM.FREE也不行,谁有办法解决这个问题,即让调用DLL的EXE文件先关闭时HOOK的程序不报错,而且不退出,即让HOOK的程序和外挂窗体完全脱离EXE文件