|
30.04.2013, 13:25
#38245187
Ссылка:
Ссылка на сообщение:
Ссылка с названием темы:
Ссылка на профиль пользователя:
|
|
|
Участник
Сообщения: 122
Рейтинг:
0
/ 0
|
|
|
|
Добрый день,
я написал класс хукера клавиатуры и соответствующую DLL. Писал с расчётом на то, что в дальнейшем можно будет использовать написанное в любом приложение без модификаций. Таким образом DLL с моим классом общается с помощью именованного канала.
Код класса:
KeyboardHooker.h :
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 :
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 :
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 :
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 ?? Линкер в таком случае имплементацию не видит)
|
|
|