How do i 'block' the WM_LBUTTONDOWN message to be fired?
The function is inside of a dll, I also tried to use LowLevelMouseProc but it does not work with error code: 1429 which means "global only hook".
I don't own the window in question.
I tried to return a WM_NULL in the code below, but it also doesn't work, what else i could try?
extern "C" __declspec(dllexport) LRESULT CALLBACK mouseHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
MSLLHOOKSTRUCT* mhs = nullptr;
int x = 0;
int y = 0;
std::wstringstream ss;
std::wstringstream ss2;
if (nCode == HC_ACTION)
{
switch (wParam)
{
case WM_LBUTTONDOWN:
ss << L"\nWM_LBUTTONDOWN " << wParam;
wParam = WM_NULL;
break;
case WM_LBUTTONUP:
ss << L"\nWM_LBUTTONUP " << wParam;
break;
case WM_MOUSEMOVE:
break;
case WM_RBUTTONDOWN:
ss << L"\nWM_RBUTTONDOWN: " << wParam;
break;
case WM_RBUTTONUP:
ss << L"\nWM_RBUTTONUP: " << wParam;
break;
default:
ss << L"\nUnknown msg: " << wParam;
break;
}
}
OutputDebugString(ss.str().c_str());
mhs = reinterpret_cast<MSLLHOOKSTRUCT*>(lParam);
x = mhs->pt.x;
y = mhs->pt.y;
ss2 << L"\nx: " << x << L" y: " << y;
OutputDebugString(ss2.str().c_str());
return CallNextHookEx(NULL, nCode, wParam, lParam);
Per the MouseProc callback function documentation:
If nCode is greater than or equal to zero, and the hook procedure did not process the message, it is highly recommended that you call CallNextHookEx and return the value it returns; otherwise, other applications that have installed WH_MOUSE hooks will not receive hook notifications and may behave incorrectly as a result. If the hook procedure processed the message, it may return a nonzero value to prevent the system from passing the message to the target window procedure.
As for your WH_MOUSE_LL error, you can't install that hook on a thread-specific basis, only globally.
Related
#include <iostream>
#include <windows.h>
LRESULT CALLBACK mouseProc(int nCode, WPARAM wParam, LPARAM lParam){
if(wParam == WM_MOUSEWHEEL){
std::cout << "wheel: " << GET_WHEEL_DELTA_WPARAM(wParam) << std::endl;
}else{
MOUSEHOOKSTRUCT* mouselparam = (MOUSEHOOKSTRUCT*)lParam;
std::cout << "etc: " << wParam << " - " << mouselparam->pt.x << "x" << mouselparam->pt.y << std::endl;
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
int main(int argc, char *argv[]) {
HHOOK hhkLowLevelMouse = SetWindowsHookEx(WH_MOUSE_LL, mouseProc, 0, 0);
MSG msg;
while (!GetMessage(&msg, NULL, NULL, NULL)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(hhkLowLevelMouse);
return 0;
}
This is the full code.
"etc:" works perfectly as I intended.
"wheel:" always outputs 0.
am i missing something?
Using HIWORD instead of GET_WHEEL_DELTA_WPARAM gives the same result.
GET_WHEEL_DELTA_WPARAM() only works with the wParam of a real WM_MOUSEWHEEL window message, not the wParam of a WH_MOUSE_LL hook.
In the hook, the wParam is just the message identifier by itself, nothing more. ALL of the mouse details are stored in a MSLLHOOKSTRUCT struct pointed by the lParam. Which you attempted to look at for all mouse messages other than WM_MOUSEWHEEL, but you are looking at the wrong struct (MOUSEHOOKSTRUCT is used by WH_MOUSE, not WH_MOUSE_LL).
Per the LowLevelMouseProc callback function documentation:
wParam [in]
Type: WPARAM
The identifier of the mouse message. This parameter can be one of the following messages: WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_MOUSEHWHEEL, WM_RBUTTONDOWN, or WM_RBUTTONUP.
lParam [in]
Type: LPARAM
A pointer to an MSLLHOOKSTRUCT structure.
And the MSLLHOOKSTRUCT structure documentation:
mouseData
Type: DWORD
If the message is WM_MOUSEWHEEL, the high-order word of this member is the wheel delta. The low-order word is reserved. A positive value indicates that the wheel was rotated forward, away from the user; a negative value indicates that the wheel was rotated backward, toward the user. One wheel click is defined as WHEEL_DELTA, which is 120.
Try this instead:
LRESULT CALLBACK mouseProc(int nCode, WPARAM wParam, LPARAM lParam){
if (nCode == HC_ACTION) {
MSLLHOOKSTRUCT* mouselparam = (MSLLHOOKSTRUCT*)lParam;
if (wParam == WM_MOUSEWHEEL) {
short delta = HIWORD(mouselparam->mouseData);
// alternatively, GET_WHEEL_DELTA_WPARAM() would also work here:
// short delta = GET_WHEEL_DELTA_WPARAM(mouselparam->mouseData);
std::cout << "wheel: " << delta << std::endl;
}else{
std::cout << "etc: " << wParam << " - " << mouselparam->pt.x << "x" << mouselparam->pt.y << std::endl;
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
I am trying to use Clipboard Format Listener for my C++ Console Application. The goal is to monitor every change in the clipboard. I create MessageOnly window, successfully call AddClipboardFormatListener in WM_CREATE, but never get WM_CLIPBOARDUPDATE message in WindowProc function.
#include <iostream>
#include "windows.h"
using namespace std;
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE:
if (AddClipboardFormatListener(hwnd))
cout << " Listener started" << endl;
else
cout << " Start listener failed" << endl;
break;
case WM_DESTROY:
if (RemoveClipboardFormatListener(hwnd))
cout << " Listener stopped" << endl;
else
cout << " Stop listener failed" << endl;
break;
case WM_CLIPBOARDUPDATE:
// Clipboard content has changed
cout << " Clipboard updated" << endl;
break;
default:
break;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
int main(int argc, char* argv[])
{
HWND hWindow = nullptr;
static const wchar_t* className = L"ClipboardListener";
WNDCLASSEX wx = {};
wx.cbSize = sizeof(WNDCLASSEX);
wx.lpfnWndProc = WindowProc;
wx.hInstance = GetModuleHandle(NULL);
wx.lpszClassName = className;
if (!RegisterClassEx(&wx)) {
cout << "Cannot register class" << endl;
}
else
{
hWindow = CreateWindowEx(
0,
className,
L"ClipboardListener",
0, 0, 0, 0, 0,
HWND_MESSAGE,
NULL, NULL, NULL);
}
if (!hWindow)
{
cout << "Cannot create window" << endl;
}
else
{
while (true)
{
// Peek for a WM_CLIPBOARDUPDATE message
MSG message = { 0 };
PeekMessage(&message, hWindow, WM_CLIPBOARDUPDATE, WM_CLIPBOARDUPDATE, PM_REMOVE);
if (message.message == WM_CLIPBOARDUPDATE)
{
cout << "Sample window received WM_CLIPBOARDUPDATE message" << endl;
}
}
}
cin.get();
DestroyWindow(hWindow);
return 0;
}
PeekMessage works well, but I don't want to use loop to receive messages.
If I delete PeekMessage or replace PM_REMOVE with PM_NOREMOVE, nothing changes.
Your message loop is wrong.
CreateWindowEx() sends a WM_CREATE message before exiting, which is why your WindowProc() receives that message.
However, PeekMessage() does not dispatch messages to windows, which is why your WindowProc() does not receive the WM_CLIPBOARDUPDATE messages. Your message loop needs to call DispatchMessage() for that. You should also be using GetMessage() instead of PeekMessage(), so that the loop makes the calling thread sleep when there are no messages to process.
A standard message loop looks more like this:
MSG message;
while (GetMessage(&message, NULL, 0, 0))
{
TranslateMessage(&message);
DispatchMessage(&message);
}
I have recently been experimenting with a little project during my limited free time to try and gain more experience and understanding with C++, but I've come to a roadblock in my current program:
I'm trying to create a global low-level mouse listener by using a windows hook, which most things seem fairly straight forward. However, identifying which X mouse button was clicked (MB4 or MB5) and which direction the scroll wheel was rolled is giving me a whole lot of headache.
According to the Microsoft docs, the current way I am trying to identify the appropriate X button clicked and scroll wheel direction is correct, but my implementation of it is not working.
I have been able to find one working solution to the X button issue (the last code segment post in this forum thread), but it seems a bit like jumping through unnecessary hoops when the Microsoft code segment is cleaner and should work.
Though C++ is not my most familiar language, I would like to continue to learn it and use it more often. I hope I'm just making a simple mistake, as this is the first time I have been working with Windows hooks. Thank you in advance for any advice or assistance anyone may be able to offer!
#include <iostream>
#include <windows.h>
static LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if(nCode >= 0)
{
switch(wParam)
{
case WM_LBUTTONDOWN:
system("CLS");
std::cout << "left mouse button down\n";
break;
case WM_LBUTTONUP:
std::cout << "left mouse button up\n";
break;
case WM_RBUTTONDOWN:
system("CLS");
std::cout << "right mouse button down\n";
break;
case WM_RBUTTONUP:
std::cout << "right mouse button up\n";
break;
case WM_MBUTTONDOWN:
system("CLS");
std::cout << "middle mouse button down\n";
break;
case WM_MBUTTONUP:
std::cout << "middle mouse button up\n";
break;
case WM_MOUSEWHEEL:
if(GET_WHEEL_DELTA_WPARAM(wParam) > 0)
std::cout << "mouse wheel scrolled up\n";
else if(GET_WHEEL_DELTA_WPARAM(wParam) < 0)
std::cout << "mouse wheel scrolled down\n";
else //always goes here
std::cout << "unknown mouse wheel scroll direction\n";
break;
case WM_XBUTTONDOWN:
system("CLS");
if(GET_XBUTTON_WPARAM(wParam) == XBUTTON1)
std::cout << "X1 mouse button down\n";
else if(GET_XBUTTON_WPARAM(wParam) == XBUTTON2)
std::cout << "X2 mouse button down\n";
else //always goes here
std::cout << "unknown X mouse button down\n";
break;
case WM_XBUTTONUP:
if(GET_XBUTTON_WPARAM(wParam) == XBUTTON1)
std::cout << "X1 mouse button up\n";
else if(GET_XBUTTON_WPARAM(wParam) == XBUTTON2)
std::cout << "X2 mouse button up\n";
else //always goes here
std::cout << "unknown X mouse button up\n";
break;
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
int main()
{
HHOOK mouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProc, NULL, 0);
MSG msg;
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(mouseHook);
return 0;
}
Please read the documentation:
LowLevelMouseProc callback function:
[...]
wParam [in] Type: WPARAM The identifier of the mouse
message. This parameter can be one of the following messages:
WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MOUSEMOVE, WM_MOUSEWHEEL,
WM_MOUSEHWHEEL, WM_RBUTTONDOWN, or WM_RBUTTONUP. lParam
[in] Type: LPARAM A pointer to an MSLLHOOKSTRUCT
structure.
So wParam can be WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_MOUSEHWHEEL, WM_RBUTTONDOWN, or WM_RBUTTONUP. There is no magic way to get any more information out of it. And if there were it would be undocumented and should be avoided.
lParam however points to a MSLLHOOKSTRUCT:
tagMSLLHOOKSTRUCT structure:
Contains information about a low-level mouse input event.
typedef struct tagMSLLHOOKSTRUCT {
POINT pt;
DWORD mouseData;
DWORD flags;
DWORD time;
ULONG_PTR dwExtraInfo;
} MSLLHOOKSTRUCT, *LPMSLLHOOKSTRUCT, *PMSLLHOOKSTRUCT;
[...]
mouseData Type: DWORD
If the message is WM_MOUSEWHEEL, the high-order word of this member is
the wheel delta. The low-order word is reserved. A positive value
indicates that the wheel was rotated forward, away from the user; a
negative value indicates that the wheel was rotated backward, toward
the user. One wheel click is defined as WHEEL_DELTA, which is 120.
If the message is WM_XBUTTONDOWN, WM_XBUTTONUP,
WM_XBUTTONDBLCLK, WM_NCXBUTTONDOWN, WM_NCXBUTTONUP, or
WM_NCXBUTTONDBLCLK, the high-order word specifies which X button was
pressed or released, and the low-order word is reserved. This value
can be one or more of the following values. Otherwise, mouseData is
not used. Value Meaning XBUTTON1 0x0001 The first X
button was pressed or released. XBUTTON2 0x0002 The second X
button was pressed or released.
So a simplified version of your callback could look like that:
#include <iostream>
#include <type_traits> // std::make_signed_t<>
#include <windows.h>
LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode != HC_ACTION) // Nothing to do :(
return CallNextHookEx(NULL, nCode, wParam, lParam);
MSLLHOOKSTRUCT *info = reinterpret_cast<MSLLHOOKSTRUCT*>(lParam);
char const *button_name[] = { "Left", "Right", "Middle", "X" };
enum { BTN_LEFT, BTN_RIGHT, BTN_MIDDLE, BTN_XBUTTON, BTN_NONE } button = BTN_NONE;
char const *up_down[] = { "up", "down" };
bool down = false;
switch (wParam)
{
case WM_LBUTTONDOWN: down = true;
case WM_LBUTTONUP: button = BTN_LEFT;
break;
case WM_RBUTTONDOWN: down = true;
case WM_RBUTTONUP: button = BTN_RIGHT;
break;
case WM_MBUTTONDOWN: down = true;
case WM_MBUTTONUP: button = BTN_MIDDLE;
break;
case WM_XBUTTONDOWN: down = true;
case WM_XBUTTONUP: button = BTN_XBUTTON;
break;
case WM_MOUSEWHEEL:
// the hi order word might be negative, but WORD is unsigned, so
// we need some signed type of an appropriate size:
down = static_cast<std::make_signed_t<WORD>>(HIWORD(info->mouseData)) < 0;
std::cout << "Mouse wheel scrolled " << up_down[down] << '\n';
break;
}
if (button != BTN_NONE) {
std::cout << button_name[button];
if (button == BTN_XBUTTON)
std::cout << HIWORD(info->mouseData);
std::cout << " mouse button " << up_down[down] << '\n';
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
Regarding your main():
Since your application has no windows, no messages will be sent to it and GetMessage() will never return. This renders the message pump youseless. A single call to GetMessage() is sufficient to give Windows the opportunity to call the installed hook callback. What is a problem though, is, that Code after the call to GetMessage() will never get executed because the only ways to end the program are closing the window or pressing Ctrl + C.
To make sure UnhookWindowsHookEx() gets called, I'd suggest setting a ConsoleCtrlHandler:
HHOOK hook = NULL;
BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
{
if (hook) {
std::cout << "Unhooking " << hook << '\n';
UnhookWindowsHookEx(hook);
hook = NULL; // ctrl_handler might be called multiple times
std::cout << "Bye :(";
std::cin.get(); // gives the user 5 seconds to read our last output
}
return TRUE;
}
int main()
{
SetConsoleCtrlHandler(ctrl_handler, TRUE);
hook = SetWindowsHookExW(WH_MOUSE_LL, MouseHookProc, nullptr, 0);
if (!hook) {
std::cerr << "SetWindowsHookExW() failed. Bye :(\n\n";
return EXIT_FAILURE;
}
std::cout << "Hook set: " << hook << '\n';
GetMessageW(nullptr, nullptr, 0, 0);
}
I am trying to create a dll where I can use to monitor all of system events (process creation, destruction, etc). This is what I have come up so far:
DLL main - the entry point of my DLL:
// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
#include "CBTHook.h"
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
CBT::CBTHook::SetHandle(hModule);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
DLL Header file
//Dll header file - function signatures
#ifdef CBTHOOKDLL_EXPORTS
#define CBTHOOKDLL_API __declspec(dllexport)
#else
#define CBTHOOKDLL_API __declspec(dllimport)
#endif
namespace CBT
{
class CBTHook
{
public:
CBTHook();
static void SetHandle(HINSTANCE handle);
void InstallHook();
void UnistallHook();
LRESULT CALLBACK HookProcedure(int nCode, WPARAM wparam, LPARAM lparam);
~CBTHook();
private:
static HINSTANCE currentProcessHandle;
HOOKPROC hkprcSysMsg;
static HHOOK hookID;
};
}
CBTHook.cpp
// CBTHook.cpp : Defines the exported functions for the DLL application.
//
#pragma once
#include "stdafx.h"
#include "CBTHook.h"
#include <Windows.h>
#include <iostream>
using namespace std;
namespace CBT
{
CBTHook::CBTHook()
{
}
void CBTHook::SetHandle(HINSTANCE handle)
{
currentProcessHandle = handle;
}
void CBTHook::InstallHook()
{
hookID = SetWindowsHookEx(WH_CBT,HookProcedure, currentProcessHandle, 0);
}
void CBTHook::UnistallHook()
{
UnhookWindowsHookEx(hookID);
}
LRESULT CALLBACK CBTHook::HookProcedure(int nCode, WPARAM wparam, LPARAM lparam)
{
if (nCode >= 0)
{
switch (nCode)
{
case HCBT_CREATEWND:
cout << "Created!~" << endl;
break;
case HCBT_DESTROYWND:
cout << "Destroied!~" << endl;
break;
default:
cout << "sth else" << endl;
break;
}
}
else
return CallNextHookEx(hookID, nCode, wparam, lparam);
}
}
Now the problem is that, SetWindowsHookEx wont accept the HookProcedure while as far as I have read and seen on the net the return value of the function in question is correct. I get the error:
error C3867: 'CBT::CBTHook::HookProcedure': function call missing argument list; use '&CBT::CBTHook::HookProcedure' to create a pointer to member
Doing as suggested by above doesn't solve the problem either!
What am I missing here?
Your hook procedure must be a free function or a static class method. If you want to call a class instance method, you need to wrap that call in one of the above.
Edit:
To set a hook you need no classes. This is a basic example. Every other problem stems from your use of a class. If you want to use a class, make sure you know how to do it. If you are unsure, C++ is not Java. You don't need to use a class if it works just perfectly without.
Example:
#include "stdafx.h"
HHOOK hHook;
BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved)
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
hHook = SetWindowsHookEx(WH_CBT, HookProcedure, hModule, 0);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
LRESULT CALLBACK HookProcedure(int nCode, WPARAM wparam, LPARAM lparam)
{
if (nCode >= 0)
{
switch (nCode)
{
case HCBT_CREATEWND:
cout << "Created!~" << endl;
break;
case HCBT_DESTROYWND:
cout << "Destroied!~" << endl;
break;
default:
cout << "sth else" << endl;
break;
}
}
else
return CallNextHookEx(hHook, nCode, wparam, lparam);
}
I'll preface this with saying that I am new to win32 programming.
I'm creating a global keyboard hook using a .dll, I have put in install and uninstall functions to handle the actual setting and removing of the keyboard hook.
#pragma comment(linker, "/SECTION:.SHARED,RWS")
#pragma data_seg(".SHARED")
static HHOOK hk=NULL;
//static CMyFile *pLF;
#pragma data_seg()
HINSTANCE hins = NULL;
__declspec( dllexport ) LRESULT Install(){
std::cout << "Installing" << std::endl;
hk = SetWindowsHookEx(WH_KEYBOARD_LL,EventAnalysis::KeystrokeAnalysis::KeyboardCallback,hins,0);
if(hk == NULL){
std::cout << "Hook creation failed! - " << GetLastError() << std::endl;
}
return 0;
}
__declspec(dllexport) BOOL CALLBACK UnInstall()
{
std::cout << "UnInstalling" << std::endl;
return UnhookWindowsHookEx(hk);
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
hins = (HINSTANCE) hModule;
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
So now that I have my .dll, I created a simple executable that loads the library and installs the hooks:
int _tmain(int argc, _TCHAR* argv[])
{
auto funHandle = LoadLibrary(L"C:\\Users\\tprodanov\\Documents\\visual studio 2010\\Projects\\HaveFun\\Release\\HaveFun.dll");
if(funHandle == NULL){
std::cout << "Library load failed! - " << GetLastError() << std::endl;
}
auto Install = (LRESULT(*)()) GetProcAddress(funHandle, "?Install##YAJXZ");
if(Install == NULL){
std::cout << "Procedure load failed! - " << GetLastError() << std::endl;
}
Install();
MSG Msg;
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
auto Uninstall = (BOOL(*)()) GetProcAddress(funHandle, "?UnInstall##YGHXZ");
if(Uninstall == NULL){
std::cout << "Procedure load failed! - " << GetLastError() << std::endl;
}
Uninstall();
return 0;
}
What I find curious is that the behavior of my program is as expected in its current state (and also if instead of a message loop I just pop out a MessageBox() that waits for the user to click OK), but it doesn't work if I use std::cin.get() or an empty while loop. Can someone please explain why this is the behavior?
Also as a followup question - the KeyboardCallback function just prints to the console "Key Pressed".
LRESULT CALLBACK EventAnalysis::KeystrokeAnalysis::KeyboardCallback(int nCode, WPARAM wParam, LPARAM lParam){
std::cout << "Key pressed" << std::endl;
return CallNextHookEx(NULL,nCode,wParam,lParam);
}
I expected that this will be printed only when I press keys when focused on the console window, but even if I type in notepad the "Key Pressed" messages show up in my executable that called the Install function of the .dll. I don't understand this, since as far as I understood the dynamic library is loaded independently in every process, so every process has its own copy of the KeyboardCallback function and it will try to print to the foreground window's console.
The documentation makes it clear what is happening:
This hook is called in the context of the thread that installed it. The call is made by sending a message to the thread that installed the hook. Therefore, the thread that installed the hook must have a message loop.
The hook is installed by the call you made to Install. And so in the same thread that makes that call you need to run a message loop.
As for why showing a message box influences things, a message box operates by running a modal message loop. And that message loop will dispatch the hook messages.
And for the followup question, again the documentation has the answer:
The system calls this function every time a new keyboard input event is about to be posted into a thread input queue.
When it says posted into a thread input queue it means any thread input queue.
Or in the remarks to the documentation of SetWindowsHookEx look at the list of the various hook types, and their scope. The WH_KEYBOARD_LL is listed as a global hook.
Note also that WH_KEYBOARD_LL is a low-level hook and so does not result in the DLL being injected into another process. In fact your code is overly complex. You simply do not need a DLL here at all. You can get it all going with a call to SetWindowsHookEx from your executable that passes a callback function in that same executable.
Here's a minimal sample program that demonstrates all this:
#include <Windows.h>
#include <iostream>
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
std::cout << "Key pressed" << std::endl;
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
int main(int argc, char* argv[])
{
std::cout << "Installing" << std::endl;
HHOOK hk;
hk = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, NULL, 0);
MSG Msg;
while (GetMessage(&Msg, NULL, 0, 0))
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
std::cout << "UnInstalling" << std::endl;
UnhookWindowsHookEx(hk);
return 0;
}