Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / C++ [игнор отключен] [закрыт для гостей] / Иногда подвисает Low Level Keyboard Hook, в чём может быть проблема? / 3 сообщений из 3, страница 1 из 1
30.04.2013, 13:25
    #38245187
HellFighter
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Иногда подвисает Low Level Keyboard Hook, в чём может быть проблема?
Добрый день,
я написал класс хукера клавиатуры и соответствующую DLL. Писал с расчётом на то, что в дальнейшем можно будет использовать написанное в любом приложение без модификаций. Таким образом DLL с моим классом общается с помощью именованного канала.
Код класса:
KeyboardHooker.h :
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
#include <Vcl.Forms.hpp>
#include <System.Classes.hpp>
#include "HOOKProc.h"
//---------------------------------------------------------------------------
class KeyboardHookerPipeMonitorThread : public TThread
{
private:

	HANDLE hNamedPipe;

	void (__fastcall*messageCallback) (TMessage, void*);
	void* pContext;

protected:

	void __fastcall Execute(); //override;

public:

	__fastcall KeyboardHookerPipeMonitorThread(HANDLE hNamedPipe, void (__fastcall*messageCallback) (TMessage, void*), void* pThis);
	__fastcall ~KeyboardHookerPipeMonitorThread();

};
//---------------------------------------------------------------------------
class KeyboardHooker
{
private:

	HHOOK hook;

	AnsiString lpszPipeName;
	HANDLE hNamedPipe;

	KeyboardHookerPipeMonitorThread* monitorThread;

	void (__fastcall*messageProcessor) (KBDHK, TMessage, void*);
	void* pContext;

	static void __fastcall localMessageProcessor(TMessage msg, void* pThis);

public:

	__fastcall KeyboardHooker(AnsiString appName);
	__fastcall ~KeyboardHooker();

	bool init(void (__fastcall*messageProcessor) (KBDHK, TMessage, void*), void* pThis);
	bool HOOK();
	bool UNHOOK();

	/*inline */static bool isKeyDownEvent(TMessage& msg);
	/*inline */static bool isKeyUpEvent(TMessage& msg);
	static KBDLLHOOKSTRUCT getKBDHOOKStruct(TMessage& msg);
};


KeyboardHooker.cpp :
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
#define _APPMAINCPP

