CreateWindowEx, GetLastError, Windows 7, and XP oddities and odd behavior - winapi

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).

Related

Basic window creation

I have a problem handling a Windows window, even though I did it this way once before and it worked fine. After reading through the most common suggestions for this problem, it still resides. Could someone tell me why Input-handling is broken?
Intended Behaviour:
create a window titled 'FirstTry'
Make its background black, using PatBlt
Show a message box when the main loop is entered the first time, and after pressing 'w'.
Close the window when pressing either Alt+F4, Escape, or the Close-button, displaying a closing message.
Observed behaviour:
as intended
as intended
MessageBox shows up the first time, but is not retriggerable with 'w'
Window it not closable, except with TaskManager (one time it showed the 'closing Application'-MessageBox as intended, but only one time)
window draggable until the first 'entered loop'-MessageBox is closed, after that its fixed
little blue 'busy'-circle of windows10 is shown full-time, after the first MessageBox
Conclusion: The Message-handling is broken.
And i cannot figure out why...
System:
Windows 10, Version 1803 (Build 17134.81), 64-bit
Compiler from VS 2017 Community Edition:
vcvarsall.bat amd64
cl -MTd -nologo -FC -Zi -W4 -WX -wd4100 -wd4312 FirstTry.cpp /link User32.lib Gdi32.lib
#include "windows.h"
static bool bAppIsRunning = false;
static bool bMessageAlreadyShown = false;
LRESULT CALLBACK win_MainWNDCallback(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam){
LRESULT result = 0;
switch(msg){
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
case WM_KEYDOWN:
case WM_KEYUP:{
WPARAM vKeyCode = wParam;
bool bWasDown = ((lParam & (1 << 30)) != 0);
bool bIsDown = ((lParam & (1 << 31)) == 0);
if (bWasDown != bIsDown)
{
switch (vKeyCode)
{
case VK_ESCAPE:{
bAppIsRunning = false;
}break;
default:{
result = DefWindowProc(wnd,msg,wParam,lParam);
}break;
}
}
}break;
default:{
result = DefWindowProc(wnd,msg,wParam,lParam);
}break;
}
return result;
}
int CALLBACK WinMain(HINSTANCE HInstance, HINSTANCE HPrevInstance, LPSTR LpCmdLine, int NCmdShow){
WNDCLASSA wndCLass = {};
wndCLass.style = CS_HREDRAW | CS_VREDRAW;
wndCLass.lpfnWndProc = win_MainWNDCallback;
wndCLass.hInstance = HInstance;
wndCLass.lpszClassName = (LPCSTR)"WindowClass";
if(RegisterClassA(&wndCLass)){
HWND wnd = CreateWindowExA(
0, wndCLass.lpszClassName, (LPCSTR)"FirstTry",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT,
1240, 720,
0, 0, HInstance, 0);
if(wnd){
bAppIsRunning = true;
HDC DeviceContext = GetDC(wnd);
PatBlt(DeviceContext, 0, 0, 1240, 720, BLACKNESS);
ReleaseDC(wnd, DeviceContext);
while(bAppIsRunning){
if(!bMessageAlreadyShown){
MessageBoxA(NULL, (LPCSTR)"Successfully entered loop.", (LPCSTR)"Success!", MB_ICONINFORMATION | MB_OK);
bMessageAlreadyShown = true;
}
MSG msg;
while(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)){
switch(msg.message){
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
case WM_KEYDOWN:
case WM_KEYUP:{
WPARAM vKeyCode = msg.wParam;
bool bWasDown = ((msg.lParam & (1<<30)) != 0);
bool bIsDown = ((msg.lParam & (1<<31)) != 0);
if(bIsDown != bWasDown){
switch(vKeyCode){
case 'W':{
bMessageAlreadyShown = false;
}break;
default:{
TranslateMessage(&msg);
DispatchMessageA(&msg);
}break;
}
}
}
}
}
}
MessageBoxA(NULL, (LPCSTR)"Closing Application.", (LPCSTR)"Bye bye!", MB_ICONINFORMATION | MB_OK);
}
}
return ERROR_SUCCESS;
}
The main problem with your code is that you are calling TranslateMessage() and DispatchMessage() only when you receive certain key press messages. You need to call them in your main message loop for ALL messages instead. And you should be processing ALL of the messages in your WndProc callback.
You are also using TCHAR-based APIs, but are misusing LPCTSTR typecasts. You need to use the TEXT() macro instead when casting string/char literals to TCHAR.
Try something more like this instead:
#include <windows.h>
static bool bMessageAlreadyShown = false;
LRESULT CALLBACK win_MainWNDCallback(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
case WM_KEYDOWN:
case WM_KEYUP: {
WPARAM vKeyCode = wParam;
bool bWasDown = ((lParam & (1 << 30)) != 0);
bool bIsDown = ((lParam & (1 << 31)) == 0);
if (bWasDown != bIsDown) {
switch (vKeyCode) {
case 'W':
case VK_ESCAPE:
DestroyWindow(wnd);
return 0;
}
}
break;
}
case WM_ERASEBKGND:
PatBlt((HDC)wParam, 0, 0, 1240, 720, BLACKNESS);
return 0;
}
return DefWindowProc(wnd, msg, wParam, lParam);;
}
int CALLBACK WinMain(HINSTANCE HInstance, HINSTANCE HPrevInstance, LPSTR LpCmdLine, int NCmdShow) {
WNDCLASS wndCLass = {};
wndCLass.style = CS_HREDRAW | CS_VREDRAW;
wndCLass.lpfnWndProc = win_MainWNDCallback;
wndCLass.hInstance = HInstance;
wndCLass.lpszClassName = TEXT("WindowClass");
if (RegisterClass(&wndCLass)) {
HWND wnd = CreateWindowEx( 0, wndCLass.lpszClassName, TEXT("FirstTry"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 1240, 720, 0, 0, HInstance, 0);
if (wnd) {
MSG msg;
while (GetMessage(&msg, 0, 0, 0)) {
if (!bMessageAlreadyShown) {
bMessageAlreadyShown = true;
MessageBox(NULL, TEXT("Successfully entered loop."), TEXT("Success!"), MB_ICONINFORMATION | MB_OK);
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
MessageBox(NULL, TEXT("Closing Application."), TEXT("Bye bye!"), MB_ICONINFORMATION | MB_OK);
return ERROR_SUCCESS;
}
Note that I removed your bAppIsRunning variable, as it has beecome redundant once the message loop processes the WM_QUIT message instead.
I also removed handling of ALT-F4, as the OS handles that for you automatically. It closes the window, triggering a WM_CLOSE message. By default, DefWindowProc() handles WM_CLOSE by destroying the window, which triggers a WM_DESTROY message.
I also added handling for WM_ERASEBKGND to draw a background on the window. Drawing from outside of the message loop is wrong. As soon as the window needs to be refreshed onscreen, any drawing you do is lost, so you have to redraw everything in response to WM_ERASEBKGND and WM_PAINT.

Under what conditions will SendMessageTimeout(...,SMTO_NORMAL,...) ignore the timeout parameter when sending to another process?

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.

Why PostMessage has no effect when called from within a global hotkey handler?

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

Windows Embedded does not honor ShutdownBlockReasonCreate

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:

SysAnimate32 on Windows 7 and 8

This code no longer works on Windows 7 or 8.
Aren't SysAnimate32 controls supported on them ?
Is there a way to make it work as it used to work on Windows XP ?
(I am required to write more details but I have no more details to talk about :)
thanks
#include <windows.h>
#include <CommCtrl.h>
HINSTANCE hInstance;
#define IDC_MYANIMATE 9
HWND CreateAnimationControl (HWND hParent)
{
HWND hAnimation = Animate_Create( hParent, IDC_MYANIMATE, ACS_AUTOPLAY | WS_BORDER | WS_CHILD, hInstance);
Animate_Open (hAnimation, "test.avi");
ShowWindow (hAnimation, SW_SHOW);
return hAnimation;
}
LRESULT CALLBACK WindowProcedure (HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
static HWND hAnimation = NULL;
switch (uiMsg)
{
case WM_DESTROY:
PostQuitMessage (0);
break;
case WM_CREATE:
hAnimation = CreateAnimationControl (hWnd);
break;
case WM_SHOWWINDOW:
if (wParam)
{
MoveWindow (hAnimation, 0, 0, 300, 300, TRUE);
Animate_Play (hAnimation, 0, -1, -1);
}
break;
}
return DefWindowProc (hWnd, uiMsg, wParam, lParam);
}
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpsCmdLine, int iCmdShow)
{
WNDCLASSEX WindowClass;
HWND hWnd;
MSG uMsg;
hInstance = GetModuleHandle (NULL);
WindowClass.cbClsExtra = 0;
WindowClass.cbSize = sizeof (WNDCLASSEX);
WindowClass.cbWndExtra = 0;
WindowClass.hbrBackground = CreateSolidBrush (RGB (0, 0, 0));
WindowClass.hCursor = LoadCursor (NULL, IDC_ARROW);
WindowClass.hIcon = LoadIcon (NULL, IDI_APPLICATION);
WindowClass.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
WindowClass.hInstance = hInstance;
WindowClass.lpfnWndProc = WindowProcedure;
WindowClass.lpszClassName = "1";
WindowClass.lpszMenuName = NULL;
WindowClass.style = 0;
if (!RegisterClassEx (&WindowClass))
{
MessageBox (NULL, "Window class registration has failed!", "Error:", MB_OK | MB_ICONERROR);
return 0;
}
hWnd = CreateWindow ("1", "Win32 Animation Testing", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL,
hInstance, NULL);
if( ! hWnd )
{
MessageBox (NULL, "Window creation has failed!", "Error:", MB_OK | MB_ICONERROR);
return 0;
}
ShowWindow( hWnd, SW_SHOW );
UpdateWindow( hWnd );
while( GetMessage( &uMsg, NULL, 0, 0 ) > 0 )
{
TranslateMessage( &uMsg );
DispatchMessage ( &uMsg );
}
return ( int ) uMsg.wParam;
}
No, that still works just fine when I tried your code on Windows 8, compiled with VS2012. A screenshot to prove it:
Notable is that your error checking is lacking, you don't pay attention to the return value of Animate_Open(). A FALSE return indicates that it could not open the .avi file. Many possible reasons, there's no better diagnostic from that function than "could not do it".
It was difficult to find a .avi file that it could handle, the control is stone-cold old and cannot handle but the simplest ones. In particular an .avi file that also has a audio track will not open, as documented by the MSDN Library. The test one I used was a very simple one I dug out of the Visual Studio image library, Animations/filecopy_16.avi.
So basic checks, after adding the error handling, is to ensure that the file is actually present in the same directory as your EXE and that it is a very simple .avi file that at least plays back in WMP.

Resources