how to capture system-menu event in console application in windows? - c++

It's easy to get system menu on console application (GetSystemMenu) and add some own entries (AppendMenu). But then these menu items are useless for the app. Is there any way to get into message stream that would identify what menu item was clicked ?
I've tried to hook to console window but without any result, I mean the WH_SYSMSGFILTER, all is compiling ok but there are no messages shown the hook function is not run by the system.
Next thing was ReadConsoleInput and this works partially, that is it shows mouse events on the system menu, but there is no information in MENU_EVENT_RECORD structure about what menu item was clicked.
These are my attempts all in one snippet, here the console should be flooded with messages, but only those from ReadConsoleInput appear, but these doesn't contain any useful information. No matter if user clicks on first or second added menu item there are only two codes shown 278 (0x116) WM_INITMENU and 287 (0x11F) WM_MENUSELECT, but there is no way I know to get to the wParam of WM_MENUSELECT message.
#include <windows.h>
#include <stdio.h>
HHOOK sysMsgFilterHook;
LRESULT CALLBACK SysMsgFilterCallback(int nCode, WPARAM wParam, LPARAM lParam) {
printf("%i\n", nCode);
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
static LRESULT CALLBACK consoleWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
printf("%u\n", uMsg);
WNDPROC origProc = (WNDPROC) GetProp(hWnd, "origProc");
return CallWindowProc(origProc, hWnd, uMsg, wParam, lParam );
}
int main() {
SetLastError(0);
HWND console_hwnd = GetConsoleWindow();
HMENU console_hMenu = GetSystemMenu(console_hwnd, FALSE);
HINSTANCE console_hinstance = (HINSTANCE)GetWindowLong(console_hwnd, GWL_HINSTANCE);
DWORD console_processid = GetWindowThreadProcessId(console_hwnd, NULL);
HANDLE console_input_handle = GetStdHandle(STD_INPUT_HANDLE);
AppendMenu(console_hMenu, MF_STRING | MF_CHECKED, NULL, "test menu item");
AppendMenu(console_hMenu, MF_STRING | MF_CHECKED, NULL, "yet another menu item");
WNDPROC origProc = (WNDPROC)SetWindowLongPtr(console_hwnd, GWL_WNDPROC, (LONG_PTR)&consoleWndProc);
SetProp(console_hwnd, "origProc", (HANDLE)origProc);
sysMsgFilterHook = SetWindowsHookEx(
WH_SYSMSGFILTER,
(HOOKPROC)SysMsgFilterCallback,
console_hinstance,
console_processid
);
DWORD numEvents = 0;
INPUT_RECORD input;
while(ReadConsoleInput(console_input_handle, &input, 1, &numEvents)) {
//printf("input.EventType: %i\n", input.EventType);
if (input.EventType == MENU_EVENT) {
printf("input.Event.MenuEvent.dwCommandId %i\n", input.Event.MenuEvent.dwCommandId);
}
}
//printf("GetLastError: %lu\n", GetLastError());
UnhookWindowsHookEx(sysMsgFilterHook);
system("pause");
return 0;
}
I've succeeded with creating hook for mouse events, that is WH_MOUSE_LL. But all other hooks do not work.
What I intend to accomplish is to get some sort of WM_MENUCOMMAND message and then get rest with GetMenuItemInfo.
I've heard that the hooking procedure should be in another dll, but how to do that ? are there any working snippets ?

Related

Make a event for a mouse button even if application is minimized