#include "KeyboardHooker.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
//---------------------------------------------------------------------------
__fastcall KeyboardHooker::KeyboardHooker(AnsiString appName)
{
	this->lpszPipeName = "\\\\.\\pipe\\" + appName + L"_KeyboardHookerMessageTransferPipe_" + AnsiString(IntToHex(Random(0x7fffffff),8));
	while(FileExists(this->lpszPipeName))
		this->lpszPipeName += AnsiString(IntToHex(Random(0x7fffffff),8));

	this->hook = NULL;
	SetPipeName(lpszPipeName.c_str());
}
//---------------------------------------------------------------------------
__fastcall KeyboardHooker::~KeyboardHooker()
{

	this->UNHOOK();
	this->monitorThread->Terminate();

	CloseHandle(this->hNamedPipe);

}
//---------------------------------------------------------------------------
bool KeyboardHooker::init(void (__fastcall*messageProcessor) (KBDHK, TMessage, void*), void* pThis)
{
	if(!messageProcessor)
		return false;

	this->hNamedPipe = CreateNamedPipeA(
		this->lpszPipeName.c_str(),          					// адрес строки имени канала
		PIPE_ACCESS_INBOUND,      								// режим открытия канала
		PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE/* | PIPE_WAIT*/,	// режим работы канала
		1,   													// максимальное количество реализаций канала
		sizeof(TMessage)*10,  										// размер выходного буфера в байтах
		sizeof(TMessage)*10,   									// размер входного буфера в байтах
		NMPWAIT_USE_DEFAULT_WAIT, 								// время ожидания в миллисекундах
		NULL 													// адрес переменной для атрибутов защиты
	);

	if(hNamedPipe == INVALID_HANDLE_VALUE)
		return false;

	this->messageProcessor = messageProcessor;
	this->pContext = pThis;

	this->monitorThread = new KeyboardHookerPipeMonitorThread(this->hNamedPipe, &KeyboardHooker::localMessageProcessor, this);

	return true;
}
//---------------------------------------------------------------------------
bool KeyboardHooker::HOOK()
{

	if(!this->hook)
	{

		this->monitorThread->Resume();

		if(this->hook = SetWindowsHookEx(WH_KEYBOARD_LL,&hookProc,GetModuleHandle(L"HOOKProc"),0))
			return true;
		else
			return false;

	}

}
//---------------------------------------------------------------------------
bool KeyboardHooker::UNHOOK()
{

	if(this->hook)
	{

		this->monitorThread->Suspend();

		if(UnhookWindowsHookEx(this->hook))
		{

			this->hook = NULL;
			return true;

		}
		else
			return false;

	}

}
//---------------------------------------------------------------------------
void __fastcall KeyboardHooker::localMessageProcessor(TMessage msg, void* pThis)
{

	KeyboardHooker* kh = reinterpret_cast<KeyboardHooker*>(pThis);

	kh->messageProcessor(KBDHK(true,static_cast<ULONG>(reinterpret_cast<KBDLLHOOKSTRUCT*>(msg.LParam)->vkCode)), msg, kh->pContext);

}
//---------------------------------------------------------------------------
bool KeyboardHooker::isKeyDownEvent(TMessage& msg)
{
	return ((msg.Msg == HC_ACTION) && ((msg.WParam == WM_KEYDOWN) || (msg.WParam == WM_SYSKEYDOWN)));
}
//---------------------------------------------------------------------------
bool KeyboardHooker::isKeyUpEvent(TMessage& msg)
{
	return ((msg.Msg == HC_ACTION) && ((msg.WParam == WM_KEYUP) || (msg.WParam == WM_SYSKEYUP)));
}
//---------------------------------------------------------------------------
KBDLLHOOKSTRUCT KeyboardHooker::getKBDHOOKStruct(TMessage& msg)
{
	return *reinterpret_cast<KBDLLHOOKSTRUCT*>(msg.LParam);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
__fastcall KeyboardHookerPipeMonitorThread::KeyboardHookerPipeMonitorThread(HANDLE hNamedPipe, void (__fastcall*messageCallback) (TMessage, void*), void* pThis)
: TThread(true)
{
	this->FreeOnTerminate = true;

	this->hNamedPipe = hNamedPipe;

	this->messageCallback = messageCallback;
	this->pContext = pThis;
}
//---------------------------------------------------------------------------
__fastcall KeyboardHookerPipeMonitorThread::~KeyboardHookerPipeMonitorThread()
{
	//
}
//---------------------------------------------------------------------------
void __fastcall KeyboardHookerPipeMonitorThread::Execute()
{

	while(!this->Terminated)
	{
		try
		{

			// ожидать данных из пайпа
			BOOL fConnected = ConnectNamedPipe(this->hNamedPipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
			if(fConnected)
			{

				TMessage msg;
				DWORD rd = 0;
				if(ReadFile(this->hNamedPipe,&msg,sizeof(TMessage),&rd,NULL) && (rd == sizeof(TMessage)))
				{

						this->messageCallback(msg, this->pContext);

				}

				DisconnectNamedPipe(this->hNamedPipe);

			}

		} catch(...){}
	}

}


Код DLL:
HOOKProc.h :
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
#if defined(_DLLMAINCPP)
#  define DLL_SPEC __declspec(dllexport)
#else
# if defined(_APPMAINCPP)
#  define DLL_SPEC __declspec(dllimport)
# else
#  define DLL_SPEC
# endif
#endif

void DLL_SPEC __stdcall SetPipeName(const char* newPipeName);
long DLL_SPEC __stdcall hookProc(int code, UINT wParam, long lParam);


HOOKProc.cpp :
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
#define _DLLMAINCPP

#include <windows.h>
#include <Winapi.Messages.hpp>

#pragma hdrstop
#include "HOOKProc.h"
#pragma argsused

extern "C" int _libmain(unsigned long reason)
{
	return 1;
}

//---------------------------------------------------------------------------
LPCSTR pipeName = NULL;
//---------------------------------------------------------------------------
void __stdcall SetPipeName(const char* newPipeName)
{
	pipeName = newPipeName;
}
//---------------------------------------------------------------------------
long __stdcall hookProc(int code, UINT wParam, long lParam)
{

	if(pipeName && (code >= 0))
	{

		HANDLE hPipe;
		int count = 0;

		while(count < 3)
		{
			hPipe = CreateFileA(
				pipeName,   // pipe name
				GENERIC_WRITE,  // read and write access
				0,              // no sharing
				NULL,           // default security attributes
				OPEN_EXISTING,  // opens existing pipe
				0,              // default attributes
				NULL);          // no template file

			// Break if the pipe handle is valid.
			if (hPipe != INVALID_HANDLE_VALUE)
				break;

			// Exit if an error other than ERROR_PIPE_BUSY occurs.
			if (GetLastError() != ERROR_PIPE_BUSY)
				return 0;

			// All pipe instances are busy, so wait for 0.1 seconds.
			if (!WaitNamedPipeA(pipeName, 100))
				return 0;

			count++;

		}

		TMessage msg; msg.Msg = code; msg.WParam = wParam; msg.LParam = lParam;

		DWORD wr = 0;
		WriteFile(hPipe,&msg,sizeof(TMessage),&wr,NULL);

		CloseHandle(hPipe);

	}

	return CallNextHookEx(0,code,wParam,lParam);

}


Всё прекрасно работает, но иногда возникают ситуации когда приложение использующее данный класс не откликается на нажатия клавиш (система не подвисает, приложение на нажатия на иконку и тп отвечает нормально). Это длится несколько секунд и потом снова всё прекрасно работает. Постоянство явления такое: происходило раз 5-7 за пару недель постоянного использования.
В чём может быть дело? Я что-то не правильно написал?

(KBDHK тоже мой класс, не буду его тут описывать тк это не имеет отношения к делу. Внутри messageProcessor больших задержек нет, только проверка и сразу PostMessage )

PS: Windows 7 64bit, среда разработки RAD Studio: C++ Builder XE2

(Заодно может кто ответит почему нельзя создать метод inline static ?? Линкер в таком случае имплементацию не видит)
...
Рейтинг: 0 / 0
30.04.2013, 13:37
    #38245196
HellFighter
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Иногда подвисает Low Level Keyboard Hook, в чём может быть проблема?
Смотрю сейчас что некоторые комментарии в тексте программы немного не верные - это я просто с MSDN брал небольшие куски где английские комментарии и забыл их потереть
...
Рейтинг: 0 / 0
06.05.2013, 12:45
    #38248807
HellFighter
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Иногда подвисает Low Level Keyboard Hook, в чём может быть проблема?
Неужели никому ничего не сказать мне на эту тему??? (((( Ну хоть напишите что всё верно, если так считаете...
...
Рейтинг: 0 / 0
Форумы / C++ [игнор отключен] [закрыт для гостей] / Иногда подвисает Low Level Keyboard Hook, в чём может быть проблема? / 3 сообщений из 3, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]