我写的键盘HOOK程序,不能在后台捕获键盘消息。“能人”请进!

bahic 2004-12-20 01:05:00
我写的键盘HOOK程序,不能在后台捕获键盘消息。只能的主窗口活动的情况才能捕获键盘消息。
就象我写的是局部HOOK一样。

HOOK.DLL的源代码如下:
#include <vcl.h>
#include <windows.h>
#pragma hdrstop

#pragma argsused

extern "C" __declspec(dllexport) void __stdcall SetHook(HWND wnd,bool mode);
static HHOOK hkKey;
static HINSTANCE Hhinst;
static HWND hwnd;
static const MY_MSG=8000; // 自定义消息号
//=======================================================================
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
Hhinst=hinst;
return 1;
}
//-------------------------------------------------------------------------
LRESULT CALLBACK HookKey(int nCode,WPARAM wParam,LPARAM lParam)
{
if (nCode == HC_ACTION)
{
if((lParam&0xc0000000)==0xc0000000) // 有键松开
PostMessage(hwnd,MY_MSG,wParam,lParam);
}
return CallNextHookEx((HHOOK)hkKey,WH_KEYBOARD,wParam,lParam);
}
//---------------------------------------------------------------------------
void __stdcall SetHook(HWND wnd,bool mode)
{
if(mode) //安装HOOK
{
hwnd=wnd;
hkKey=SetWindowsHookEx(WH_KEYBOARD,(HOOKPROC)HookKey,Hhinst,0);
}
else
{
if(hkKey)UnhookWindowsHookEx(hkKey);
}
}
//-----------------------------------------------------------------------





