More WinAPI problems
Hello everyone, I encountered a few more problems while creating my system-wide makro program. 1) I can't load my dll with LoadLibraryW, only LoadLibraryA. Why? 2) The LoadLibraryA function fails with Error Code 127 - I still get a Handle and can register my function as a LowLevelKeyboardProc, so I'm not really sure what went wrong. Google tells me Code 127 means my .dll is dependant on other .dlls which can't be found, but I have no idea which/why/how. 3) I intend to use the SendInput function to simulate Unicode character presses - to be precise, I want to inject this -- ಠ_ಠ -- whenever I press CTRL+SHIFT+ALT+Q (for example). Sadly SendInput gives me Error Code 87 (Incorrect Parameter), but I don't know what I'm doing wrong. I hope you guys can help me out! This is the .dll code: - CODE BEGIN - import std.c.windows.windows; import core.sys.windows.dll; import core.runtime; import std.stdio; //const auto INPUT_KEYBOARD = 1; //const auto KEYEVENTF_UNICODE = 4; extern (C) void gc_init(); extern (C) void gc_term(); extern (C) void _minit(); extern (C) void _moduleCtor(); extern (C) void _moduleDtor(); extern (Windows) struct KBDLLHOOKSTRUCT { DWORD vkCode; DWORD scanCode; DWORD flags; DWORD time; ULONG_PTR dwExtraInfo; }; extern (Windows) struct KEYBDINPUT { WORD wVk; WORD wScan; DWORD dwFlags; DWORD time; ULONG_PTR dwExtraInfo; }; extern (Windows) struct INPUT { DWORD type; KEYBDINPUT ki; }; extern (Windows) LRESULT CallNextHookEx( HANDLE hhk, int nCode, WPARAM wParam, LPARAM lParam ); extern (Windows) SHORT GetKeyState( int nVirtKey ); extern (Windows) UINT SendInput( UINT nInputs, INPUT* pInputs, int cbSize ); __gshared HINSTANCE g_hInst; extern (Windows) BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved) { g_hInst = hInstance; switch (ulReason) { case DLL_PROCESS_ATTACH: g_hInst = hInstance; Runtime.initialize; //dll_process_attach( hInstance, true ); break; case DLL_PROCESS_DETACH: //dll_process_detach( hInstance, true ); break; case DLL_THREAD_ATTACH: //dll_thread_attach( true, true ); break; case DLL_THREAD_DETACH: //dll_thread_detach( true, true ); break; default: return true; } return true; } extern (Windows) LRESULT LowLevelKeyboardProc(int code, WPARAM wParam, LPARAM lParam) { Runtime.initialize; //MessageBoxA(null, HALLO, OK,0); KBDLLHOOKSTRUCT* details = cast(KBDLLHOOKSTRUCT*) lParam; if(code == 0 wParam == WM_KEYDOWN) { if(details.vkCode == 0x51) { SHORT shiftkey = GetKeyState( VK_SHIFT ); SHORT ctrlkey = GetKeyState( VK_CONTROL ); SHORT altkey = GetKeyState ( VK_MENU ); if( ( shiftkey == -127 || shiftkey == -128 ) ( ctrlkey == -127 || ctrlkey == -128 ) ( altkey == -127 || altkey == -128 ) ) { //MessageBoxA(null, BOOM, OK,0); INPUT[3] toSend = new INPUT[3]; toSend[0].type = 1; toSend[0].ki.wVk = 0; toSend[0].ki.wScan = 0x0CA0; toSend[0].ki.dwFlags = 4; toSend[0].ki.time = 0; toSend[0].ki.dwExtraInfo = details.dwExtraInfo; toSend[1].type = 1; toSend[1].ki.wVk = 0; toSend[1].ki.wScan = 0x005F; toSend[1].ki.dwFlags = 4; toSend[1].ki.time = 0; toSend[1].ki.dwExtraInfo = details.dwExtraInfo; toSend[2].type = 1; toSend[2].ki.wVk = 0; toSend[2].ki.wScan = 0x0CA0; toSend[2].ki.dwFlags = 4; toSend[2].ki.time = 0; toSend[2].ki.dwExtraInfo = details.dwExtraInfo; SendInput( cast(UINT)3, toSend.ptr, toSend[0].sizeof ); writeln(GetLastError()); //MessageBoxA(null, cast(char*)GetLastError(), OK,0); return 1; }
WinAPI LowLevel Keyboard Hooks
Hello everyone, I had this great idea of writing a Program that intercepts all keyboard presses and modifies them in certain cases. I want to use it as some kind of global makro program to run in the background and for example allow me to easily post unicode smileys. This is where the probelms begin. If I understood the WinAPI doc correctly, I need to install a LowLevel Keyboard Hook using SetWindowsHookEx(). Unfortunately there are two versions of this function, SetWindowsHookExW and SetWindowsHookExA. What's the difference? The function to get called is passed as a parameter, but apparently it needs to be located in a .dll if using global hooks. So I need to first load my .dll file using LoadLibraryA( ) or LoadLibraryW( ), locate my function using GetProcAddress( ) and then set the hook using SetWindowsHookExW (or *-A)). Unfortunately for me, even the LoadLibrary function fails, returning Module could not be found. Now I'm 99% sure my .dll is crap because this is the first time I ever wrote one, but it DOES have a DllMain(), initializes the D Runtime and also has the other function I want to install the hook for. I'm hoping some bright minds here could help me out because google didn't, and I'm out of my depth. If you want me to, I'll post the source code, but I didn't want this post to get too big, which still did, but anyway.
Re: WinAPI LowLevel Keyboard Hooks
But what are the differences of loading the Unicode version vs. the ANSI version? I called the Unicode one because I figured that would be the sensible choice, since Unicode is the default for D (if I remember correctly). I have no clue what the actual effects of calling the wrong version would be. Anyway, here's the of my .dll: -- Code begin -- import std.c.windows.windows; import core.sys.windows.dll; import core.runtime; extern (C) void gc_init(); extern (C) void gc_term(); extern (C) void _minit(); extern (C) void _moduleCtor(); extern (C) void _moduleDtor(); extern (Windows) struct KBDLLHOOKSTRUCT { DWORD vkCode; DWORD scanCode; DWORD flags; DWORD time; ULONG_PTR dwExtraInfo; }; extern (Windows) LRESULT CallNextHookEx( int function() hhk, int nCode, WPARAM wParam, LPARAM lParam ); __gshared HINSTANCE g_hInst; extern (Windows) BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved) { return true; switch (ulReason) { case DLL_PROCESS_ATTACH: g_hInst = hInstance; Runtime.initialize; //dll_process_attach( hInstance, true ); break; case DLL_PROCESS_DETACH: dll_process_detach( hInstance, true ); break; case DLL_THREAD_ATTACH: dll_thread_attach( true, true ); break; case DLL_THREAD_DETACH: dll_thread_detach( true, true ); break; default: return true; } return true; } extern (Windows) LRESULT LowLevelKeyboardProc(int code, WPARAM wParam, LPARAM lParam) { KBDLLHOOKSTRUCT* details = cast(KBDLLHOOKSTRUCT*) lParam; MessageBoxA(null, cast(char *)WHOA, Error, MB_OK | MB_ICONEXCLAMATION); if(code == 0 wParam == WM_KEYDOWN) { if(details.vkCode == 0x41) { return 1; } } return CallNextHookEx(null, code, wParam, lParam); } -- Code End -- Lots of copypaste was used. I injected some senseless code to try and check if a specific function ever gets called, though I now realise the DllLoad itself is what fails. Haven't cleaned it back up yet, though. The .def file contains the following: (including newlines) -- .DEF BEGIN -- LIBRARY keydll.dll EXETYPE NT SUBSYSTEM WINDOWS CODE PRELOAD DATA PRELOAD -- .DEF END -- I compiled the dll using: dmd -ofkeydll.dll -L/IMPLIB keydll.d keydll.def No linker/compiler errors.
Re: WinAPI LowLevel Keyboard Hooks
I guess you have to 'export' the function: extern (Windows) export LRESULT LowLevelKeyboardProc(int code, WPARAM wParam, LPARAM lParam) and include EXPORTS LowLevelKeyboardProc in the .DEF file Thanks, I changed that. Also, I changed LoadLibraryW( ) to LoadLibraryA( ) in the main program and now it works (kinda). I feel stupid now, although I still don't get why it wouldn't work with LoadLibraryW.
Re: WinAPI LowLevel Keyboard Hooks
On Thursday, 19 July 2012 at 16:38:19 UTC, DLimited wrote: I guess you have to 'export' the function: extern (Windows) export LRESULT LowLevelKeyboardProc(int code, WPARAM wParam, LPARAM lParam) and include EXPORTS LowLevelKeyboardProc in the .DEF file Thanks, I changed that. Also, I changed LoadLibraryW( ) to LoadLibraryA( ) in the main program and now it works (kinda). I feel stupid now, although I still don't get why it wouldn't work with LoadLibraryW. Acutally, that was only the half-truth. The .dll seems to get loaded correctly ( GetLastError returns 0), but my keyboard-presses aren't captured at all. My system seems to freeze up for ~5sec, after which everything resumes. Any keyboard input seems to get buffered and is processed by my terminal after my program closes. Also I'm unsure about types because the often-used HHOOK is not defined with my imports, so I'm left guessing what it is. I used the type int function() instead (my best guess). Here's the code: --- CODE BEGIN - import std.c.windows.windows; import std.stdio; import core.thread; extern (C) void gc_init(); extern (C) void gc_term(); extern (C) void _minit(); extern (C) void _moduleCtor(); extern (C) void _moduleDtor(); extern (C) void _moduleUnitTests(); extern (Windows) int function() SetWindowsHookExA( int idHook, HOOKPROC lpfn, HINSTANCE hMod, DWORD dwThreadId ); extern (Windows) struct KBDLLHOOKSTRUCT { DWORD vkCode; DWORD scanCode; DWORD flags; DWORD time; ULONG_PTR dwExtraInfo; }; extern (Windows) LRESULT CallNextHookEx( int function() hhk, int nCode, WPARAM wParam, LPARAM lParam ); extern (Windows) bool UnhookWindowsHookEx( int function() hhk ); extern (Windows) HMODULE LoadLibraryA( LPCTSTR lpFileName ); extern (Windows) int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { int result; gc_init(); // initialize garbage collector _minit(); // initialize module constructor table try { _moduleCtor(); // call module constructors //_moduleUnitTests(); // run unit tests (optional) result = myWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow); _moduleDtor(); // call module destructors } catch (Exception o) // catch any uncaught exceptions { MessageBoxA(null, cast(char *)o.toString(), Error, MB_OK | MB_ICONEXCLAMATION); result = 0; // failed } gc_term(); // run finalizers; terminate garbage collector return result; } int myWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { HOOKPROC hkprcSysMsg; HINSTANCE hinstDLL; extern (Windows) int function() hhookSysMsg; hinstDLL = LoadLibraryA(cast(LPCTSTR)correct_absolute_path\\keydll.dll); writeln(GetLastError()); //returns 0 hkprcSysMsg = cast(HOOKPROC)GetProcAddress(hinstDLL, LowLevelKeyboardProc); writeln(GetLastError()); //return 0 hhookSysMsg = SetWindowsHookExA( 13, hkprcSysMsg, hinstDLL, 0); writeln(GetLastError()); // returns 0 aswell Thread.sleep( dur!(seconds)(10) ); UnhookWindowsHookEx( hhookSysMsg ); return 0; }
Re: WinAPI LowLevel Keyboard Hooks
On Thursday, 19 July 2012 at 17:35:29 UTC, dnewbie wrote: You don't see the WHOA message? Try this alias HANDLE HHOOK; No, I don't get any message after key-presses. I changed int function() to HANDLE, sadly it still doesn't work.
Re: WinAPI LowLevel Keyboard Hooks
On Thursday, 19 July 2012 at 18:40:15 UTC, dnewbie wrote: On Thursday, 19 July 2012 at 17:48:06 UTC, DLimited wrote: On Thursday, 19 July 2012 at 17:35:29 UTC, dnewbie wrote: You don't see the WHOA message? Try this alias HANDLE HHOOK; No, I don't get any message after key-presses. I changed int function() to HANDLE, sadly it still doesn't work. For some reason, it doesn't work with 'Thread.sleep' This works: http://dpaste.dzfl.pl/1e6e5960 It doesn't work for me. I can 1 Message Box from the Code in MyWinMain, but none for the Keystrokes. I registered a hook for Keyboard input, and that code is supposed to produce a message box aswell. The function for that is called LowLevelKeyboardProc and located in above-mentioned .dll file. The registering of the hook seems to pass, but the function never actually gets called.
Re: WinAPI LowLevel Keyboard Hooks
On Thursday, 19 July 2012 at 19:43:45 UTC, dnewbie wrote: On Thursday, 19 July 2012 at 18:56:15 UTC, DLimited wrote: On Thursday, 19 July 2012 at 18:40:15 UTC, dnewbie wrote: On Thursday, 19 July 2012 at 17:48:06 UTC, DLimited wrote: On Thursday, 19 July 2012 at 17:35:29 UTC, dnewbie wrote: You don't see the WHOA message? Try this alias HANDLE HHOOK; No, I don't get any message after key-presses. I changed int function() to HANDLE, sadly it still doesn't work. For some reason, it doesn't work with 'Thread.sleep' This works: http://dpaste.dzfl.pl/1e6e5960 It doesn't work for me. I can 1 Message Box from the Code in MyWinMain, but none for the Keystrokes. I registered a hook for Keyboard input, and that code is supposed to produce a message box aswell. The function for that is called LowLevelKeyboardProc and located in above-mentioned .dll file. The registering of the hook seems to pass, but the function never actually gets called. Did you add EXPORTS LowLevelKeyboardProc to the .DEF file? It works here. Yes, I did. Are the newlines important? And you really get a MessageBox per keystroke? I start as admin, disabled my AV but still, no success.
Re: WinAPI LowLevel Keyboard Hooks
On Thursday, 19 July 2012 at 20:06:55 UTC, dnewbie wrote: On Thursday, 19 July 2012 at 19:51:31 UTC, DLimited wrote: Yes, I did. Are the newlines important? And you really get a MessageBox per keystroke? I start as admin, disabled my AV but still, no success. Yes, I get 2 WHOA messages. One from the WM-KEYDOWN and the other from WM-KEYUP. Sorry I don't know what is wrong. THANK YOU for your help! It works now! I didn't call Runtime.initialize; in my exported function because I thought the runtime would already be initialized in the DllMain - seems like that is not the case. Wouldn't have thought of it if I hadn't had your sample code, though! Thanks a ton!