This is excerpt from my code based on win32 api:
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
void __fastcall TMyThread::Execute(void)
{
WNDCLASSEX wc = {0};
wc.cbSize = sizeof(WNDCLASSEX);
wc.lpfnWndProc = WindowProc;
wc.hInstance = GetModuleHandle(NULL);
wc.lpszClassName = class_name.c_str();
if (!RegisterClassEx(&wc))
{
MessageBox(NULL, L"Window Registration Failed!", L"Error", MB_ICONEXCLAMATION | MB_OK);
return;
}
hwnd = CreateWindowEx(0, class_name.c_str(), NULL, 0, 0, 0, 100, 100, HWND_MESSAGE, NULL, wc.hInstance, NULL);
if (hwnd == NULL)
{
MessageBox(NULL, L"Window Creation Failed!", L"Error", MB_ICONEXCLAMATION | MB_OK);
return;
}
MSG msg;
BOOL ret;
while ((ret = GetMessage(&msg, 0, 0, 0)) != 0)
{
if (ret != -1)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
My questions:
Is it required to do some resource cleanup after quitting message loop (like CloseHandle for example)? Quite often i am seeing code samples without any such things. Is it correct?
Can newly created window receive messages into thread queue before first call of GetMessage function (we suppose that window was successfully created i.e. function CreateWindowEx returned without errors)?
Please take in mind that TMyThread is not main thread of application. So it can be created and destroyed many times in one application run. Please don't pay attention to quite simplified window creation. This particular window is not meant to be visible on screen. It is created solely for purpose of receiving messages from another application. This is highlighted by using HWND_MESSAGE value of hWndParent parameter when calling CreateWindowEx function.
By creating, running and destroying thread in the above example again and again I have found out that two methods needs to be called after quitting from message loop. First is DestroyWindow and second is UnregisterClass. In regular application DestroyWindow function should be called in WM_CLOSE handler after the user confirms that he really wants to close the application. DestroyWindow function then sends WM_DESTROY and WM_NCDESTROY messages to window. In response to WM_DESTROY message application should call PostQuitMessage(0) function which results to immediately quitting message loop. So this part of code is not neccessary in all scenarios. I needed to call DestroyWindow function explicitly because I exit message loop by simply sending WM_QUIT message. When not doing it sometimes I received error 1412 (ERROR_CLASS_HAS_WINDOWS) when trying to unregister window class.
if (hwnd != NULL)
{
ret = DestroyWindow(hwnd);
if (ret == 0)
{
str.printf(L"Window destroying failed (GetLastError = %d)!", GetLastError());
ShowError(str);
}
hwnd = NULL;
}
ret = UnregisterClass(class_name.c_str(), wc.hInstance);
if (ret == 0)
{
str.printf(L"Window class unregistration failed (GetLastError = %d)!", GetLastError());
ShowError(str);
}
You must be very careful with resources in Win32. Make sure you've looked at the documentation carefully to determine what Windows itself will unload for you and what you have to unload yourself.
For examples, HWNDs will get destroyed as parent HWNDs get destroyed.
The best trick is to attempt to unload everything you've personally created. If you get an error returned from a particular function on unload, you likely should not unload it as it's been unloaded by Windows or some related resource.
It is important not to unload things when it is not necessary, as that could cause a crash.
So for example, an icon created with a window that's directly from a resource likely shouldn't be unloaded. But an HBITMAP you create that you draw to other windows, should most definitely be unloaded.
Your section question can be determined by a quick test with breakpoints. I do not know off the top of my head.
Related
I'm building a real time graphics application and I've noticed that under certain conditions the operating system will post nonqueued messages that block my program. For example, this will happen during the entire time that a user is resizing the window.
To solve this problem, I would like to put the window on a different thread, but I read that this is a terrible idea because of the way windows messages work. Is it still a problem if I process all messages on the other thread, and never send or receive messages from the main thread? I'm thinking about setting up my own message queue with a mutex so I can pass the data I care about back and forth. If this won't work, are there any other ways to solve this problem?
Here's a simplified version of the code I'm running:
LRESULT CALLBACK WindowCallback(HWND window, UINT message, WPARAM wParam, LPARAM lParam) {
if (message == WM_SIZE) {
// This event gets called a lot
// Handle window resize
return 0;
} else {
return DefWindowProc(window, message, wParam, lParam);
}
}
int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev, LPSTR cmd, int numCmd) {
WNDCLASSA class = {};
class.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
class.lpfnWndProc = WindowCallback;
class.lpszClassName = "Name";
class.hInstance = instance;
RegisterClassA(&class)l
HWND win = CreateWindowExA(0, class.lpszClassName, "Name",
WS_VISIBLE | WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 600, 400,
0, 0, instance, 0);
while(true) {
// Handle Events
MSG msg = {};
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) {
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// Do Updating of State and Graphics Rendering Here
}
}
Thanks in advance!
I'm trying to create an application that will be notified about each active window change in Windows so it could do some tasks like detecting window titles, therefore "punishing" bad people accessing bad content on our PC machines. So, this is really important for the application because it's purpose is to log "bad" applications from history.
So, in my main function, I started a thread for my WindowLogger.
windowThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) WindowLogger,
(LPVOID) argv[0], 0, NULL );
if (windowThread)
{
// Also a bit of protection here..
return WaitForSingleObject(windowThread, INFINITE);
}
Then, here is my WindowLogger procedure:
// Function called by main function to install hook
DWORD WINAPI
WindowLogger(LPVOID lpParameter)
{
HHOOK hWinHook;
HINSTANCE hExe = GetModuleHandle(NULL);
if (!hExe)
{
return 1;
}
else
{
hWinHook = SetWindowsHookEx(WH_CBT, (HOOKPROC) CBTProc, hExe, 0);
MSG msg;
// I AM UNSURE ABOUT THIS PART..
// Probably wrong code :D ..
while (GetMessage(&msg, NULL, 0, 0) != 0)
{
if (msg.message == HCBT_ACTIVATE) {
// my code to log the window name
}
}
UnhookWindowsHookEx(hWinHook);
}
return 0;
}
And finally, my CBTProc callback function, it logs the windows using my log() function:
LRESULT CALLBACK
CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
{
switch (nCode)
{
case HCBT_ACTIVATE:
{
HWND foreground = GetForegroundWindow();
char window_title[50];
if (foreground)
GetWindowText(foreground, window_title, 25);
log("|");
log(&window_title[0]);
log("|");
}
}
}
So I had debugged the program and what I figured out is that hWinHook becomes NULL after SetWindowsHookEx() -- this is what probably causes my program to mailfunction..
.. Can you help me out with this?
Thanks in advance.
Passing 0 for the dwThreadId parameter to SetWindowsHookEx is used to register a hook for all threads in the system, i.e. a global hook. However to do this, your hook code needs to be located within a DLL (so that the DLL can be mapped into the address space of other processes). Since your hook code is in your main executable rather than a DLL the call is failing.
I am trying to implemente a close-save-file dialog into a Win32 project, but encouter a strange problem. Here is my solution.
Create a simple win32 project in Visual Studio.
Handle WM_COMMAND to create new window.
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
InitInstance(hInst, SW_SHOW);
//DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
windowCount--;
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
Handle WM_SYSCOMMNAD to show the save-before-quit messagebox.
case WM_SYSCOMMAND:
if (wParam == SC_CLOSE) {
int ret = MessageBox(NULL, L"do you really want to close", L"question", MB_YESNO|MB_APPLMODAL);
if (ret == IDNO)
return 0;
closedCount++;
StringCchPrintf(buff, 256, L"hwnd %x user choose to close\n", hWnd);
OutputDebugString(buff);
}
return DefWindowProc(hWnd, message, wParam, lParam);
two variable closeCount and windowCount to ensure terminate after all windows are closed.
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0) || (closedCount != windowCount))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
windowCount++;
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
Full code: http://pastebin.com/EVWWMz8L
There are two bugs in above code:
Create two windows and click close button for each window, then confirm to close for one window would close both windows. Which means, close MessageBox in one window would cause MessageBox in the other window return without any user input.
Create two windows and click close button for each window. Then use aero thumbnail to activate one messagebox and confirm to close, but the associated window would not close. I need to confirm both messagebox to close window.
How could this happen, what's wrong with my code?
1, Handler for WM_DESTROY is wrong, right handler should be:
case WM_DESTROY: {
StringCchPrintf(buff, 256, L"%x recieved Wm-DESTROY\n", hWnd);
OutputDebugString(buff);
closedCount++;
if (closedCount == windowCount) {
PostQuitMessage(0);
}
}
FULL code: http://pastebin.com/EU7cVKUb
Root cause:
PostQuitMessage terminate the MessageBox/DialogBox message loop, cause them missing and return immediate. In conclusion, DO NOT call PostQuitMessage until you really need to do this.
2, MessageBox/DialogBox should have owner window, otherwise user could use alt+tab/aero-thumbnail to select the box. So create the messagebox with hwnd as parent could solve problem 2.
I am having trouble correctly running a message loop from within a message handler. In effect replicating how DialogBox() processes messages, minus all of the windowing.
Simply invoking GetMessage() from within a message handler nearly works except when the WM_SYSKEYDOWN event opening the system menu also triggers the entry into a sub-loop. After this weird things happen, with keys presses being swallowed and WM_MOUSEMOVE messages relative to the system menu getting sent to the main window.
For the record this happens both in Windows 8 and XP.
To give some context I am attempting a threading model where a (windowless) worker thread communicates through blocking SendMessage calls back to the main window acting as a server. These actions may require further input or depend on other I/O and thus regular messages need to be processed until the reply is ready.
I'm fairly certain that this is a basic mistake or misunderstanding on my part, just like last time I posted here, but I can't quite seem to work out what I'm doing wrong on my own.
Here is my repro case. Try navigating after pressing ALT+SPACE to open the system menu,
#include <windows.h>
BOOL update;
LRESULT WINAPI WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
MSG msg;
char text[256];
switch(uMsg) {
case WM_DESTROY:
ExitProcess(0);
// Trigger an update on input
case WM_SYSKEYDOWN:
update = TRUE;
break;
// Display the update from the worker thread, returning once it is time to
// ask for the next one
case WM_USER:
wsprintf(text, TEXT("%u"), (unsigned int) lParam);
SetWindowText(hwnd, text);
while(!update && GetMessage(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
update = FALSE;
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
DWORD WINAPI ThreadProc(void *hwnd) {
// Submit updates as quickly as possible
LONG sequence = 1;
for(;;)
SendMessage(hwnd, WM_USER, 0, sequence++);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCommandLine, int nCmdShow) {
HWND hwnd;
MSG msg;
// Create our window
WNDCLASS windowClass = { 0 };
windowClass.lpfnWndProc = WindowProc;
windowClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
windowClass.hCursor = NULL;
windowClass.lpszClassName = TEXT("Repro");
RegisterClass(&windowClass);
hwnd = CreateWindow(TEXT("Repro"), TEXT("Repro"),
WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL,
hInstance, 0);
// Launch the worker thread
CreateThread(NULL, 0, ThreadProc, hwnd, 0, NULL);
// And run the primary message loop
while(GetMessage(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
Modal message loops are perfectly fine. Raymond Chen has a series of articles on writing modal message loops properly.
One thing I notice: Your thread should post the message, not send it; SendMessage calls directly into the window proc. Don't use PostThreadMessage, either; that's designed for threads without visible UI (and the nested DispatchMessage won't know how to dispatch the thread message, resulting in dropped messages).
OK so I have my main window procedure (simplified):
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
{
if(!loadFiles())
SendMessage(hwnd, WM_CLOSE, 0, 0);
}
break;
case WM_CLOSE:
DestroyWindow(hwnd);
return 0;
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
loadFiles() is a function to read some text files. If the files are missing, it posts an error message and then returns false. I handle this by sending the WM_CLOSE message, which sends WM_DESTROY? The program calls PostQuitMessage(0) and.. nothing. The process is still sitting in background, now using 100% CPU on core 1. Here is my message loop :
MSG Msg;
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
Very simple, I've looked around and seen people using all kinds of different loops, most with PeekMessage() function.. its worth noting I have several child windows containing different controls, I show and hide them when the user selects different tabs, but I don't think it matters because PostQuitMessage(0) is supposed to post WM_QUIT to the message queue, which destroys the child windows aswell right? Any help? Thanks
According to MSDN WM_CREATE is sent during CreateWindow. So you are destroying the window right during creation. I am not sure that this is supposed to work. Also, why so complicated? The documentation says
If an application processes this message, it should return zero to
continue creation of the window. If the application returns –1, the
window is destroyed and the CreateWindowEx or CreateWindow function
returns a NULL handle.
So just return -1 in case loadFiles() fails and handle CreateWindow returning NULL accordingly.