程序的功能目的很简单,如果程序窗口被其他程序挡住,按Ctrl+Z能把程序窗口切换到最前面来(成为当前窗口)。
实现的方式是:用一个键盘钩子监视Ctrl+Z,当这两个键被按下时,把程序窗口最大化,并置为TopMost窗口。
出现问题的地方是,有时候切换几次后,再把程序关掉,会出现explorer.exe出错的提示,点确定后桌面消失,过一会儿才会出来。键盘钩子写在一个DLL里,代码是改自网上找来的一个键盘钩子的代码
DLL代码:
library Hook;uses
  HookUnit in 'HookUnit.pas';exports
EnableHotKeyHook,
DisableHotKeyHook;{$R *.RES}
begin
hNextHookProc := 0; 
procSaveExit := ExitProc;
ExitProc := @HotKeyHookExit;
end.HookUnit.pas代码:
unit HookUnit;
interface
uses
Windows, Messages,Dialogs,SysUtils,IniFiles,Forms;
var
hNextHookProc: HHook;//保存SetWindowsHookEx的返回值
procSaveExit: Pointer;
function KeyboardHookHandler(iCode: Integer;wParam: WPARAM;lParam: LPARAM): LRESULT; stdcall; export;
function EnableHotKeyHook: BOOL; export;//安装钩子
function DisableHotKeyHook: BOOL; export;//卸载钩子
procedure HotKeyHookExit; far;
implementation
function KeyboardHookHandler(iCode: Integer;wParam: WPARAM;lParam: LPARAM): LRESULT; stdcall; export;
const
_KeyPressMask=$80000000;//键盘掩码常量
var
   myhandle,otherhandle:Cardinal;
  ini:Tinifile;
  s:string;
  scr_w,scr_h:integer;
begin
Result:=0;
If iCode < 0 Then //根据SDK说明,若iCode小于0,调用CallNextHookEx并返回
begin
Result:=CallNextHookEx(hNextHookProc, iCode, wParam, lParam);
Exit;
end;
// 监测是否按下了Ctrl+Z,
if ((lParam and _KeyPressMask) = 0) and(GetKeyState(vk_control) <0)
and ((wParam = Ord('Z')) )then
begin
//以下是我自己改的部分
   scr_h:=GetDeviceCaps(getwindowdc(getdesktopwindow),VERTRES);//高
   scr_w:=GetDeviceCaps(getwindowdc(getdesktopwindow),HORZRES);//宽
   s:=ExtractFilePath(Application.ExeName)+'pic\button.ini';
   ini:=TIniFile.Create(s);
  //从配置文件中读取程序的标题名
   s:=ini.ReadString('buttons','title','');
   //找到程序窗口的句柄
   myhandle:=FindWindow(nil,PChar(s));
   //最大化窗口
   PostMessage(myhandle,WM_SYSCOMMAND,SC_MAXIMIZE,0);
   //设置为TopMost窗口
   SetWindowPos(myhandle,HWND_TOPMOST,0, 0,scr_w,scr_h, SWP_NOSIZE);
//修改结束
   Result:=1;
   Exit;
end;
end;
function EnableHotKeyHook: BOOL; export;
begin
Result := False;//初始化返回值
if hNextHookProc<>0 then//如果已经注册,直接退出
Exit; 
//挂上键盘钩子,同时传回值必须保留下来,免得Hook呼叫链结断掉
hNextHookProc:=SetWindowsHookEx(WH_KEYBOARD,KeyboardHookHandler,HInstance,0);
//注册hook
Result:=hNextHookProc <> 0;//通过返回值确定是否注册成功
end;
function DisableHotKeyHook: 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 DisableHotKeyHook;//如果忘了解除HOOK,自动代理解除动作
ExitProc:=procSaveExit;
end;
end.在主程序里调用这个钩子
在主窗体的onFormCreate事件中调用loadhook加载钩子
procedure TForm1.loadHook;
var
  path:string;begin
 if HookHandle=0 then
   begin
     path:=ExtractFilePath(Application.ExeName)+'Hook.dll';
     HookHandle:=LoadLibrary(PChar(path));
     if HookHandle>0 then
       begin
         @EnableHook:=GetProcAddress(HookHandle,'EnableHotKeyHook');
         @DisableHook:=GetProcAddress(HookHandle,'DisableHotKeyHook');
         if @EnableHook<>nil then
            EnableHook;
       end;
   end;
 
end;
在主窗体的onClose事件中调用unloadHook卸载钩子
procedure TForm1.unloadHook;
begin
  if @DisableHook<>nil then
    begin
      DisableHook;
      //if DisableHook then
       // ShowMessage('注销钩子成功');
    end;
  if HookHandle<>0 then
    begin
      FreeLibrary(HookHandle);
    end;
end;
请各位大哥帮我看看,有哪里写得不好导致程序不稳定

解决方案 »

  1.   

    RegisterHotKey不行么,干嘛要用键盘钩子?
      

  2.   

    被这个bug折磨很久了,请大家来帮帮忙,是不是有其他方法可以实现的
      

  3.   

    RegisterHotKey?我找找,老大有demo代码否?
      

  4.   

    BOOL RegisterHotKey(
    HWND hWnd, // window to receive hot-key notification
    int id, // identifier of hot key
    UINT fsModifiers, // key-modifier flags
    UINT vk // virtual-key code);
    参数 id为你自己定义的一个ID值,对一个线程来讲其值必需在0x0000 - 0xBFFF范围之内,对DLL来讲其值必需在0xC000 - 0xFFFF 范围之内,在同一进程内该值必须唯一
    参数 fsModifiers指明与热键联合使用按键,可取值为:MOD_ALT MOD_CONTROL MOD_WIN MOD_SHIFT
    参数 vk指明热键的虚拟键码 
    弱弱地问一下 'z' 的virtual-key code有没有?