I want to make an application that responds to a mouse button so I done this:
case WM_LBUTTONDOWN:
MessageBox(
NULL,
(LPCWSTR)L"HALLOOOO",
(LPCWSTR)L"Worked",
MB_ICONASTERISK | MB_OK | MB_DEFBUTTON2
);
break;
but the problem is that this only works if the user clicks on the window and I want it to work even with the window minimized
this work even if the application is minimized
GetKeyState(VK_LBUTTON);
but if I put this in a loop if I press it once it will detect 1 million times because it will just check if the key is down and if I add delay using Sleep(250) it may work but sometimes it will not detect anything even if the user pressed the key
I want my app to be able to detect if a key is pressed even if it's minimized how can I do this?
Since you already have a window, call SetWindowsHookEx with WH_MOUSE_LL.
The API is documented here and the parameters are explained.
HHOOK SetWindowsHookExW(
[in] int idHook,
[in] HOOKPROC lpfn,
[in] HINSTANCE hmod,
[in] DWORD dwThreadId
);
The lpfn hook procedure can be defined as follows:
HWND hmain_window;
HHOOK hhook;
LRESULT CALLBACK mouse_proc(int code, WPARAM wparam, LPARAM lparam)
{
if (code == HC_ACTION && lparam)
{
if (wparam == WM_LBUTTONDOWN)
{
//MOUSEHOOKSTRUCT* mstruct = (MOUSEHOOKSTRUCT*)lparam;
static int i = 0;
std::wstring str = L"mouse down " + std::to_wstring(i++);
SetWindowText(hmain_window, str.c_str());
}
}
return CallNextHookEx(hhook, code, wparam, lparam);
}
int APIENTRY wWinMain(HINSTANCE hinst, HINSTANCE, LPWSTR, int)
{
...
RegisterClassEx(...);
hmain_window = CreateWindow(...);
hhook = SetWindowsHookEx(WH_MOUSE_LL, mouse_proc, hinst, 0);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(hhook);
return 0;
}
You can try SetWindowsHookEx with parameter WH_MOUSE_LL or WH_MOUSE.
This article shows how to install a keyboard hook. You can replace WH_KEYBOARD with WH_MOUSE to install a mouse hook and use this document to handle the callback.

SetWindowsHookEx stops receiving WH_MOUSE_LL events when window focus lost