//我的主程序中的调用过程
void __fastcall TForm1::Button3Click(TObject *Sender)
{
static bool run=false;
static HINSTANCE hDLL; // DLL句柄
typedef void __stdcall (*DLLFUN)(HWND hwnd,bool mode);
DLLFUN SetHook;
if(!run)
{
hDLL=LoadLibrary((LPCTSTR)"HOOK.dll"); // DLL文件名:HOOK.dll
if(hDLL==NULL) { ShowMessage("DLL: 不能加载!程序退出。"); exit(1); }
SetHook =(DLLFUN)GetProcAddress(hDLL,"SetHook");
if(SetHook==NULL)
{ ShowMessage("DLL: 函数没找到!程序退出。"); FreeLibrary(hDLL); exit(1); }
SetHook(this->Handle,true);
}
else
{
SetHook(NULL,false); // 卸下HOOK
FreeLibrary(hDLL); // 卸下DLL
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ApplicationEvents1Message(tagMSG &Msg,bool &Handled)
{
static const myMessage=2000;
static const SecondPar=1;
if(Msg.message==myMessage)
ShowMessage(" 收到HOOK按键消息!\n\n 【键虚拟码】:"+IntToStr(Msg.wParam));
}
//---------------------------------------------------------------------------





...全文
252 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
bahic 2004-12-24
  • 打赏
  • 举报
回复
jishiping,谢谢你了,呵呵,你是对的,我又重新用你说的写了一下,可以了,就是象你说的,改了就行!
jishiping 2004-12-20
  • 打赏
  • 举报
回复
“我这个程序本来就不用共享内存”
---------------------------------------------------------------------
不是你本来用不用共享内存的问题,而是你必须要通过某种方式,让线程加载的DLL能够访问到你的窗口句柄。当然不是一定要用共享内存,共享内存只是一种方式。

至于键盘钩子,我还是很熟悉的。“不能在后台捕获键盘消息,只能的主窗口活动的情况才能捕获
键盘消息”,原因就在于我一开始说的。如果楼主对此持怀疑态度,我也没有办法。
sydt 2004-12-20
  • 打赏
  • 举报
回复
听课!!!

收藏!!!
bahic 2004-12-20
  • 打赏
  • 举报
回复
我这个程序本来就不用共享内存,而且我原来用是的CtreatFileMapping申请的共享内存来传递
参数,也不行的,
我现在的感觉就是我的HOOk.DLL根本就没有连入系统HOOK中去,也就不能捕获系统中的消息了。
我现在的问题就是怎样连入系统HOOK链中去,只有这样才能捕获系统消息。
是不是的BCB中还要设置什么地方的参数才行。我真的是不明白不。。。
BeRoy 2004-12-20
  • 打赏
  • 举报
回复
老大来了~
jishiping 2004-12-20
  • 打赏
  • 举报
回复
第二种方法,就是使用文件影射的方法,创建共享内存。下面是我写的一个共享内存的class,
EXE中 将共享的窗口句柄 hwnd 写入到共享内存中,每次从共享内存中取出窗口句柄。

class TShareMem
{
private:
int FSize;
BYTE *FBuffer;
char FName[33];
bool FCreated;
HANDLE FHandle;
public:
TShareMem(LPCSTR Name, int Size);
~TShareMem();

int Size() { return FSize; }
LPCSTR Name() { return FName; }
BYTE* Buffer() { return FBuffer; }
bool Created() { return FCreated; }
};

TShareMem::TShareMem(LPCSTR name, int size)
{
FSize = size<0 ? 0 : size;
memset(FName, 0, sizeof(FName));
if (!name || name[0]==0)
strcpy(FName, "ShareMemory");
else
strncpy(FName, name, sizeof(
FName)-1);

FHandle = CreateFileMapping((HANDLE)
0xFFFFFFFF, NULL, PAGE_READWRITE,
0, FSize, FName);
FCreated = GetLastError() == 0x0000;
if (FHandle != NULL) {
FBuffer = (BYTE*)MapViewOfFile(
FHandle, FILE_MAP_WRITE, 0,
0, FSize);
if (FBuffer && FCreated)
memset(FBuffer, 0, FSize);
}
else
FBuffer = NULL;
if (FBuffer == NULL) {
char msg[256]; int ID;
ID = FORMAT_MESSAGE_FROM_SYSTEM;
FormatMessage(ID,0,GetLastError(
),0,msg,sizeof(msg),NULL);
MessageBox(GetActiveWindow(),msg,
"Error",MB_ICONWARNING|MB_OK);
}
}

TShareMem::~TShareMem()
{
if (FBuffer) UnmapViewOfFile(FBuffer);
if (FHandle) CloseHandle(FHandle);
}
jishiping 2004-12-20
  • 打赏
  • 举报
回复
问题在于DLL中的 hwnd 这个参数。全局Hook,DLL会被系统调用(二不仅仅是你的程序)。所以,这个参数 hwnd 只在你自己调用的时候有效,被Windows调用的时候就无效了。进一步说,DLL的入口函数 DllEntryPoint 中的参数 Reason,一般情况下为 DLL_PROCESS_ATTACH,但是作为全局钩子的时候,这个参数就可能是 DLL_THREAD_ATTACH 了。当 Reason 为 DLL_THREAD_ATTACH 时,你的那个参数 hwnd 就是无效的参数了。
解决办法,一是“创建共享内存段”,不过我自己没有用过,以下的内容,我记得是从 cker 写的帖子中得到的,不过我自己至今没有没有使用过。

需要改变数据段和类名字,在想要共享的文件中增加 #pragma option -zR[段名字]
和#pragma option -zT[类名字]
下面的代码将输出一个称为'data'的整数。
#pragma option -zRSHSEG // 改变缺省的数据段名字
#pragma option -zTSHCLASS // 改变缺省的数据类名字
// 初始化我们打算共享的数据
int data = 0;

注意本文件中的段名是SHSEG SHCLASS。
Linker需要一个.def文件来创建共享段。下面是.def文件的内容。
//File: Shared.def
LIBRARY SHAREDDLL
SEGMENTS
SHSEG CLASS 'SHCLASS' SHARED

下面是包含dll入口点的dll源文件,包括了设置及取得共享内存段的方法。
#include <Windows.h>
#pragma hdrstop
#include "Shared.h"
USEDEF("Shared.def");

#pragma option -zRSHSEG // 改变缺省的数据段名字
#pragma option -zTSHCLASS // 改变缺省的数据类名字
// 初始化我们打算共享的数据
int data = 0;

int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)
{
return 1;
}

void __declspec(dllexport) SetData(int x)
{
data = x;
}

int __declspec(dllexport) GetData(void)
{
return data;
}
lihongxing2002 2004-12-20
  • 打赏
  • 举报
回复
up

13,873

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder相关内容讨论区
社区管理员
  • 基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