The following program works on Windows 7 but not on Windows 7 Embedded Standard Service Pack 1. It does not prevent the shutdown (e.g. shutdown /r /t 0) from happening.
This is a similar question as the one which is linked as duplicate. But that question has the accepted answer of "it does not work". I also provide sourcecode to a working solution in Windows 7 which just needs some adjustment for Windows Embedded.
Any ides how to get it working on Embedded? Or at least a hint where the Windows Docu points that difference out?
#include <windows.h>
#include <stdio.h>
const char g_szClassName[] = "myWindowClass";
// Step 6: the Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_QUERYENDSESSION:
OutputDebugStr("Got WM_QUERYENDSESSION message\n");
char buf[1024];
sprintf(buf, "Callback %d %d\n", wParam, lParam);
OutputDebugStr(buf);
return FALSE; // FALSE should prevent reboot
break;
case WM_ENDSESSION:
OutputDebugStr("Got WM_ENDSESSION message\n");
Sleep(5000); // Should never get here!
break;
case WM_CLOSE:
OutputDebugStr("Got WM_CLOSE message\n");
DestroyWindow(hwnd);
break;
case WM_DESTROY:
OutputDebugStr("Got WM_DESTROY message\n");
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;
//Step 1: Registering the Window Class
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&wc))
{
MessageBox(NULL, "Window Registration Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
// Step 2: Creating the Window
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
"The title of my window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
NULL, NULL, hInstance, NULL);
if(hwnd == NULL)
{
MessageBox(NULL, "Window Creation Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
// Step 3: We provide a reason for the shutdown prevention
BOOL ret = ShutdownBlockReasonCreate(hwnd, L"PreventShutdown running which prevents shutdown");
if(ret == FALSE)
{
MessageBox(NULL, "ShutdownBlockReasonCreate Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
// Step 4: We elevate the program to be asked as soon as possible to inhibit shutdown
ret = SetProcessShutdownParameters(0x4FF, SHUTDOWN_NORETRY)
if(ret == FALSE)
{
MessageBox(NULL, "ShutdownBlockReasonCreate Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
OutputDebugStr("Now starting message loop\n");
// Step 5: The Message Loop
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
We already have a canonical answer for this question, you'll find it here. Seven hundred views and half a year of researching this make this the best known answer, it can't be done.
Keep an eye on your existing question on the MSDN Forums.
I'll close with a few graphical explanations why this kind of feature is not implemented on an embedded operating system:
Related
Reading the documentation for SendMessageTimeout I thought the only time SendMessageTimeout would ignore the timeout parameter was when either:
The target window belongs to the same thread
Or "If the window receiving the message belongs to the same queue as the current thread[...]"
But I've encountered a case where either I'm misunderstanding what MSDN means by "same queue" or something else is going on.
When MSDN writes same queue, I'm thinking they're referring to the issues related to using AttachThreadInput, which I know from reading The Old New Thing is potentially dangerous.
I've tried my best at producing a minimal example, that hopefully still reflects the actual case I've encountered. I'm not looking for specific workarounds as I already have lots of options for avoiding this exact issue.
In short process A periodically broadcasts a message to all windows. Process B monitors process A and at some point decides to politely ask it to close. Process B uses SendMessageTimeout to allow for the case where process A has unsaved changes and puts up a dialog in its WM_CLOSE handler.
I've tested this on Win8.1 and Win10. Compiled using MSVC2015 Update 2 and 3, but I don't think anything is MSVC/MSVC version/C(++) specific.
Compile and run: cl /nologo /W4 /EHsc a.cpp user32.lib && cl /nologo /W4 /EHsc b.cpp user32.lib && a.exe && b.exe
This should bring up a "Waiting" dialog in process A. I was expecting process B to display an error dialog saying SendMessageTimeout failed, but it doesn't. It hangs until the dialog is closed in process A.
// a.cpp
#include <windows.h>
#define CLASS_NAME TEXT("A_WINDOW_CLASS")
LRESULT CALLBACK WndProc(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
static UINT uCommonMsg = RegisterWindowMessage(TEXT("CommonMsg"));
const int nTimerId = 100;
DWORD_PTR dwResult;
switch (uiMsg) {
case WM_CREATE:
return SetTimer(hwnd, nTimerId, 1000, nullptr);
case WM_DESTROY:
KillTimer(hwnd, nTimerId);
PostQuitMessage(0);
break;
case WM_TIMER:
SendMessageTimeout(HWND_BROADCAST, uCommonMsg, 0, 0, SMTO_NORMAL, 1000, &dwResult);
return 0;
case WM_CLOSE:
MessageBox(hwnd, TEXT("Waiting..."), CLASS_NAME, MB_OK);
break;
}
return DefWindowProc(hwnd, uiMsg, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hinst, HINSTANCE, LPSTR, int)
{
WNDCLASS wc = { 0 };
wc.lpfnWndProc = WndProc;
wc.hInstance = hinst;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszClassName = CLASS_NAME;
if (!RegisterClass(&wc)) return GetLastError();
HWND hwnd = CreateWindow(CLASS_NAME, CLASS_NAME, WS_VISIBLE|WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, hinst, 0);
if (!hwnd) return GetLastError();
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
// b.cpp
#include <windows.h>
HWND hwndAWindow;
int nReceived;
LRESULT CALLBACK WndProc(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam) {
static UINT uCommonMsg = RegisterWindowMessage(TEXT("CommonMsg"));
if (uiMsg == uCommonMsg) {
++nReceived;
return 0;
}
DWORD_PTR dwResult;
switch (uiMsg) {
case WM_CREATE: return uCommonMsg != 0;
case WM_DESTROY: PostQuitMessage(0); break;
case WM_USER:
// Ask window A to close
if (!SendMessageTimeout(hwndAWindow, WM_CLOSE, 0, 0, SMTO_NORMAL, 5000, &dwResult)) {
MessageBox(hwnd, TEXT("SendMessageTimeout failed"), TEXT("Error"), MB_ICONERROR|MB_OK);
}
SendMessage(hwnd, WM_CLOSE, 0, 0); // We're done
return 0;
}
return DefWindowProc(hwnd, uiMsg, wParam, lParam);
}
#define CLASS_NAME TEXT("B_WINDOW_CLASS")
int WINAPI WinMain(HINSTANCE hinst, HINSTANCE, LPSTR, int) {
hwndAWindow = FindWindow(TEXT("A_WINDOW_CLASS"), nullptr);
if (!hwndAWindow) return -1;
WNDCLASS wc = { 0 };
wc.lpfnWndProc = WndProc;
wc.hInstance = hinst;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszClassName = CLASS_NAME;
if (!RegisterClass(&wc)) return GetLastError();
HWND hwnd = CreateWindow(CLASS_NAME, CLASS_NAME, WS_VISIBLE|WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, hinst, 0);
if (!hwnd) return GetLastError();
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
// Once we're sure A is up and running ask window B to do its thing
if (nReceived) {
PostMessage(hwnd, WM_USER, 0, 0);
}
}
return 0;
}
You probably want
if (!SendMessageTimeout(hwndAWindow, WM_CLOSE, 0, 0, SMTO_NORMAL | SMTO_ABORTIFHUNG, 5000, &dwResult))
in b.cpp.
Also, WM_CLOSE can't be sent - it can only be posted. Sending WM_CLOSE cross-thread often ends up with an RPC_E_CANTCALLOUT_ININPUTSYNCCALL error.
A GUI app I'm writing does send a keydown event to another window, a cmd.exe.
PostMessage(hwnd, WM_KEYDOWN, VK_RETURN, 0);
The event is sent just fine when it's done on events like WM_CREATE, WM_KEYUP, etc (a new line appears in cmd.exe).
Then I setup a global hotkey with RegisterHotKey. In a WM_HOTKEY handler I successfully receive key presses but PostMessage has no effect anymore.
How to fix that?
Full example, minified as possible:
#include <iostream>
#include <Windows.h>
using namespace std;
const char g_szClassName[] = "myWindowClass";
BOOL CALLBACK enumWindows(HWND hwnd, LPARAM lParam) {
char winTitle[1024*10];
GetWindowText(hwnd, winTitle, sizeof(winTitle));
if (strstr(winTitle, "cmd.exe") != NULL) {
cout << "Sending a message to window " << hwnd << ": " << winTitle << endl;
PostMessage(hwnd, WM_KEYDOWN, VK_RETURN, 0);
}
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch(msg) {
case WM_CREATE:
// register hotkey ctrl+alt+s
RegisterHotKey(hwnd, 100, MOD_ALT | MOD_CONTROL, 'S');
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
EnumWindows(enumWindows, 0);
PostQuitMessage(0);
break;
case WM_HOTKEY:
// hotkey ctrl+alt+s fired
EnumWindows(enumWindows, 0);
break;
case WM_KEYUP:
EnumWindows(enumWindows, 0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
// just init stuff, do not waste your time
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
RegisterClassEx(&wc);
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, g_szClassName, "Test", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 240, 120, NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while(GetMessage(&Msg, NULL, 0, 0) > 0) {
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
Windows 7 64-bit
Raymond Chen has documented why this doesn't work the way you expect (PostMessage IS working just fine, but the response of the other window depends on actual keyboard state, just as I surmised in my comment). See his blog post:
You can't simulate keyboard input with PostMessage
It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
AVG says that the executable compiled from the code below is a high priority "Trojan horse PSW.Agent.AYRW". Is something wrong here, or is this just a false alarm?
#include <windows.h>
const char g_szClassName[] = "myWindowClass";
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_LBUTTONDOWN:
{
char szFileName[MAX_PATH];
HINSTANCE hInstance = GetModuleHandle(NULL);
GetModuleFileName(hInstance, szFileName, MAX_PATH);
MessageBox(hwnd, szFileName, "This program is:", MB_OK | MB_ICONINFORMATION);
}
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&wc))
{
MessageBox(NULL, "Window Registration Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
"The title of my window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
NULL, NULL, hInstance, NULL);
if(hwnd == NULL)
{
MessageBox(NULL, "Window Creation Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
Is this really creating a virus?
Edit: this is now that much more important because I can't even compile the program to its original location anymore without windows restricting my access. Grumble... AVG 2012 was so much better.
let AVG know that it's a false positive http://samplesubmit.avg.com/
The following code works on Window 7, but when I run it on Windows XP, it fails with an error message returned by windows: "The system can not find the file specified".
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include <uxtheme.h>
#include <string>
const char g_szClassName[] = "myWindowClass";
const char title[] = "Window Title\0";
COLORREF WinColor;
HFONT defaultFont;
NONCLIENTMETRICSA Metrics;
DWORD dwVersion;
DWORD dwMajorVersion;
DWORD dwMinorVersion;
HBRUSH hBrushColor;
bool LastError = false;
bool W32Error (const char * Msgtext);
// Step 4: the Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_NCCREATE:
{
Metrics.cbSize = sizeof(NONCLIENTMETRICS);
SystemParametersInfo (SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &Metrics, 0);
defaultFont = (HFONT) CreateFontIndirect (& Metrics.lfMessageFont);
return TRUE;
}
break;
case WM_CTLCOLORSTATIC: {
dwVersion = GetVersion();
dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
if ( (IsAppThemed()) && (dwMajorVersion < 6) ) {
WinColor = GetSysColor(COLOR_WINDOW);
SetBkColor((HDC)wParam, WinColor);
return (LRESULT)hBrushColor;
}
}
break;
case WM_CREATE: {
HWND hButton = CreateWindowEx(
0,
"BUTTON", "Button",
WS_TABSTOP |
WS_VISIBLE |
WS_CHILD |
BS_NOTIFY |
BS_PUSHBUTTON,
10, 10, 96, 32, hwnd,
(HMENU)50,
GetModuleHandle(NULL),
NULL);
if (W32Error ("Button Creation Failed\nReason:")) exit (1);
return TRUE;
}
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;
// Initialize common controls.
INITCOMMONCONTROLSEX icc;
icc.dwSize = sizeof(icc);
icc.dwICC = ICC_WIN95_CLASSES |
ICC_COOL_CLASSES |
ICC_INTERNET_CLASSES|
ICC_LINK_CLASS |
ICC_STANDARD_CLASSES|
ICC_PROGRESS_CLASS |
ICC_USEREX_CLASSES;
InitCommonControlsEx(&icc);
//Step 1: Registering the Window Class
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
// see if something is going on before the window registration takes place....
if (W32Error ("Previous Check for Error?\nReason:")) exit (1);
if(!RegisterClassEx(&wc))
{
MessageBox(NULL, "Window Registration Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
if (W32Error ("Window Registration Failed\nReason:")) exit (1);
// Step 2: Creating the Window
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
"The title of my window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
NULL, NULL, hInstance, NULL);
if (W32Error ("Window Creation Failed\nReason:")) exit (1);
if(hwnd == NULL)
{
MessageBox(NULL, "Window Creation Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
SendMessageA(hwnd, WM_SETFONT, WPARAM (defaultFont), TRUE);
SendMessageA(hwnd, WM_SETTEXT, WPARAM(NULL) , LPARAM (title));
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
// Step 3: The Message Loop
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
bool W32Error (const char * Msgtext)
{
LPTSTR errorText = NULL;
DWORD dwLastError = GetLastError();
if (!dwLastError) {
LastError = false;
return LastError;
}
// use system message tables to retrieve error text
// allocate buffer on local heap for error text
// Important! will fail otherwise, since we're not (and CANNOT) pass insertion parameters
FormatMessageA(
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, // unused with FORMAT_MESSAGE_FROM_SYSTEM
dwLastError,
MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&errorText, // output
0, // minimum size for output buffer
0); // arguments - see note
if ( NULL != errorText ) {
std::string Message;
Message += Msgtext;
Message += "\n";
Message += errorText;
MessageBoxA(NULL, (LPCSTR)Message.c_str(), "An Internal Error Occurred", MB_OK);
LocalFree(errorText);
errorText = NULL;
LastError = true;
} else {
LastError = false;
}
return LastError;
}
As an additional, I have a resource.rc and resource.h file linked in with winres that complies in a manifest.xml that provides a controls version 6 specification.
Ok, so here is the deal, This runs on Windows 7 without a hitch. And it runs on XP, unless I put in the line if (W32Error ("Window Registration Failed\nReason:")) exit (1);
(basically, it calls my error checking routine which includes GetLastError())
if(!RegisterClassEx(&wc))
{
MessageBox(NULL, "Window Registration Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
if (W32Error ("Window Registration Failed\nReason:")) exit (1);
When I include that line, I get an error "The system can not find the file specified." The return value back from RegisterClassEx does not go into the if block, so RegisterClassEx returns Ok.
This only happens on Windows XP, it works just fine on Windows 7. If I don't include this line, it works as if nothing is wrong.
The point of this sample is to get themes to work right on both XP and Windows 7. (not an easy task.)
Why is RegisterClassEx returning Ok, but generates an error for GetLastError on Windows XP and not on Windows 7?
Also, what file is it looking for anyway? I have seen other Google results say It has to do with a messed up message loop or window procedure, but that's not the case here.
General mistake... Due to MSDN you may check GetLastError only when RegisterClassEx "return value is zero". When RegisterClassEx or CreateWindowEx or any other functions are succeeded, GetLastError may return garbage, there is no guarantee that GetLastError will returns zero (if different behavior does not described in Return value section).
This program works well when the left mouse button is pressed in the window of application, but what i need is that the program also registers when the button is pressed out of the application. I am running under windows 7.
#include <windows.h>
const char g_szClassName[] = "myWindowClass";
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_LBUTTONDOWN:
{
char szFileName[MAX_PATH];
HINSTANCE hInstance = GetModuleHandle(NULL);
GetModuleFileName(hInstance, szFileName, MAX_PATH);
MessageBox(hwnd, szFileName, "This program is:",
MB_OK | MB_ICONINFORMATION);
}
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&wc))
{
MessageBox(NULL, "Window Registration Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
"The title of my window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
NULL, NULL, hInstance, NULL);
if(hwnd == NULL)
{
MessageBox(NULL, "Window Creation Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
You can try the Windows Raw Input API, which ignores focus.