I have an SDL2 program that opens an SDL window. In the main I create a hook for mouse events as
hMSHook = SetWindowsHookEx(WH_MOUSE_LL, MouseProc, NULL, NULL);
while outside of the main I have the custom mouse event handler
HHOOK hMSHook;
int xPosAbsolute = 0;
int yPosAbsolute = 0;
LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HC_ACTION)
{
auto &ms = *(const MOUSEHOOKSTRUCT *)lParam;
if (wParam == WM_MOUSEMOVE)
{
xPosAbsolute = ms.pt.x;
yPosAbsolute = ms.pt.y;
}
}
return CallNextHookEx(hMSHook, nCode, wParam, lParam);
}
When the window is in focus, the mouse coordinates xPosAbsolute and yPosAbsolute are properly updated as the mouse moves. However, if another window receives focus, these variables stop being updated.
My question is, how do I make SetWindowsHookEx() continue receiving WH_MOUSE_LL events while my window is not in focus?
EDIT:
Actually, as it turns out, SetWindowsHookEx only stopped receiving event updates when the window focus was lost to another window that was launched as administrator, while the SDL2 window of this program was launched as a regular user. Once the current program is launched as administrator as well, all updates continue to come in (using the above code), even when window focus is lost. So this turned out to be a non-issue.
Focus is not required but keep pumping messages is required.
The following is a mini Win32 window application with low level hook you can refer to. It will receive WM_MOUSEMOVE message in all existing threads running in the same desktop as the calling thread regardless of which window holds the focus.
LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HC_ACTION)
{
auto& ms = *(const MOUSEHOOKSTRUCT*)lParam;
if (wParam == WM_MOUSEMOVE)
{
OutputDebugString(L"\n WM_MOUSEMOVE \n");
OutputDebugStringA(to_string(counter++).c_str());
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
return DefWindowProc(hWnd, message, wParam, lParam);
}
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
HHOOK hMSHook = SetWindowsHookEx(WH_MOUSE_LL, MouseProc, NULL, NULL);
WNDCLASSEXW wcex = {0};
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.lpfnWndProc = WndProc;
wcex.hInstance = hInstance;
wcex.lpszClassName = szWindowClass;
RegisterClassExW(&wcex);
HWND hWnd = CreateWindowW(szWindowClass, L"test", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
MSG msg;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
}

Confusion about mouse hooks in c++

I am trying to get global mouse position. I have a hook working that can get the mouse position, however it only has access to it inside the hook code. Trying to access the data inside main doesn't work.
The best way to explain this is with code:
LRESULT CALLBACK mouseHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
PMSLLHOOKSTRUCT p = (PMSLLHOOKSTRUCT) lParam;
position.x = p->pt.x;
position.y = p->pt.y;
std::cout<<position.x<<std::endl;
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
int WINAPI WinMain (HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpszArgument,int nCmdShow)
{
HHOOK mouseHook = SetWindowsHookEx(WH_MOUSE_LL,mouseHookProc,hInstance,NULL);
MessageBox(NULL, "Press OK to close.", "", MB_OK);
return 0;
}
With the above code, moving the mouse will show the new position in the console window. However, if I put the std::cout<<position.x<<std::endl; inside of main, it will just say 0. position is a global variable.
Code when the output is inside of main:
LRESULT CALLBACK mouseHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
PMSLLHOOKSTRUCT p = (PMSLLHOOKSTRUCT) lParam;
position.x = p->pt.x;
position.y = p->pt.y;
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
int WINAPI WinMain (HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpszArgument,int nCmdShow)
{
HHOOK mouseHook = SetWindowsHookEx(WH_MOUSE_LL,mouseHookProc,hInstance,NULL);
for(;;)
{
std::cout<<position.x<<std::endl;
}
MessageBox(NULL, "Press OK to close.", "", MB_OK);
return 0;
}
The first chunk of code works fine, it detects the mouse position, I just don't know how to get the x,y data into my main.
re this posted code:
LRESULT CALLBACK mouseHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
PMSLLHOOKSTRUCT p = (PMSLLHOOKSTRUCT) lParam;
position.x = p->pt.x;
position.y = p->pt.y;
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
int WINAPI WinMain (HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpszArgument,int nCmdShow)
{
HHOOK mouseHook = SetWindowsHookEx(WH_MOUSE_LL,mouseHookProc,hInstance,NULL);
std::cout<<position.x<<std::endl;
MessageBox(NULL, "Press OK to close.", "", MB_OK);
return 0;
}
Here's what the main function specifies should happen:
First, a call to SetWindowsHookEx (this happens once).
Then, outputting position (this happens once).
Then, displaying a MessageBox (this happens once).
That's all.
During the call to MessageBox the hook procedure is called (whenever you move your mouse), but it doesn't do anything visible, just an internal update.
Why did you expect more?
How to fix:
Instead of relying on the internal message loop in MessageBox, which doesn't do any output, code up your own.
Not to do with functionality, but just because the current code is like very dirty clothing that does serve its purpose but feels ungood to wear: replace Microsoft's WinMain monstrosity with a standard C and C++ main.
For global hook the hook procedure mouseHookProc should be in a DLL so that it can be injected into processes.
Check this:
http://www.codeproject.com/Articles/1037/Hooks-and-DLLs

Global Keyboard Hook Spy?

I'm writing up a quick tool in C# thats meant to sort of be a virtual keyboard. At the moment I am using SendKeys. I want to know if keyloggers would capture the keys so I found this code but i don't have mfc installed so i cant compile nor run it
How might i key if SendKeys is being logged by keyloggers or how do I get the code (snippet below) running in a single exe to test my code with?
#include <Windows.h>
static UINT uMsg = 0;
static HWND hWndMain = 0;
static HHOOK hKeyHook = NULL ;
#pragma data_seg()
HINSTANCE hInstance = 0;
HOOKPROC lpfnHookProc = 0;
LRESULT __stdcall KeyboardFunc (int nCode, WPARAM wParam, LPARAM lParam)
{
BOOL bPassToChain;
char szDebug [100];
// Check for exception cases...
if (nCode < 0)
return (CallNextHookEx (hKeyHook, nCode, wParam, lParam));
if (nCode == HC_NOREMOVE)
return (CallNextHookEx (hKeyHook, nCode, wParam, lParam));
switch (wParam)
{
case VK_F2:
wsprintf (szDebug, "F2 key message, lparam = 0x%X\n", lParam);
OutputDebugString (szDebug);
// only send on keydown, not keyup (autorepeat)
if (HIWORD (lParam) & 0xC000)
{
OutputDebugString ("F2 Keyup\n");
}
else
{
wsprintf (szDebug, "Sending F2 keydown message %d to hwnd 0x%X\n",
uMsg, hWndMain);
OutputDebugString (szDebug);
PostMessage (hWndMain, uMsg, 0, 0);
}
bPassToChain = FALSE;
break;
default :
bPassToChain = TRUE ;
break ;
}
if (bPassToChain)
return (CallNextHookEx (hKeyHook, nCode, wParam, lParam));
else
return TRUE ; // We have processed this key
}
BOOL __stdcall InstallExampleKeyboardHook (HWND hWnd, UINT uMyMsg)
{
hWndMain = hWnd ;
uMsg = uMyMsg;
lpfnHookProc = (HOOKPROC) KeyboardFunc ;
hKeyHook = SetWindowsHookEx (WH_KEYBOARD, lpfnHookProc, hInstance, NULL);
if (hKeyHook)
return TRUE ;
else
return FALSE ;
}
It's nothing about MFC. Straight native c++ code. If you have Visual Studio, you should be able to make a quick console c++ app, copy and paste that code in, and compile and test. If not, go and get the free but big Windows SDK. Less friendly then VS, but there's a compiler, so should get you in the right direction.
Low level hooks are not quite debugger friendly, so you might need to trace or log out some helpful statements.
Edited: to get the module handle, you will need something like this:
HookModule = LoadLibrary(ModulePath);
HookProc HookFunction = GetProcAddress(HookModule, "GetMessageCallBack");
GetMessageHookHandle = SetWindowsHookEx(HookType.WH_GETMESSAGE, HookFunction, HookModule, 0);

getting the 'name of the application' along with the key taps

To record the key taps I install the hook as :
BOOL WINAPI installHook(HINSTANCE hinstDLL, DWORD fwdReason, LPVOID lpvReserved) {
handleKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, hinstDLL, 0);
MSG msg;
while(GetMessage(&msg, NULL, 0, 0)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
// write here
}
Is there any way I can know the application name where the keys are currently being tapped ? Like I have opened notepad an writing something , can I get the name of the application which is notepad along with the key taps ? Same goes for some other application like mozilla firefox.
The inside of your hook should look like so:
static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
// if it is not a keydown event, continue the chain
if(HC_ACTION != nCode || WM_KEYDOWN != wParam)
return CallNextHookEx(0, nCode, wParam, lParam);
const KBDLLHOOKSTRUCT* messageInfo = reinterpret_cast<const KBDLLHOOKSTRUCT*>(lParam);
// add more code here...
// tell Windows we processed the hook
return 1;
}
messageinfo.vkCode will contain the key codes your looking for. The official list of these codes is at: http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731%28v=vs.85%29.aspx
Keys usually get typed into the foreground window (although sometimes strange window layouts happens). You can get the title of the foreground window like this:
TCHAR title[100]; // increase size for longer titles
GetWindowText(GetForegroundWindow(), title, 100);
If you want to get the name of the program instead, use:
TCHAR title[100]; // increase size for longer program names
GetWindowModuleFileName(GetForegroundWindow(), title, 100);
And, remember to add error checking and check the documentation.