Win32 Subclassing - About Messages - winapi

So I'm practicing subclassing a predefined window class in Win32 so I can define my own custom message proc for the predefined classes (e.g. making a custom WndProc for a button class) and I got it to work for the most part but I can't get the WM_COMMAND messages to be automatically sent to the new message proc. I can set up a case in the parent window for WM_COMMAND and check the wParam then call the respective new message proc for the child window that sent the WM_COMMAND message but I would prefer for this to be done automatically like all the other commands. As far as I can tell all the other WM_'s I have tried in the custom message proc I defined get passed to it automatically from the parent window's message proc, but the WM_COMMAND messages won't unless I explicitly redirect them. I have a feeling WM_COMMAND messages will always be sent to the parent window when subclassing the way I have it set up, but if someone could explain why this is the case or what I would need to do in order to direct all messages belonging to the button window to the custom WndProc I defined, it would be much appreciated.
Code:
#include <Windows.h>
#include <windowsx.h>
#define IDC_BUTTON 0
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
LRESULT CALLBACK WndProcButton (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
HWND g_hwndButton = NULL;
WNDPROC g_wndProcButtonOrigianl = NULL;
BOOL g_bSeeingMouse = FALSE;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR szCmdLine, int iCmdShow)
{
static TCHAR szClassName[] = TEXT ("HelloWin") ;
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szClassName ;
if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("This program requires Windows NT!"),
szClassName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (szClassName, // window class name
TEXT ("The Hello Program"), // window caption
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // initial x position
CW_USEDEFAULT, // initial y position
CW_USEDEFAULT, // initial x size
CW_USEDEFAULT, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL) ; // creation parameters
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
LRESULT CALLBACK WndProcButton (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch( message )
{
case WM_COMMAND:
MessageBox( hwnd, TEXT( "Test box" ), TEXT( "Test box" ), MB_OK );
SetFocus( g_hwndButton );
break;
default:
if( !g_bSeeingMouse && GetCapture() == hwnd )
{
g_bSeeingMouse = TRUE;
SetWindowText( hwnd, L"Ok +mouse" );
}
else if( g_bSeeingMouse && GetCapture() != hwnd )
{
g_bSeeingMouse = FALSE;
SetWindowText( hwnd, L"Ok" );
}
break;
}
return CallWindowProc( g_wndProcButtonOrigianl, hwnd, message, wParam, lParam );
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc ;
PAINTSTRUCT ps ;
RECT rect ;
switch (message)
{
case WM_CREATE:
g_hwndButton = CreateWindow( L"Button", // predefined class
L"Ok", // button text
( WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON ), // styles
// Size and poition values are given explicitly, because
// the CW_USEDEFAULT constant gives zero values for buttons.
10, // starting x position
10, // starting y position
100, // button width
30, // button height
hwnd, // parent window
(HMENU)IDC_BUTTON, // no menu
(HINSTANCE)GetWindowLongPtr( hwnd, GWLP_HINSTANCE ),
NULL ); // pointer not needed
SetFocus( g_hwndButton );
g_wndProcButtonOrigianl = (WNDPROC)SetWindowLongPtr( g_hwndButton, GWLP_WNDPROC, (LONG_PTR)WndProcButton );
return 0 ;
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
GetClientRect (hwnd, &rect) ;
DrawText (hdc, TEXT ("Hello, Windows 98!"), -1, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;
EndPaint (hwnd, &ps) ;
return 0 ;
case WM_DESTROY:
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}

By design, WM_COMMAND and WM_NOTIFY messages are sent to a control's parent window. There is no way to make the API automatically send them to the control that generated them. The parent window must handle them, or forward them, as needed. There is no avoiding that.
In the VCL framework originally written by Borland and now owned by Embarcadero, it uses a simple system for forwarding such messages. When any parent window receives one of these messages, it increments the message ID by an offset that puts the message into the user-defined range, and then forwards the message to the child HWND specified in the message. So WM_COMMAND becomes CN_COMMAND and WM_NOTIFY becomes CN_NOTIFY, which the child control's window procedure can look for.
For example:
#define MY_COMMAND (WM_COMMAND + some_offset)
#define MY_NOTIFY (WM_NOTIFY + some_offset)
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
if (lParam != 0)
SendMessage((HWND)lParam, MY_COMMAND, wParam, lParam);
return 0;
case WM_NOTIFY:
SendMessage(((NMHDR*)lParam)->hwndFrom, MY_NOTIFY, wParam, lParam);
return 0;
...
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
LRESULT CALLBACK WndProcButton (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch( message )
{
case MY_COMMAND:
...
case MY_NOTIFY:
...
}
return CallWindowProc( g_wndProcButtonOrigianl, hwnd, message, wParam, lParam );
}

Related

Keep window on top of taskbar on Windows 11

I found that on windows 11, even if I created windows with WS_EX_TOPMOST style, the window still get covered by taskbar if you click anywhere on the taskbar. The only exception to this is task manager. How does it achieve it?
I want a feature to draw stuff on the taskbar, or at least mimic that behavior using a transparent window. I think there used to be 2 ways to achieve that:
Get DC of taskbar and draw (which no longer work on Windows11)
Create a transparent window and keep it on top of taskbar (issues with how to keep it topmost)
I kind of get stuck now. Any help is appreciated.
UPDATE:
I just noticed that the taskbar window, shown as DesktopWindowXamlSource in Spy++ does not have the WS_EX_TOPMOST style set. I guess it's possible to cover it for some ways?
#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
#include <iostream>
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
// Register the window class.
const wchar_t CLASS_NAME[] = L"Sample Window Class";
WNDCLASS wc = { };
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;
RegisterClass(&wc);
// Create the window.
HWND hwnd = CreateWindowEx(
WS_EX_TOPMOST, // Optional window styles.
CLASS_NAME, // Window class
L"Learn to Program Windows", // Window text
WS_OVERLAPPEDWINDOW, // Window style
// Size and position
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, // Parent window
NULL, // Menu
hInstance, // Instance handle
NULL // Additional application data
);
if (hwnd == NULL)
{
return 0;
}
ShowWindow(hwnd, nCmdShow);
// Run the message loop.
MSG msg = { };
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
// All painting occurs here, between BeginPaint and EndPaint.
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
EndPaint(hwnd, &ps);
}
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
And this is how the window get covered by taskbar when I click start.

Message loop not exiting when I close the window

I am new to programming with the Win32 API, and have been trying to figure out why this application is not returning when I close the window.
#include <windows.h>
LRESULT CALLBACK WindowProc(
_In_ HWND hwnd,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd)
{
// Register window class
WNDCLASS wc = {};
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = L"Window Class";
RegisterClass(&wc);
// Create window
HWND window = CreateWindowEx(
0,
wc.lpszClassName,
L"Window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
// Show window
ShowWindow(window, nShowCmd);
// Main Program Loop
MSG msg = {};
while (msg.message != WM_QUIT)
{
if (PeekMessage(&msg, window, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return msg.wParam;
}
LRESULT CALLBACK WindowProc(
_In_ HWND hwnd,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
I stepped through the code with a debugger and saw that after destroying the window, the value of the message was WM_PAINT, and so the program was continuously looping, but I don't understand why WM_QUIT is not being posted.
By providing window as an argument to PeekMessage you are telling it you only want to retrieve messages posted or sent to that window.
But WM_QUIT is a thread message - it's not associated with any given window. To retrieve it you need to call PeekMessage with nullptr for the window filter.
In addition to Jonathan Potter's answer, your message loop should be using GetMessage() instead of PeekMessage():
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
GetMessage() blocks the calling thread until a message arrives, and returns FALSE when WM_QUIT is received and the hWnd parameter is NULL.
By using PeekMessage(), you are running a tight busy loop, and the contents of msg are indeterminate when PeekMessage() returns FALSE when no message is available.

How to handle the message-only window to get the messages from the console window?

I'm trying to know when a console window has moved so I created a new message-only window to get the messages of the console but I don't know if it is working because the message is apparently never being received.
#define WINVER 0x0501
#include <windows.h>
#include <iostream>
WNDPROC glpfnConsoleWindow; // NEW
using namespace std;
LRESULT APIENTRY MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_SIZE:
cout<<"Window moved"<<endl;
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
// NEW
return CallWindowProc(glpfnConsoleWindow, hwnd, uMsg, wParam, lParam);
//return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
HWND hwnd;
MSG Msg;
const char lpcszClassName[] = "messageClass";
WNDCLASSEX WindowClassEx;
// == NEW
HWND consHwnd;
consHwnd = GetConsoleWindow();
glpfnConsoleWindow = (WNDPROC)SetWindowLong(consHwnd, GWL_WNDPROC, (LONG)MainWndProc);
// ==
ZeroMemory(&WindowClassEx, sizeof(WNDCLASSEX));
WindowClassEx.cbSize = sizeof(WNDCLASSEX);
WindowClassEx.lpfnWndProc = MainWndProc;
WindowClassEx.hInstance = hInstance;
WindowClassEx.lpszClassName = lpcszClassName;
if (RegisterClassEx(&WindowClassEx) != 0)
{
// Create a message-only window
hwnd = CreateWindowEx(0, lpcszClassName, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, hInstance, NULL);
if (hwnd != NULL)
cout<<"Window created"<<endl;
else
UnregisterClass(lpcszClassName, hInstance);
}
ShowWindow(hwnd,nCmdShow);
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return (int)Msg.wParam;
}
Perhaps you should process WM_MOVE, which, according to the documentation, is sent after the window has been moved. WM_SIZE is sent when the size changes.
I think your problem is that the WM_MOVE and WM_SIZE messages are going to the console window rather than to your hidden window.
I suspect you'll have to call GetConsoleWindow to get the console window handle, and then call SetWindowLong to attach your window proc to the console window. Be sure to pass messages on to the original window proc.

win32 waiting for events(synchroniztion)

I have 3 windows that have to interact with each other using events.
windows 1 and 2 are identical; each only have one button in them.
Basically, I the main window(program 3) to not show up until one of the other two windows buttons
is clicked; this is how it was describes in the lab:
You need to use synchronization to control the processes (starting Program3 via Program1 or 2, ending Program1 or 2 via closing Program3). Note: Program1 and Program2 must have had their button clicked in order for them to receive the signal to die
I've been looking around and got this so far for code:
Main window(program 3):
#include <windows.h>
#include<string.h>
#include <stdio.h>
#include <tchar.h>
#include <conio.h>
#pragma comment(lib, "winmm.lib")
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("RACE") ;
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
HANDLE hEvents[2];
hEvents[0] = "btn2";
hEvents[1] = "btn3";
DWORD count = 2;
HBRUSH brush;
brush = CreateSolidBrush(RGB(255,0,0));
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = brush;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("This program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
TCHAR* name;
//WAIT FOR SIGNAL
DWORD result = WaitForMultipleObjects(count,hEvents,FALSE,INFINITE);//work on this
if(result == WAIT_OBJECT_0)
{
name = TEXT("Program 1");
}
else if(result == WAIT_OBJECT_0 + 1)
{
name = TEXT("Program 2");
}
hwnd = CreateWindow (szAppName, // window class name
name, // window caption
WS_OVERLAPPEDWINDOW, // window style
0, // initial x position
0, // initial y position
600, // initial x size
600, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL); // creation parameters
ShowWindow (hwnd, iCmdShow) ;//DON'T SHOW UNTIL ANOTHER WINDOW'S BUTTON IS PUSHED.
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc ;
PAINTSTRUCT ps ;
TCHAR* carNames[5] = {TEXT("Red Car"), TEXT("Blue Car"), TEXT("Black Car"), TEXT("Green Car"), TEXT("Orange Car")};
switch (message)
{
case WM_CREATE:
HWND hwndButton;
for(int i = 0; i < 5; i++)
{
hwndButton = CreateWindow ( TEXT("button"),//type of child window
carNames[i],//text displayed on button
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,//type of button
20, (20*i*5+10),
85, 25,
hwnd, //parent handle i.e. main window handle
(HMENU) i,//child ID – any number
((LPCREATESTRUCT) lParam)->hInstance, NULL);
}
break;
return 0 ;
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
EndPaint (hwnd, &ps) ;
return 0 ;
/* case WM_CLOSE:
c--;
DestroyWindow(hwnd);
return 0 ;*/
case WM_DESTROY:
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
window 2(program2):
#include <windows.h>
#include<string.h>
#pragma comment(lib, "winmm.lib")
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("Part 2") ;
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("This program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (szAppName, // window class name
TEXT ("Part 2"), // window caption
WS_OVERLAPPEDWINDOW, // window style
0, // initial x position
0, // initial y position
300, // initial x size
200, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL) ; // creation parameters
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc ;
PAINTSTRUCT ps ;
HANDLE hEvent;
switch (message)
{
case WM_CREATE:
HWND hwndButton2;
hwndButton2 = CreateWindow ( TEXT("button"),//type of child window
TEXT("PRESS ME!"),//text displayed on button
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,//type of button
20, 20,
200, 25,
hwnd, //parent handle i.e. main window handle
(HMENU) 45,//child ID – any number
((LPCREATESTRUCT) lParam)->hInstance, NULL);
hEvent = CreateEvent(NULL, //no security attributes
FALSE, //auto-reset event object
FALSE, //initial state is nonsignaled
L"btn2"); //unnamed object
return 0 ;
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
EndPaint (hwnd, &ps) ;
return 0 ;
case WM_COMMAND:
SetEvent("btn2");
return 0;
case WM_DESTROY:
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
and window 3 (program 3): which is pretty much identical to window 2
#include <windows.h>
#include<string.h>
#pragma comment(lib, "winmm.lib")
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("Part 3") ;
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("This program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (szAppName, // window class name
TEXT ("Part 3"), // window caption
WS_OVERLAPPEDWINDOW, // window style
0, // initial x position
0, // initial y position
300, // initial x size
200, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL) ; // creation parameters
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc ;
PAINTSTRUCT ps ;
HANDLE hEvent1;
switch (message)
{
case WM_CREATE:
HWND hwndButton3;
hwndButton3 = CreateWindow ( TEXT("button"),//type of child window
TEXT("PRESS ME!"),//text displayed on button
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,//type of button
20, 20,
200, 25,
hwnd, //parent handle i.e. main window handle
(HMENU) 95,//child ID – any number
((LPCREATESTRUCT) lParam)->hInstance, NULL);
hEvent1 = CreateEvent(NULL, //no security attributes
FALSE, //auto-reset event object
FALSE, //initial state is nonsignaled
L"btn3"); //unnamed object
return 0 ;
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
EndPaint (hwnd, &ps) ;
return 0 ;
case WM_COMMAND:
SetEvent("btn3");
return 0;
case WM_DESTROY:
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
These are all in the same solution; but in different projects(multiple project in one solution).
The problem right now is that I can't seem to get the main window to open when I click
either one of the buttons. I've tried many different things, but none seem to be working.
Any and all help is appreciated. Thanks in advance.
HANDLE hEvents[2];
hEvents[0] = "btn2";
hEvents[1] = "btn3";
That's not right. You'll have to call the CreateEvent function just like you do in the other two programs.

After calling MoveWindow() with TRUE, the window client area is still invalid

MSDN doc's for MoveWindow() says:
"If the bRepaint parameter is TRUE, the system sends the WM_PAINT message to the window procedure immediately after moving the window (that is, the MoveWindow function calls the UpdateWindow function)."
But when I call GetUpdateRect() after MoveWindow(), while processing the WM_LBUTTONDOWN message in the parent, I get a beep, which shows that the child is invalid. What is the explanation ???
#include <windows.h>
#include <windowsx.h>
#include <tchar.h>
HINSTANCE ghInstance;
LRESULT CALLBACK WindowProc (HWND hwnd, UINT message, UINT wParam, LONG lParam);
LRESULT CALLBACK ChildProc (HWND hwnd, UINT message, UINT wParam, LONG lParam);
int APIENTRY WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
{
HWND hWnd;
MSG msg;
WNDCLASSEX wndclassx;
ghInstance = hInstance;
wndclassx.cbSize = sizeof(WNDCLASSEX);
wndclassx.style = 0;
wndclassx.lpfnWndProc = WindowProc;
wndclassx.cbClsExtra = 0;
wndclassx.cbWndExtra = 0;
wndclassx.hInstance = hInstance;
wndclassx.hIcon = 0;
wndclassx.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclassx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclassx.lpszMenuName = NULL;
wndclassx.lpszClassName = _T("ParentWindow");
wndclassx.hIconSm = NULL;
if( !RegisterClassEx(&wndclassx) ) return 0;
wndclassx.cbSize = sizeof(WNDCLASSEX);
wndclassx.style = 0;
wndclassx.lpfnWndProc = ChildProc;
wndclassx.cbClsExtra = 0;
wndclassx.cbWndExtra = 0;
wndclassx.hInstance = hInstance;
wndclassx.hIcon = 0;
wndclassx.hCursor = 0;
wndclassx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclassx.lpszMenuName = NULL;
wndclassx.lpszClassName = _T("ChildWindow");
wndclassx.hIconSm = NULL;
if( !RegisterClassEx(&wndclassx) ) return 0;
if( !(hWnd = CreateWindow(_T("ParentWindow"), _T("Parent Window"), WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance,
NULL)) ) return 0;
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);
while( GetMessage(&msg, NULL, 0, 0) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
LRESULT CALLBACK WindowProc (HWND hwnd, UINT message, UINT wParam, LONG lParam)
{
HWND hWnd;
switch ( message )
{
case WM_CREATE:
CreateWindow(_T("ChildWindow"), NULL, WS_CHILD | WS_VISIBLE | WS_BORDER, 10, 10, 100, 100, hwnd, (HMENU)0,
ghInstance, NULL);
break;
case WM_LBUTTONDOWN:
hWnd = GetWindow(hwnd, GW_CHILD);
MoveWindow(hWnd, 10, 10, 200, 200, true);
if( GetUpdateRect(hWnd, NULL, FALSE) ) MessageBeep(-1);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}
LRESULT CALLBACK ChildProc (HWND hwnd, UINT message, UINT wParam, LONG lParam)
{
return DefWindowProc(hwnd, message, wParam, lParam);
}
The MSDN doc's is wrong. MoveWindow() with TRUE doesn't call UpdateWindow() as the documentation says. It just invalidates the window client area. If I call UpdateWindow() just after MoveWindow() the program runs as expected.
I tried it myself and WM_PAINT is triggered before the if(GetUpdateRect()) is. Also, GetUpdateRect returns FALSE for me.
I'm running Visual Studio 2008 on XP.
I guess it could depend on what compiler you are using, what operating system that is used and whatnot. According to the code you passed everything is done in the same thread, but if it is a multithreaded program I think that this could inflict some issues as well.

Resources