As far as I understand, Windows makes a division of labor with regards to the (re)painting of a given window; the division into background erasure and foreground painting. The WM_ERASEBKGNDmessage is sent to prepare an invalidated portion of a given window for painting, and usually this preparation consists of erasing the background so the actual painting can commence of a clean canvas. It seems to me this message is always sent when Windows invalidates part of a given window (and so is basically always sent in conjunction with a WM_PAINT message being posted). Whenever the application itself invalidates (part of) a given window, the last argument to the InvalidateRect function specifies whether a WM_ERASEBKGNDis to be sent or not. So I wrote a small program to test my assumptions, but its behavior eludes me a little. This is said program:
#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hwInstance, PWSTR pCmdLine, int nCmdShow)
{
// Register the window class.
const wchar_t CLASS_NAME[] = L"Sample Window Class";
WNDCLASS wc = {0};
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszClassName = CLASS_NAME;
RegisterClass(&wc);
// Create the window.
HWND hwnd = CreateWindowEx(
0, // 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);
UpdateWindow(hwnd);
// Run the message loop.
MSG msg = {0};
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static int eb_count = 0; // counts number of WM_ERASEBKGND messages
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_PAINT:
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
RECT rect;
wchar_t text[40];
wsprintf(text, L"Number of WM_ERASEBKGND messages: %i\n", eb_count);
GetClientRect(hwnd, &rect);
DrawText(hdc, text, -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hwnd, &ps);
return 0;
case WM_RBUTTONDOWN: // repaint whenever RBUTTONDOWN
InvalidateRect(hwnd, NULL, FALSE);
UpdateWindow(hwnd);
return 0;
case WM_ERASEBKGND:
eb_count++;
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
I am handling WM_ERASEBKGND in the window procedure (it is a case in my switch), so it should not be passed to the default window procedure. However, I don't do any actual background erasing (I simply increment a static variable) and I return 0 to indicate that no erasing actually took place. It seems to me that in this program, the background should never get erased. This does, however, happen in two distinct instances.
Whenever I maximize the window, the background of the invalid portion does get erased with the class background brush. But how is this possible? The window procedure certainly does no such thing upon receiving a WM_ERASEBKGND message.
A similar thing happens whenever DrawText repaints its string. I would expect that the incrementing numbers would get painted on top of eachother (leading to an illegible mess, of course). So it seems the 'DrawText' function also somehow erases the background of the rectangle in which it paints its string.
My last question pertains to my assumption that a WM_ERASEBKGND message is sent whenever Windows invalidates part of a window. I noticed that whenever the window is covered by another window and subsequently uncovered, no WM_ERASEBKGND message seems to be sent. Does this mean my assumption is wrong?
Sorry for the long read, but any and all help in answering these questions would be greatly appreciated.
... my assumption that a WM_ERASEBKGND message is sent whenever Windows invalidates part of a window. I noticed that whenever the window is covered by another window and subsequently uncovered, no WM_ERASEBKGND message seems to be sent ...
That's because, as of Vista and later, we have the Desktop Window Manager (DWM) lurking away in the, erm, background. This buffers the contents of all the on-screen windows so that Windows doesn't need to issue WM_ERASEBKGND or WM_PAINT requests when part of one is uncovered - it can just copy the so-called back-buffer back to the screen.
[Parts of] windows do still get invalidated - either by you or the OS - but not as often as they used to be back in the XP days. Try minimising and restoring a window for example - then it has to be redrawn. When you do that, the DWM probably throws away the back-buffer to save memory while the window is minimised.
Apart from that, what the others said in the comments.
As per the answer by #Paul Sanders most recently the Desktop Window Manager is a process that does, actually, cache the contents of windows so it can perform a blend effects when composing the desktop, which means that your Window does not always get repainted in the way it did in earlier editions of Windows.
Prior to that, the move from a co-operatively multitasked to a multithreaded OS (This painting model was in the Windows 3.0 API) introduced some race conditions that, iirc, Windows would try and cover up by doing a pre-emptive background-brush fill in some cases when some process changed the visibility of another processes window. This is what you see when you maximise the window.
Your call to DrawText is working, because DrawText - by default - does its own background erase - you need to call SetBkMode passing in the TRANSPARENT flag to render just the font.
Related
For my college project I am developing a solution to distinguish between mouse user data from a person with Parkinson's compared to a healthy person. For which I need mouse data, ideally raw.
I presume I have misunderstood how to collect raw mouse input from the WM_INPUT message but I cannot figure it out.
I have been looking at the following thread: How to accurately measure mouse movement in inches or centimetres for a mouse with a known DPI
and Mouse input libraries on github all of which seem to easily catch a WM_INPUT message whose lParam is a handle to some RawInputData with something like this:
GetMessage(&msg, GetActiveWindow(), WM_INPUT, 0);
if (msg.message == WM_INPUT){ .....
And then retreiving the lParam from the message and collecting the data associated with that handle with:
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER));
However when I call GetMessage in my main loop, the function never exits!
Consequently there is no way (that i know of) for me to get a handle to the RawInputData. Especially since the MSDN page just assumes you have the lParam already.
In summary I need a method of getting an lParam to pass to the GetRawInputData function which will remain active whether the program is running in the active window of not.
I'm running this code in a blank C++ CLR project in Visual Studio with the "winuser.h" library.
#include "stdafx.h"
#include "Windows.h"
#include "winuser.h"
#ifndef HID_USAGE_PAGE_GENERIC
#define HID_USAGE_PAGE_GENERIC ((USHORT) 0x01)
#endif
#ifndef HID_USAGE_GENERIC_MOUSE
#define HID_USAGE_GENERIC_MOUSE ((USHORT) 0x02)
#endif
int main(array<System::String ^> ^args)
{
RAWINPUTDEVICE Rid[1];
Rid[0].usUsagePage = HID_USAGE_PAGE_GENERIC;
Rid[0].usUsage = HID_USAGE_GENERIC_MOUSE;
Rid[0].dwFlags = 0; //ideally RIDEV_INPUTSINK but that prevents registration
Rid[0].hwndTarget = GetActiveWindow(); //ideally this would be Null to be independent of the active window
if (RegisterRawInputDevices(Rid, 1, sizeof(Rid[0])) == FALSE) {
//registration failed. Call GetLastError for the cause of the error
Console::WriteLine("Registration Error");
}
MSG msg;
while (true) {
while (GetMessage(&msg, GetActiveWindow(), WM_INPUT, 0) != 0) { //this command is never completed
DispatchMessage(&msg); //this line is never ran
}
if (msg.message == WM_INPUT) {
Console::WriteLine("caught a message!!!");
}
}
}
Issue solved after much more research I found the winAPI walk through which I followed fixing the issue above by adding an:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE unused, PSTR cmd, int show) {.....}
Function to register devices and create a window then call GetMessage which calls LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {....} with the parameters occupied by the message ID,WParam and LParam corresponding the message event.
For anyone stuck with a similar issue follow this MSDN guide: https://msdn.microsoft.com/en-us/library/bb384843.aspx
Using this code the resulting dialog box is drawn without ability to be able to be resized by mouse:
#include <windows.h>
static UINT_PTR CALLBACK OFNHookProc (HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam) {
return 0;
}
int main() {
OPENFILENAMEW ofn;
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(OPENFILENAMEW);
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_ENABLEHOOK;
ofn.lpfnHook = OFNHookProc;
GetOpenFileNameW(&ofn);
return 0;
}
Removing OFN_ENABLEHOOK shows correct dialog window with resize indicator at bottom right corner. How to make dialog that is user-resizeable and with hook procedure ?
(of course that hook is mock here, only to illustrate the error, no matter what I put inside, of course if it is correct on other matters, result is the same)
You need to include the OFN_ENABLESIZING flag when using OFN_ENABLEHOOK. This is documented behavior:
OPENFILENAME structure
OFN_ENABLESIZING
0x00800000
Enables the Explorer-style dialog box to be resized using either the mouse or the keyboard. By default, the Explorer-style Open and Save As dialog boxes allow the dialog box to be resized regardless of whether this flag is set. This flag is necessary only if you provide a hook procedure or custom template. The old-style dialog box does not permit resizing.
I'm working on a win32 c/cpp project involving openGL. I'm just starting and had a few basic questions regarding how a standard win32 program works. Following a tutorial, I made the winmain create a new window, enable openGL for the window, and then enter the main loop where if there are messages, the program handles them, and otherwise, the program moves onto drawing openGL animations. Following that, I simply shut down openGL and destroy the window. I'm not too confused about what's happening in here, but this is where I get lost:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message)
{
case WM_CREATE:
return 0;
case WM_CLOSE:
PostQuitMessage( 0 );
return 0;
case WM_DESTROY:
return 0;
case WM_KEYDOWN:
switch ( wParam )
{
case VK_ESCAPE:
PostQuitMessage(0);
return 0;
}
return 0;
default:
return DefWindowProc( hWnd, message, wParam, lParam );
}
though I do see in the winmain that I register this function to my window class via
wc.lpfnWndProc = WndProc;
How exactly does this process work? Can someone explain the pipeline to me - as the winmain method runs, it goes onto drawing the opengl animation, but as soon as a key is pressed, it enters message handling... and then what? How does my winmain method communicate with the WndProc method? What's actually happening from the machine's point of view?
In your WinMain there should be a pair of TranslateMessage / DispatchMessage calls. TranslateMessage is responsible for getting keystrokes being delivered correctly and DispatchMessage traverses the window hierachy to deliver the messages to the window that has the input focus, effectively calling the function which pointer was registered as default window message handler (Window Procedure) with the message as parameters.
I have this class here that I made based on another one I had. It is supposed to handle the whole creating windows and stuff, but it seems to be getting into a hang now. The older version used to work fine, I don't know WHAT I may have forgotten to add to this one that might be causing it to hang like this.
This is the message loop:
int Window::HandleMessages()
{
while(GetMessage(&this->windat.msgs, NULL, 0, 0))
{
TranslateMessage(&this->windat.msgs);
DispatchMessage(&this->windat.msgs);
}
return this->windat.msgs.wParam;
}
Pretty basic stuff, I don't know why, but it will simply hang... When I run the program, it'll just show me an empty prompt window, and by testing, I got it to show a message box if I used it before the while loop, but inside it doesn't work. I've been trying to compare both this class and the older one and haven't figured out what might be wrong with this. Could anyone tell me what could possibly trigger this behaviour?
Thanks
OK, now this left me pretty confused. By messing around with GetLastError, it seems that it is returning error 2 (file not found) ANYWHERE I put it, even if right at the start of the Main, before I instantiate my Window class. If I call GetLastError anytime after CreateWindowEx, it'll return an error like 1047 or something, about class not found or something. HWND becomes NULL too
Here is the code for the main.cpp:
#include "SimpWin/SimpWin.h"
#include <stdio.h>
// Make the class name into a global variable
char szClassName[] = "WindowsApp";
void ErrorExit(LPTSTR lpszFunction)
{
// Retrieve the system error message for the last-error code
LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL );
// Display the error message and exit the process
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
(lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
sprintf((char*)lpDisplayBuf,
TEXT("%s failed with error %d: %s"),
lpszFunction, dw, lpMsgBuf);
MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf);
ExitProcess(dw);
}
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nFunsterStil)
{
ErrorExit(TEXT("CreateWindowEx"));
Window* win = Window::CreateWindowClass(hThisInstance, szClassName, WindowProcedure);
if(!win->Register())
{
return 0;
}
win->Show(nFunsterStil);
int res = win->HandleMessages();
delete win;
return res;
}
/* This function is called by the Windows function DispatchMessage() */
LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
return DefWindowProc (hwnd, message, wParam, lParam);
}
This here, is the code for the Window::Register function:
int Window::Register()
{
if(this->windat.wincl.hIcon == NULL)
{
this->windat.wincl.hIcon = LoadIcon(NULL, IDI_APPLICATION);
}
if(this->windat.wincl.hIconSm == NULL)
{
this->windat.wincl.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
}
if(!RegisterClassEx(&this->windat.wincl))
{
return 0;
}
this->windat.hwnd = CreateWindowEx (
0, /* Extended possibilites for variation */
(char*) this->windat.sName, /* Classname */
(char*) this->windat.sTitle, /* Title Text */
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, /* default window */
CW_USEDEFAULT, /* Windows decides the position */
CW_USEDEFAULT, /* where the window ends up on the screen */
this->windat.cDimension.width, /* The programs width */
this->windat.cDimension.height, /* and height in pixels */
HWND_DESKTOP, /* The window is a child-window to desktop */
NULL, /* No menu */
this->windat.hInstance, /* Program Instance handler */
NULL /* No Window Creation data */
);
return 1;
}
I'm lost here, I don't know why the eff this is going on... :/
Use PeekMessage instead of GetMessage.
Check the return value to GetMessage() - your while loop won't exit if there are errors. It should look like this:
while (GetMessage(&this->windat.msgs, NULL, 0, 0) > 0)
{
...
}
Well, I finally got it working! :D
It actually had to do with a completely unrelated class I had here. It is a String class (which descended from Array) which I made, and the copy function had a bug, it would copy the character array I passed to it, but would not update the length field of the class...
That copy function would be called whenever I had to set the class to a value through operator=. The length is required for the operator char* to convert the class to c-format string. I'd use that cast when passing the ClassName and Title values to CreateWindowEx, and it would return me an array of 0 chars, and that's where hell happened.
Now I fixed that lib up, and it's working fine now. Thanks :D
Even though it's pretty old... from MSDN on GetMessage:
Unlike GetMessage, the PeekMessage function does not wait for a message to be posted before returning.
That is, GetMessage waits for next message to become available. You treat this wait in progress as a freeze, supposedly because you did not actually have the intention to wait for messages.
Note that you can attach debugger at the time of supposed freeze, pause the execution and inspect the call stacks of the threads. Once you find your thread and its call stack and its GetMessage in progress on the stack - you isolate the problem well enough to know where to read on documented behavior.
I'm working on a portability layer for OpenGL (abstracts the glX and wgl stuff for Linux and Windows)... Anyhow, it has a method for creating a Window... If you don't pass in a parent, you get a real window with a frame... If you pass in a parent, you get a borderless, frameless window...
This works fine, as long as I do it all on 1 thread... As soon as another thread tries to create a child window, the app deadlocks in the win32 call "CreateWindow()". Any ideas?
This is not a real answer, but since so many people seem to believe that Win32 forbids creating children in other threads than the parent, I feel obliged to post a demonstration to the contrary.
The code below demonstrates creation of a child window on a parent belonging to a different process. It accepts a window handle value as a command-line parameter and creates a child window on that parent.
// t.cpp
#include <windows.h>
#include <stdio.h>
#define CLASS_NAME L"fykshfksdafhafgsakr452"
static LRESULT CALLBACK WindowProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch ( msg )
{
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
BeginPaint(hwnd, &ps);
EndPaint(hwnd, &ps);
break;
}
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
int main( int argc, char* argv[] )
{
HWND parent = (argc >= 2) ? (HWND)strtoul(argv[1], 0, 0) : (HWND)0;
printf("parent: 0x%x\n", parent);
WNDCLASS wc = {};
wc.lpfnWndProc = WindowProc;
wc.hInstance = (HINSTANCE)GetModuleHandle(NULL);
wc.lpszClassName = CLASS_NAME;
wc.hbrBackground = (HBRUSH)(COLOR_ACTIVECAPTION + 1);
if ( !RegisterClass(&wc) )
{
printf("%d: error %d\n", __LINE__, GetLastError());
return 0;
}
const DWORD style = WS_CHILD | WS_VISIBLE;
HWND hwnd = CreateWindow(CLASS_NAME, L"Test", style, 50, 50, 100, 100,
parent, 0, wc.hInstance, 0);
if ( !hwnd )
{
printf("%d: error %d\n", __LINE__, GetLastError());
return 0;
}
MSG msg;
while ( GetMessage(&msg, 0, 0, 0) )
DispatchMessage(&msg);
return 0;
}
Compile this with the following command (using MSVC command line environment):
cl /EHsc /DUNICODE /D_UNICODE t.cpp user32.lib
Then use Spy++ or some other tool to obtain handle value of any window -- e.g. of Notepad or the browser you're viewing this site in. Let's assume it's 0x00001234. Then run the compiled sample with t.exe 0x1234. Use Ctrl-C to terminate t.exe (or just close the console window).
When a child window is created, it can interact with the parent window via SendMessage. But, note that SendMessage across thread boundary blocks threads unlike PostMessage. If the parent window's thread is waiting for the child thread, and the child thread is trying to create a window whose parent is in that thread, then it's a deadlock.
In general, I don't think it's a good idea to make child-parent relationship across the threads. It can very easily make deadlock.
There are a lot of replies here saying that you MUST NOT attempt to have child and parent windows on different threads, and rather emphatically stating that it will not work.
If that was so, Windows would put some safeguards in and simply fail out when you attempted to call CreateWindow.
Now, there definitely are thread coupling issues that can cause major issues, but, that said with those constraints, this is a supported scenario.
This is an interesting question: A lot of old school win32 guys have told me you CANNOT do this. In researching this, I found this forum: SendMessage(). My current theory is that CreateWindowEx() must send a message (via SendMessage(), so it blocks) to the parent window to ask for permission to exist (or at least to notify of its existence)... Anyhow, as long as that parent thread is free to process these messages, it all works...
A window is tied to the thread that creates it (more specifically, to that thread's message queue). A parent window cannot reside in a different thread than its child windows.