To simplify the case, I edit the code from the Visual Studio New Projects/Visual C++/Windows Desktop/Windows Desktop Application. Just add RegisterHotKey and case WM_HOTKEY and hWnd_Main from InitInstance.
The MessageBox will appear as many times as I press Shift+Ctrl+Alt+Win+Z. I thought that the messagebox will block the message loop thread(i.e. MainThread in Visual studio Thread Window) and the second time I press Shift+Ctrl+Alt+Win+Z, the Message WM_HOTKEY should be waited in the message queue. How can a single thread simultaneously run multiple times? Is my understanding wrong?
How can I limit only one entry of MessageBox(hWnd_Main, _T("Test2"), _T("Test2"), NULL); ? I open a file after the messagebox, and find out it could open multiple times.
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance(hInstance, nCmdShow))
{
return FALSE;
}
RegisterHotKey(hWnd_Main, 0x666, MOD_ALT | MOD_CONTROL | MOD_SHIFT | MOD_WIN, 'Z');
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_HOTKEY:
{
UINT nID = LOWORD(wParam);
if (nID == 0x666)
{
printf("GetCurrentThreadId: %d\n",GetCurrentThreadId());
MessageBox(hWnd_Main, _T("Test"), _T("Test"), NULL);
MessageBox(hWnd_Main, _T("Test2"), _T("Test2"), NULL);
}
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Related
I want to break from the windows message loop. Just like C++ how to break message loop in windows hook . I came up with one solution, which works fine for Window Desktop Application, but fails for Console Application. How can this happen?
EDIT: I upload my codes to https://github.com/hellohawaii3/Experiment , clone it and then you can reproduce my problem quickly. Thanks!
1.Why I want to do so?
I am writing a console application. First, users are asked to set some options which determine app's behaviors. Then, the app start the message loop and monitor the input of the keyboard/mouse. Users may want to change the setting, so I want to enable users to press some hotkey, quit from the message loop and go back to the beginning of the application.
If you know any way to implement this function without worrying about breaking from the message loop, please tell me! However, I also want to know why my solution fails for console app and works well for desktop app. Thanks for your help!
2.What have I tried.
I use a bool variable 'recieve_quit'. When certain key is pressed on the keyboard, the variable is setting to True by the hook callback function. For every loop getting message, check the variable 'recieve_quit' first and quit when the variable is False.
3.Result of my experiment
For Console APP, The variable 'recieve_quit' is set correctly when certain key is pressed, however, the message loop continues.
For Windows Desktop APP with GUI, I can quit from the message loop as expected.
4.Experiment settings
I am using VS2019, C++, windows 10 home 1909.
I use dll inject to set hook for my console app.
5.My code
I provide toy example codes here, most of which is generated by Visual Studio automatically, do not bother if you think my codes are too loog.
(a)My console app
Console:
// Console.cpp
#include <iostream>
#include "dll_func.h"
#include <windows.h>
int main()
{
MSG msg;
HHOOK hhook_tmp2 = SetWindowsHookEx(WH_KEYBOARD_LL, HandleKeyboardEvent, hDllModule, 0);
while (recieve_quit == false)
{
if (GetMessage(&msg, nullptr, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
MessageBox(NULL, TEXT("APP QUIT"), TEXT(" "), MB_OK);
}
(b)my dll containing hook function
My dll_func.h file, following the doc https://learn.microsoft.com/en-us/cpp/build/walkthrough-creating-and-using-a-dynamic-link-library-cpp?view=msvc-160
#pragma once
#ifdef DLL1_EXPORTS
#define DLLFUNC_API __declspec(dllexport)
#else
#define DLLFUNC_API __declspec(dllimport)
#endif
#include "framework.h"
extern "C" DLLFUNC_API bool recieve_quit;
extern "C" DLLFUNC_API LRESULT CALLBACK HandleKeyboardEvent(int nCode, WPARAM wParam, LPARAM lParam);// refer to https://stackoverflow.com/a/60913531/9758790
extern "C" DLLFUNC_API HMODULE hDllModule;//or whatever name you like
My dll_func.cpp file, containing the definition of hook function.
#include "pch.h"
#include <windows.h>
#include "dll_func.h"
bool recieve_quit = false;
LRESULT CALLBACK HandleKeyboardEvent(int nCode, WPARAM wParam, LPARAM lParam)
{
PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT)lParam;
if (wParam == WM_KEYDOWN) {
if (p->vkCode == VK_F8) {
recieve_quit = true;
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
The dllmain.cpp is also modified a little after it is created by Visual Studio as suggested by https://stackoverflow.com/a/60913531/9758790 to get the hinstance of the dll for dll injection.
// dllmain.cpp
#include "pch.h"
#include "dll_func.h"
// refer to https://stackoverflow.com/a/60913531/9758790
HMODULE hDllModule;//or whatever name you like
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
hDllModule = hModule;
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
(c) My Desktop application.
I select 'Creating Windows Desktop Application' when created the solution with Visual Studio. Most of the codes is generated automatically by VS. The codes I added and modifed is surrounded by ***** in the codes.
// GUI.cpp
//
#include "framework.h"
#include "GUI.h"
#define MAX_LOADSTRING 100
HINSTANCE hInst;
WCHAR szTitle[MAX_LOADSTRING];
WCHAR szWindowClass[MAX_LOADSTRING];
// *********************** ADDED BY ME! ***********************
// same as dll_func.cpp
bool recieve_quit = false;
LRESULT CALLBACK HandleKeyboardEvent(int nCode, WPARAM wParam, LPARAM lParam)
{
//FILE* file;
//fopen_s(&file, "./temp0210222.txt", "a+");
//fprintf(file, "Function keyboard_hook called.n");
//fclose(file);
PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT)lParam;
if (wParam == WM_KEYDOWN) {
if (p->vkCode == VK_F8) {
recieve_quit = true;
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
// *********************** END OF MY CODES ***********************
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// *********************** ADDED BY ME! ***********************
HHOOK hhook_tmp2 = SetWindowsHookEx(WH_KEYBOARD_LL, HandleKeyboardEvent, hInst, 0);
// *********************** END OF MY CODES ***********************
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_GUI, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_GUI));
MSG msg;
// main message loop:
// *********************** MODIFIED BY ME! ***********************
//while (GetMessage(&msg, nullptr, 0, 0))
//{
// if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
// {
// TranslateMessage(&msg);
// DispatchMessage(&msg);
// }
//}
while (recieve_quit == false)
{
if (GetMessage(&msg, nullptr, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
MessageBox(NULL, TEXT("APP QUIT"), TEXT(" "), MB_OK);
// *********************** END OF MODIFICATION ***********************
return (int) msg.wParam;
}
//
// Function: MyRegisterClass()
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_GUI));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_GUI);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
//
// Function: InitInstance(HINSTANCE, int)
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance;
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//
// Function: WndProc(HWND, UINT, WPARAM, LPARAM)
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// "About"
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
(d)Tips for reproducing my results
For Console APP: Build a new console application solution named Console, and copy my codes to replace Console.cpp. Add a new project to this solution, select Create new project -> DLL, name it as Dll1. Create dll_func.h, dll_func.c, and copy my codes in. Do not forget to modify dllmain.cpp, too. Set the path of AdditionalIncludeDirectories, add dll1.lib to AdditionalDependencies. Set the path to dll and lib files too.
For Windows Desktop APP: Build a now Windows Desktop App solution, name it as GUI. Copy my codes in GUI.cpp and simply run it. Press key F8, the app will quit and pop up a message box as expected.
This post explains why console apps dont receive keyboard messages and how they can handle them:
does not go inside the Windows GetMessage loop on console application
In your console case execution enters GetMessage and never exits it. The hook receives a notification and correctly sets recieve_quit. Since the execution never exits GetMessage, recieve_quit is not checked.
This answer is about handling getting keypresses in a console app:
https://stackoverflow.com/a/6479673/4240951
In general - add a hidden window to your console app or check GetAsyncState of the needed key.
There is no need to set hooks when you have a message loop. You may check keypresses as follows:
while (recieve_quit == false)
{
if (GetMessage(&msg, nullptr, 0, 0)) {
if (msg.message == WM_KEYDOWN && msg.wParam == VK_F8)
recieve_quit = true;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Having such supers simple Win app:
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow) {
...
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance(hInstance, nCmdShow)) {
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_GL1WIN));
MSG msg;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0)) {
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_COMMAND: {
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId) {
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_CLOSE:
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
When the WM_CLOSE case is disabled (commented out) everything works OK - when i click the X button the window closes but when the WM_CLOSE case is enabled like in the above code the app seems to freeze - doesn't react when clicking the X button and i have to kill it from the task manager.
On WM_CLOSE the window should normally be destroyed with DestroyWindow, like:
case WM_CLOSE:
DestroyWindow(hWnd);
break;
In your case you just return without doing anything with that window, so it simple 'freezes'.
Without WM_CLOSE case, the message is passed to DefWindowProc that reacts to it by destroying the window. With WM_CLOSE case, you handle the message and don't pass it to DefWindowProc - then it's your responsibility to do something in response to that message.
I have windows application with this source code
#include <Windows.h>
#include <thread>
#include <chrono>
int WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int cmdShow)
{
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WinProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
switch (Message)
{
case WM_QUERYENDSESSION:
MessageBox(NULL, "Triggered?", "Message", 0);
AbortSystemShutdown(NULL);
return 0;
default:
return DefWindowProc(hWnd, Message, wParam, lParam);
}
return 0;
}
I need to know when the system is shutting down and prevent it, or at least send a message to the user.
It doesn't seem that my application is receiving the WM_QUERYENDSESSION message.
I also tried to use ShutdownBlockReasonCreate() but I don't have a HWND for a window.
How should I do this?
As stated in the reference for WM_QUERYENDSESSION:
A window receives this message through its WindowProc function.
You have a WindowProc but you are missing a window. A WindowProc must be associated with a window, otherwise it is not known to Windows. To associate a WindowProc with a window, you can call RegisterClassEx followed by CreateWindowEx. Specify the name of your newly created window class in the call to CreateWindowEx.
The window must be a top-level window. It can be invisible, but in this case the following applies (from Application Shutdown Changes in Windows Vista):
Also note that if your application has no visible top-level windows,
it must use this API [ShutdownBlockReasonCreate()] if it needs to successfully block shutdown. Such
applications will automatically be terminated if they block shutdown
without using the API.
Note that a message-only window will not receive WM_QUERYENDSESSION.
Working example:
#include <windows.h>
LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam );
int APIENTRY wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPWSTR lpCmdLine, int nCmdShow )
{
WNDCLASSEXW wx = { sizeof(wx) }; // set cbSize member and zero-initialize all other
wx.lpfnWndProc = WndProc;
wx.hInstance = hInstance;
wx.lpszClassName = L"MyWindowClass";
if( ! RegisterClassExW( &wx ) )
return 1; // TODO: improve error handling
HWND hWnd = CreateWindowExW( 0, wx.lpszClassName, L"My Application", 0, 0, 0, 0, 0,
NULL, NULL, NULL, NULL );
if( ! hWnd )
return 2; // TODO: improve error handling
MSG msg;
while( GetMessage( &msg, nullptr, 0, 0 ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
return static_cast<int>( msg.wParam );
}
LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
switch( message )
{
case WM_QUERYENDSESSION:
{
// Try to block shutdown.
ShutdownBlockReasonCreate( hWnd, L"I don't want to sleep (yet)!" );
return FALSE;
}
case WM_ENDSESSION:
{
// TODO: Always handle this message because shutdown can be forced
// even if we return FALSE from WM_QUERYENDSESSION!
return 0;
}
default:
{
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
return 0;
}
Further read:
Application Shutdown Changes in Windows Vista
Restart Manager - Guidelines for Applications
Shutting Down
I want to hook my KeyboardProc from dll into my created window using dll injection. I want to see message boxes when pressing keys with focused injected window, but my code is not working properly.
Injected window code:
#include <windows.h>
#include <iostream>
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (lParam)
{
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArgs, int nCmdShow)
{
HWND hwnd;
LPCTSTR className = L"WNDCLASS";
LPCTSTR windowName = L"Window";
WNDCLASSEX wcex;
memset(&wcex, 0, sizeof(wcex));
wcex.cbSize = sizeof(wcex);
wcex.hInstance = hInstance;
wcex.lpszClassName = className;
wcex.style = CS_DBLCLKS;
wcex.lpfnWndProc = WndProc;
wcex.hbrBackground = CreateSolidBrush(RGB(255, 255, 255));
if (!RegisterClassEx(&wcex))
{
return -1;
}
hwnd = CreateWindowEx(NULL, className, windowName, WS_OVERLAPPEDWINDOW, 0, 0, 500, 500, NULL, NULL, hInstance, NULL);
if (!hwnd)
{
return -2;
}
MSG msg;
ShowWindow(hwnd, SW_NORMAL);
UpdateWindow(hwnd);
while (GetMessage(&msg, hwnd, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return
msg.lParam;
}
dll code:
// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
#include <iostream>
#include <Windows.h>
#include <TlHelp32.h>
#include <tchar.h>
HHOOK hhkKb;
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (wParam == WM_KEYDOWN)
{
MessageBox(0, L"DOWN", L"keyboard key down in dll", MB_ICONINFORMATION);
}
else if (wParam == WM_KEYUP)
{
MessageBox(0, L"UP", L"keyboard key up in dll", MB_ICONINFORMATION);
}
return
CallNextHookEx(hhkKb, nCode, wParam, lParam);
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
HWND windowHandle = FindWindow(NULL, L"Window");
if (windowHandle == NULL)
{
MessageBox(NULL, L"Error", L"Handle is null", MB_ICONERROR);
return TRUE;
}
DWORD threadId = GetWindowThreadProcessId(windowHandle, NULL);
hhkKb = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, hModule, threadId);
MessageBox(NULL, L"Success", L"Sucessfully injected dll", MB_ICONINFORMATION); //shows that message
break;
}
case DLL_PROCESS_DETACH:
{
UnhookWindowsHookEx(hhkKb);
break;
}
}
return TRUE;
}
I see "Sucessfully injected dll" message, but when I'm pressing keys into injected window, the KeyboardProc is not called, what I'm doing wrong?
using dll injection
unclear how you do this dll injection, but based on your previous question can assume that you manually inject your dll by CreateRemoteThread to LoadLibraryA. and in any case call SetWindowsHookEx from dll entry point is error by sense.
formally if thread, which call SetWindowsHookEx, exit - hooks will be automatically removed. so can say that on exit thread indirect call UnhookWindowsHookEx. don't sure are this clear documented, but can be view in next simply test
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
DbgPrint("%x>KeyboardProc(%x)\n", GetCurrentThreadId(), wParam);
return CallNextHookEx(0, nCode, wParam, lParam);
}
ULONG HookThread(PVOID threadId)
{
DbgPrint("%x>HookThread(%x)\n", GetCurrentThreadId(), (ULONG)(ULONG_PTR)threadId);
if (HHOOK hhk = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, (HINSTANCE)&__ImageBase, (ULONG)(ULONG_PTR)threadId))
{
Sleep(10000);//10 sec
//MessageBoxW(0,0,L"Close Me", MB_ICONWARNING);
}
return 0;
}
void test()
{
if (HANDLE hThread = CreateThread(0, 0, HookThread, (PVOID)(ULONG_PTR)GetCurrentThreadId(), 0,0))
{
CloseHandle(hThread);
MessageBoxW(0,0,L"Press Buttons here", MB_ICONINFORMATION);
}
}
first several seconds (or until you close MessageBoxW L"Close Me" if chose this variant) you can view dbgprint from KeyboardProc when you press buttons on first messagebox. after HookThread exit - no more KeyboardProc will be called.
so if you inject dll via CreateRemoteThread - this thread call LoadLibrary, then SetWindowsHookEx will be called in this thread, and finally thread just exit - and this remove effect of call SetWindowsHookEx - hook will be remove.
however if we use SetWindowsHookEx we not need manually inject dll to process. visa versa - this api special design for automatically inject dll to remote process. and of course you must not call SetWindowsHookEx from dll entry point - this is nonsense. you need call SetWindowsHookEx from remote process - as result your dll and will be injected to target process. reread Installing and Releasing Hook Procedures
I used the MSVC++ wizard to create a win32 application. I added a new menu resource and added the typical 'File'->'Exit' etc.. Then I added it to the main dialog under the properties in msvc++. When I run the form it shows the menu on the form but if I click on File it doesn't even do the hover and it doesn't show the popup of Exit. Its almost like it's disabled. I really didn't think I needed to add any code. Any help is appreciated. Thanks.
#include "stdafx.h"
#define MAX_LOADSTRING 100
struct _globals {
HINSTANCE hInst;
HWND hWnd;
} g;
LRESULT CALLBACK DialogProc(HWND, UINT, WPARAM, LPARAM);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
InitCommonControls();
g.hInst = hInstance;
g.hWnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, (DLGPROC)DialogProc);
if (g.hWnd == NULL) {
GetLastError();
return FALSE;
}
ShowWindow(g.hWnd, nCmdShow);
UpdateWindow(g.hWnd);
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_ACCELLS));
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
if (TranslateAccelerator(g.hWnd, hAccelTable, &msg))
continue;
if (IsDialogMessage(g.hWnd, &msg))
continue;
// process message
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK DialogProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
break;
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
switch (wmId)
{
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
Your DialogProc function looks more like a window procedure than a dialog procedure. Unlike window procedures, dalog procedures do not return LRESULT values, they return BOOL values, and they do not call DefWindowProc. There are some other differences as well.