I have a multithreaded application and on certain threads, I'm creating windows using ATL's CWindowImpl<>. I have a static method that I'm using as the thread procedure. I need to create a window on the thread, because I need some of my communication with the thread to be synchronous, and PostThreadMessage() is expressly asynchronous. When my window receives the WM_DESTROY message (handler defined by the MESSAGE_HANDLER macro), it calls PostQuitMessage(), as shown in this method:
LRESULT MyATLWindowClass::OnDestroy(UINT uMsg,
WPARAM wParam,
LPARAM lParam,
BOOL& bHandled) {
::PostQuitMessage(0);
return 0;
}
I'm using a custom message to the thread using PostThreadMessage() to indicate to the thread that it's time to terminate itself. Handling that custom message, I call the CWindowImpl::DestroyWindow() method, which does appear to properly destroy the window, as my OnDestroy message handler is getting called. However, it doesn't appear that the owning thread ever receives a WM_QUIT message for processing. Included below is a simplified version of my thread procedure.
unsigned int WINAPI MyATLWindowClass::ThreadProc(LPVOID lpParameter) {
// Initialize COM on the thread
::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
// Create the window using ATL
MyATLWindowClass new_window;
HWND session_window_handle = new_window.Create(
/* HWND hWndParent */ HWND_MESSAGE,
/* _U_RECT rect */ CWindow::rcDefault,
/* LPCTSTR szWindowName */ NULL,
/* DWORD dwStyle */ NULL,
/* DWORD dwExStyle */ NULL,
/* _U_MENUorID MenuOrID */ 0U,
/* LPVOID lpCreateParam */ NULL);
// Initialize the message pump on the thread.
MSG msg;
::PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
// Run the message loop
BOOL get_message_return_value;
while ((get_message_return_value = ::GetMessage(&msg, NULL, 0, 0)) != 0) {
if (get_message_return_value == -1) {
// GetMessage handling logic taken from MSDN documentation
break;
} else {
if (msg.message == WD_SIGNAL_THREAD_SHUTDOWN) {
// Requested thread shutdown, so destroy the window
new_window.DestroyWindow();
} else if (msg.message == WM_QUIT) {
// Process the quit message and exit the message loop
// to terminate the thread
break;
} else {
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
}
// Uninitialize COM on the thread before exiting
::CoUninitialize();
return 0;
}
Note that it doesn't seem to matter if I call DestroyWindow() or if I send a WM_CLOSE message to the window. The thread's message pump is not receiving WM_QUIT in either case. Should the owning thread's message pump be receiving such a message? Where is my misunderstanding about how the thread's message pump and the window's message pump interact? Or what am I missing about how ATL's window classes create and manage windows?
GetMessage() never returns WM_QUIT. That message forces it to return 0 instead, designed to terminate your message loop.
Beware of the considerable hazards of using PostThreadMessage(). It should never be used on a thread that also displays windows, like the one you are using. The issue is that it doesn't take a HWND argument. So only your message loop can see the message, it won't be delivered to any window with DispatchMessage(). This goes wrong when a modal message loop is entered, the kind that are outside of your control. Like the modal loop that makes MessageBox work. Or the one that Windows uses to allow the user to resize a window. Or the one that DialogBox() uses. Etcetera. Always use PostMessage(), use your own message number.
Some late additional thoughts. You could probably safely terminate your message loop as soon as you have discovered WD_SIGNAL_THREAD_SHUTDOWN:
if (msg.message == WD_SIGNAL_THREAD_SHUTDOWN) {
// Requested thread shutdown, so destroy the window
new_window.DestroyWindow();
break; // exit the message loop
}
DestroyWindow is a synchronous call, the window will be fully destroyed before it returns and you can exit the loop. So, posting WM_QUIT would be redundant.
Also, you could use message-only window, if the windows is invisible and its only purpose is to process messages.
Related
I have written a small test application that inserts files (with hardcoded paths) into the currently active folder/application via delayed rendering. It works as expected. But I have a question - why does PeekMessage always return FALSE? But if you remove the PeekMessage call, Wndproc will never be called. I read a similar post, but I'm creating a window in the same thread in which I'm trying to process messages.
Code:
static LRESULT CALLBACK WindProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
switch (Msg) {
case WM_RENDERALLFORMATS: {
OpenClipboard(hWnd);
EmptyClipboard();
}
case WM_RENDERFORMAT: {
printf("WM_RENDERFORMAT received");
<Here the file paths are copied to the clipboard>
if (Msg == WM_RENDERALLFORMATS)
CloseClipboard();
return 0;
}
case WM_DESTROYCLIPBOARD:
return 0;
}
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
HWND hwnd_;
void thread_(void* ignored) {
WNDCLASSEX wcx = { 0 };
wcx.cbSize = sizeof(WNDCLASSEX);
wcx.lpfnWndProc = WindProc;
wcx.hInstance = GetModuleHandle(NULL);
wcx.lpszClassName = TEXT("my_class");
RegisterClassEx(&wcx);
hwnd_ = CreateWindowEx(0, TEXT("my_class"), TEXT(""), 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL);
MSG msg;
while (true) {
if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
printf("PeekMessage returned TRUE\n");
TranslateMessage(&msg);
DispatchMessage(&msg);
break;
}
Sleep(1000);
}
}
void main() {
CloseHandle((HANDLE)_beginthread(thread_, 0, NULL));
// let's give some time to thread to create msg window
Sleep(100);
if (OpenClipboard(hwnd_)) {
EmptyClipboard();
SetClipboardData(CF_HDROP, NULL);
CloseClipboard();
}
while (true) {
Sleep(100);
}
}
PeekMessage() (and GetMessage()) only returns messages that are posted via PostMessage() or PostThreadMessage() to the calling thread's message queue. PeekMessage() returns FALSE when there is no posted message available at the moment it is called. GetMessage() blocks until a posted message becomes available.
However, the messages in question (WM_RENDERFORMAT and WM_RENDERALLFORMATS) are instead being sent via SendMessage...() directly to the target window. But, the messages are being sent by another thread, so PeekMessage() (or GetMessage()) is still needed, as they internally dispatch messages that are sent across thread boundaries.
This is stated in PeekMessage()'s documentation:
Dispatches incoming nonqueued messages, checks the thread message queue for a posted message, and retrieves the message (if any exist).
...
During this call, the system dispatches (DispatchMessage) pending, nonqueued messages, that is, messages sent to windows owned by the calling thread using the SendMessage, SendMessageCallback, SendMessageTimeout, or SendNotifyMessage function. Then the first queued message that matches the specified filter is retrieved. The system may also process internal events. If no filter is specified, messages are processed in the following order:
Sent messages
Posted messages
Input (hardware) messages and system internal events
Sent messages (again)
WM_PAINT messages
WM_TIMER messages
As well as the GetMessage() documentation:
Retrieves a message from the calling thread's message queue. The function dispatches incoming sent messages until a posted message is available for retrieval.
...
During this call, the system delivers pending, nonqueued messages, that is, messages sent to windows owned by the calling thread using the SendMessage, SendMessageCallback, SendMessageTimeout, or SendNotifyMessage function. Then the first queued message that matches the specified filter is retrieved. The system may also process internal events. If no filter is specified, messages are processed in the following order:
Sent messages
Posted messages
Input (hardware) messages and system internal events
Sent messages (again)
WM_PAINT messages
WM_TIMER messages
And SendMessage()'s documentation:
If the specified window was created by the calling thread, the window procedure is called immediately as a subroutine. If the specified window was created by a different thread, the system switches to that thread and calls the appropriate window procedure. Messages sent between threads are processed only when the receiving thread executes message retrieval code. The sending thread is blocked until the receiving thread processes the message. However, the sending thread will process incoming nonqueued messages while waiting for its message to be processed. To prevent this, use SendMessageTimeout with SMTO_BLOCK set. For more information on nonqueued messages, see Nonqueued Messages.
With that said, your handling of the WM_RENDERALLFORMATS message is wrong. For one thing, it must not call EmptyClipboard(), and for another, it is not checking whether your app is still the clipboard owner before rendering its data. See What is the proper handling of WM_RENDERFORMAT and WM_RENDERALLFORMATS? for why these points are important.
Also, you have a race condition in your main thread. Before it calls OpenClipboard(), it sleeps for only 100ms to wait for the window to be created first, but there is no guarantee that hwnd_ will have been assigned within that 100ms. It could take that long just for the worker thread to start running, for instance.
A better option is to have the worker thread signal an event when the window is created, and then have the main thread wait on that event (even better would be to simply move the initial SetClipboardData() call into the worker thread itself after creating the window, but you have dismissed that option).
Try something more like this instead:
static LRESULT CALLBACK WindProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
/*
case WM_CREATE:
if (OpenClipboard(hWnd)) {
EmptyClipboard();
SetClipboardData(CF_HDROP, NULL);
CloseClipboard();
}
return 0;
}
*/
case WM_RENDERALLFORMATS: {
if (OpenClipboard(hWnd)) {
if (GetClipboardOwner() == hWnd) {
SendMessage(hWnd, WM_RENDERFORMAT, CF_HDROP, 0);
}
CloseClipboard();
}
return 0;
}
case WM_RENDERFORMAT: {
printf("WM_RENDERFORMAT received");
if (wParam == CF_HDROP) {
// <Here the file paths are copied to the clipboard>
}
return 0;
}
case WM_DESTROYCLIPBOARD:
return 0;
}
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
HWND hwnd_ = NULL;
void thread_(void* arg) {
HANDLE hEvent = (HANDLE)arg;
WNDCLASSEX wcx = { 0 };
wcx.cbSize = sizeof(WNDCLASSEX);
wcx.lpfnWndProc = WindProc;
wcx.hInstance = GetModuleHandle(NULL);
wcx.lpszClassName = TEXT("my_class");
RegisterClassEx(&wcx);
hwnd_ = CreateWindowEx(0, TEXT("my_class"), TEXT(""), 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL);
SetEvent(hEvent);
if (hwnd_ == NULL) {
return 0;
}
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
printf("GetMessage returned a message\n");
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
int main() {
HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!hEvent)
return 1;
uintptr_t res = _beginthread(thread_, 0, hEvent);
if (res == -1L) {
CloseHandle(hEvent);
return 1;
}
WaitForSingleObject(hEvent, INFINITE);
CloseHandle(hEvent);
if (hwnd_ != NULL) {
if (OpenClipboard(hwnd_)) {
EmptyClipboard();
SetClipboardData(CF_HDROP, NULL);
CloseClipboard();
}
}
HANDLE hThread = (HANDLE)res;
WaitForSingleObject(hThread, INIFINTE);
CloseHandle(hThread);
return 0;
}
why does PeekMessage always return FALSE?
Assuming that the window handle that you pass to PeekMessage is valid, then the reason for PeekMessage returning FALSE is simply that there are no messages in the queue.
That this is the case can be discerned from the documentation which says:
If a message is available, the return value is nonzero.
If no messages are available, the return value is zero.
I'm trying to implement the following scenario:
Requirement
Write a C++ program to capture all the keyboard inputs on Windows OS. The program should start capturing keystrokes and after about 3 seconds (the specific amount time is not very relevant, it could be 4/5/etc.), the program should stop capturing keystrokes and continue its execution.
Before I proceed with the actual implementation details, I want to clarify that I preferred tο write the requirements in a form of exercise, rather than providing a long description. I'm not trying to gather solutions for homework. (I'm actually very supportive to such questions when its done properly, but this is not the case here).
My solution
After working on different implementations the past few days, the following is the most complete one yet:
#include <iostream>
#include <chrono>
#include <windows.h>
#include <thread>
// Event, used to signal our thread to stop executing.
HANDLE ghStopEvent;
HHOOK keyboardHook;
DWORD StaticThreadStart(void *)
{
// Install low-level keyboard hook
keyboardHook = SetWindowsHookEx(
// monitor for keyboard input events about to be posted in a thread input queue.
WH_KEYBOARD_LL,
// Callback function.
[](int nCode, WPARAM wparam, LPARAM lparam) -> LRESULT {
KBDLLHOOKSTRUCT *kbs = (KBDLLHOOKSTRUCT *)lparam;
if (wparam == WM_KEYDOWN || wparam == WM_SYSKEYDOWN)
{
// -- PRINT 2 --
// print a message every time a key is pressed.
std::cout << "key was pressed " << std::endl;
}
else if (wparam == WM_DESTROY)
{
// return from message queue???
PostQuitMessage(0);
}
// Passes the keystrokes
// hook information to the next hook procedure in the current hook chain.
// That way we do not consume the input and prevent other threads from accessing it.
return CallNextHookEx(keyboardHook, nCode, wparam, lparam);
},
// install as global hook
GetModuleHandle(NULL), 0);
MSG msg;
// While thread was not signaled to temirnate...
while (WaitForSingleObject(ghStopEvent, 1) == WAIT_TIMEOUT)
{
// Retrieve the current messaged from message queue.
GetMessage(&msg, NULL, 0, 0);
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// Before exit the thread, remove the installed hook.
UnhookWindowsHookEx(keyboardHook);
// -- PRINT 3 --
std::cout << "thread is about to exit" << std::endl;
return 0;
}
int main(void)
{
// Create a signal event, used to terminate the thread responsible
// for captuting keyboard inputs.
ghStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
DWORD ThreadID;
HANDLE hThreadArray[1];
// -- PRINT 1 --
std::cout << "start capturing keystrokes" << std::endl;
// Create a thread to capture keystrokes.
hThreadArray[0] = CreateThread(
NULL, // default security attributes
0, // use default stack size
StaticThreadStart, // thread function name
NULL, // argument to thread function
0, // use default creation flags
&ThreadID); // returns the thread identifier
// Stop main thread for 3 seconds.
std::this_thread::sleep_for(std::chrono::milliseconds(3000));
// -- PRINT 4 --
std::cout << "signal thread to terminate gracefully" << std::endl;
// Stop gathering keystrokes after 3 seconds.
SetEvent(ghStopEvent);
// -- PRINT 5 --
std::cout << "from this point onwards, we should not capture any keystrokes" << std::endl;
// Waits until one or all of the specified objects are
// in the signaled state or the time-out interval elapses.
WaitForMultipleObjects(1, hThreadArray, TRUE, INFINITE);
// Closes the open objects handle.
CloseHandle(hThreadArray[0]);
CloseHandle(ghStopEvent);
// ---
// DO OTHER CALCULATIONS
// ---
// -- PRINT 6 --
std::cout << "exit main thread" << std::endl;
return 0;
}
Implementation details
The main requirement is the capturing of keystrokes for a certain amount of time. After that time, we should NOT exit the main program. What I thought would be suitable in this case, is to create a separate thread that will be responsible for the capturing procedure and using a event to signal the thread. I've used windows threads, rather than c++0x threads, to be more close to the target platform.
The main function starts by creating the event, followed by the creation of the thread responsible for capturing keystrokes. To fulfill the requirement of time, the laziest implementation I could think of was to stop the main thread for a certain amount of time and then signaling the secondary one to exit. After that we clean up the handlers and continue with any desired calculations.
In the secondary thread, we start by creating a low-level global keyboard hook. The callback is a lambda function, which is responsible for capturing the actual keystrokes. We also want to call CallNextHookEx so that we can promote the message to the next hook on the chain and do not disrupt any other program from running correctly. After the initialization of the hook, we consume any global message using the GetMessage function provided by the Windows API. This repeats until our signal is emitted to stop the thread. Before exiting the thread, we unhook the callback.
We also output certain debug messages throughout the execution of the program.
Expected behavior
Running the above code, should output similar messages like the ones bellow:
start capturing keystrokes
key was pressed
key was pressed
key was pressed
key was pressed
signal thread to terminate gracefully
thread is about to exit
from this point onwards, we should not capture any keystrokes
exit main thread
Your output might differ depending on the number of keystrokes that were captured.
Actual behavior
This is the output I'm getting:
start capturing keystrokes
key was pressed
key was pressed
key was pressed
key was pressed
signal thread to terminate gracefully
from this point onwards, we should not capture any keystrokes
key was pressed
key was pressed
key was pressed
A first glance into the output reveals that:
The unhook function was not called
The program keeps capturing keystrokes, which might indicate that something is wrong with the way I process the message queue
There is something wrong regarding the way I'm reading the messages from the message queue, but after hours of different approaches, I could not find any solution for the specific implementation. It might also be something wrong with the way I'm handling the terminate signal.
Notes
The closer I could get on finding an answer, here in SO, was this question. However the solution did not helped me as much as I wanted.
The provided implementation is a minimum reproducible example and can be compiled without the need to import any external libraries.
A proposed solution will be to implement the capturing-keystrokes functionality as a separate child process, where will be able to start and stop whenever we like. However, I'm more interested in finding a solution using threads. I'm not sure if this is even possible (it might be).
The above code does not contain any error handling. This was on purpose to prevent possible over bloated of the code.
For any questions you might have, feel free to comment! Thank you in advance for your time to read this question and possibly post an answer (it will be amazing!).
I think this is your problem:
while (WaitForSingleObject(ghStopEvent, 1) == WAIT_TIMEOUT)
{
// Retrieve the current messaged from message queue.
GetMessage(&msg, NULL, 0, 0);
TranslateMessage(&msg);
DispatchMessage(&msg);
}
The reason is that currently your loop can get stuck on the GetMessage() step forever and never again look at the manual-reset event.
The fix is simply to replace the combination of WaitForSingleObject + GetMessage with MsgWaitForMultipleObjects + PeekMessage.
The reason you've made this mistake is that you didn't know GetMessage only returns posted messages to the message loop. If it finds a sent message, it calls the handler from inside GetMessage, and continues looking for posted message. Since you haven't created any windows that can receive messages, and you aren't calling PostThreadMessage1, GetMessage never returns.
while (MsgWaitForMultipleObjects(1, &ghStopEvent, FALSE, INFINITE, QS_ALLINPUT) > WAIT_OBJECT_0) {
// check if there's a posted message
// sent messages will be processed internally by PeekMessage and return false
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
1 You've got logic to post WM_QUIT but it is conditioned on receiving WM_DESTROY in a low-level keyboard hook, and WM_DESTROY is not a keyboard message. Some hook types could see a WM_DESTROY but WH_KEYBOARD_LL can't.
What I thought would be suitable in this case, is to create a separate
thread that will be responsible for the capturing procedure
it's not necessary to do this if another thread will just wait for this thread and nothing to do all this time
you can use code like this.
LRESULT CALLBACK LowLevelKeyboardProc(int code, WPARAM wParam, LPARAM lParam)
{
if (HC_ACTION == code)
{
PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT)lParam;
DbgPrint("%x %x %x %x\n", wParam, p->scanCode, p->vkCode, p->flags);
}
return CallNextHookEx(0, code, wParam, lParam);
}
void DoCapture(DWORD dwMilliseconds)
{
if (HHOOK hhk = SetWindowsHookExW(WH_KEYBOARD_LL, LowLevelKeyboardProc, 0, 0))
{
ULONG time, endTime = GetTickCount() + dwMilliseconds;
while ((time = GetTickCount()) < endTime)
{
MSG msg;
switch (MsgWaitForMultipleObjectsEx(0, 0, endTime - time, QS_ALLINPUT, MWMO_INPUTAVAILABLE))
{
case WAIT_OBJECT_0:
while (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
break;
case WAIT_FAILED:
__debugbreak();
goto __0;
break;
case WAIT_TIMEOUT:
DbgPrint("WAIT_TIMEOUT\n");
goto __0;
break;
}
}
__0:
UnhookWindowsHookEx(hhk);
}
}
also in real code - usual not need write separate DoCapture with separate message loop. if your program before and after this anyway run message loop - posiible all this do in common message loop,
I am just learning to create a gui using the winapi, but i have run into an issue. I can create a window like this
#include "stdafx.h"
#include <windows.h>
int main()
{
HWND hwnd = CreateWindow(L"STATIC",NULL,WS_VISIBLE|WS_SYSMENU|WS_CAPTION,0,0,600,600,NULL,NULL,NULL,NULL);
UpdateWindow(hwnd);
MSG msg;
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
_gettch();
}
But the windows will not close when the close button is clicked, and the window can not be dragged around or moved. I was wondering how i would enable these features of the window.
Static windows are not there for normal windows, you should try and look up how to register and handle your own class with RegisterWindowEx then use the same class name to create a window. You have to have your own window procedure in order to handle messages.
All window classes registered by the system run their own default window procudure and as far as I know none of them handle WM_CLOSE ( that is the close button ) this is why you can't close it.
For you main windows always use something like WS_OVERLAPPEDWINDOW so it'll be clear if it's okay or not and from that eliminate the flags you don't need.
How you set it up :
WNDCLASSEX wndcls;
HWND hMainWnd;
// Register your own window class
ZeroMemory(&wndcls,sizeof(WNDCLASSEX));
wndcls.cbSize=sizeof(WNDCLASSEX);
wndcls.style=CS_VREDRAW+CS_HREDRAW;
wndcls.lpfnWndProc=&appWndFunc;
wndcls.hInstance=hInstance;
wndcls.hIcon=hMainIcon; // or just LoadIcon(hInstance,MAKEINTRESOURCE(IDI_MAIN_ICON))
wndcls.hIconSm=hMainIcon;
wndcls.hCursor=LoadCursor((HINSTANCE)NULL,IDC_ARROW);
wndcls.hbrBackground=(HBRUSH)COLOR_APPWORKSPACE;
wndcls.lpszClassName="myWndClass";
if (RegisterClassEx(&wndcls)==0)
{
// failed to register class name
return false;
}
// Create window with your own class
hMainWnd=CreateWindowEx(0,\
"myWndClass","widnow title",\
WS_OVERLAPPEDWINDOW|WS_VISIBLE,\
0,\
0,\
250,\
250,\
hMainWnd,NULL,hInstance,NULL);
if (hMainWnd==(HWND)NULL)
{
// failed to create main window
return false;
}
Then your main loop :
bool bAppMainLoop=false
while(!bAppMainLoop)
{
WaitMessage();
while(PeekMessage(&emsg,NULL,0,0,PM_NOREMOVE))
{
if(GetMessage(&emsg,NULL,0,0)==0)
{
bAppMainLoop=true;
break;
}
TranslateMessage(&emsg);
DispatchMessage(&emsg);
}
}
This is a bit more than usual setup, so let me explain , in order to not burn CPU, you wait for a message with WaitMessage, it'll block until something happens, like move window, click, paint etc. PeekMessage will return true if there is a message so calling it in a while loop will make sure it drains the message quene, GetMessage will obtain the message if it returns 0 it means that your app called the PostQuitMessage(0) so a WM_QUIT arrived was found in the message loop that means it's time to break out from the message loop. The rest Translate and Dispatch does what it name says.
Finally you need your own window procedure :
LRESULT CALLBACK appWndFunc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
if (uMsg==WM_CLOSE)
{
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd,uMsg,wParam,lParam);
}
DefWindowProc is essential that handles all commonly occurring messages from the system, thus you don't need to handle those here. You simply respond to the WM_CLOSE message which is sent when you want to close the window and post a quit message into the message loop that you will catch and exit.
Additional info :
It's not required to release your stuff since windows does that for you so it wont be locked the next time you start your program , but it's a good practice to at least Unregister your window class after your main loop.
Btw that is the wrong main function : WinMain that is the correct one. Plus to avoid even more bugs make sure you compile a windows GUI application.
I think i am ruining in to a deadlock, have been searching for the solution over hours. Any suggestions?
What i am trying to do is: ater startGame button click, create thread that send request to the server and then gets the answer, after the answer the thread must send a message to Initialize game window to the main proc...
Message Proc that belongs to WinMain:
LRESULT CALLBACK WndProc(HWND myWindow, UINT messg, WPARAM wParam, LPARAM lParam)
{
switch (messg) {
case WM_STARTGAME:
DestroyWindow(hStartGameButton);
DestroyWindow(hHistoryButton);
InitGameWindow(myWindow);
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDC_STARTGAME_BUTTON:
{
parametros param;
param.myWindow = myWindow;
start_game = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadStartGame, (LPVOID)&myWindow, 0, NULL);
}
}
}
And this is the thread:
DWORD WINAPI ThreadStartGame(LPVOID param){
HWND w = (HWND)param;
DWORD n;
BOOL ret;
mensagem resposta;
mensagem msg;
msg.tipo = COMECAR_JOGO;
msg.verifica = true;
if (!WriteFile(hPipe, &msg, (DWORD)sizeof(mensagem), &n, NULL)) {return 0;}
ret = ReadFile(hPipeN, &resposta, (DWORD)sizeof(mensagem), &n, NULL);
if (!ret || !n) {
return false;
}
PostMessage(w, WM_STARTGAME, NULL, NULL); // <- THIS GETS EXECUTED BUT NOTHINK HAPPENS AFTER
return 0;
}
I don't think there is any deadlock here.
start_game = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadStartGame, (LPVOID)&myWindow, 0, NULL);
This line passes the address of the HWND to the thread (&myWindow)
HWND w = (HWND)param;
This line uses the adress itself as HWND and the SendMessage sends the message to this address which is not a HWND.
Try modifying to
start_game = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadStartGame, (LPVOID)myWindow, 0, NULL);
W/o even looking at the code, I can tell you right away: do not use SendMessage between threads. I recommend reading Psychic debugging: The first step in diagnosing a deadlock is a simple matter of following the money and Preventing Hangs in Windows Applications:
Use asynchronous window message APIs in your UI thread, especially by replacing SendMessage with one of its non-blocking peers: PostMessage, SendNotifyMessage, or SendMessageCallback
...
Any blocking call that crosses thread boundaries has synchronization properties that can result in a deadlock. The calling thread performs an operation with 'acquire' semantics and cannot unblock until the target thread 'releases' that call. Quite a few User32 functions (for example SendMessage), as well as many blocking COM calls fall into this category.
For starters, you're unlikely supposed to do that in the first place. Quoting MSDN:
A thread in an executable that calls the C run-time library (CRT) should use the _beginthreadex and _endthreadex functions for thread management rather than CreateThread and ExitThread; this requires the use of the multithreaded version of the CRT. If a thread created using CreateThread calls the CRT, the CRT may terminate the process in low-memory conditions.
Second, your thread can be worker or UI thread, from the first type you must not call most of the window related functions, as it has no message pump. DestroyWindow is such. (So many times I tried to use MessageBox despite my own comment a few lines upper telling it's forbidden in that function ;).
From worker threads the usual method is to use PostThreadMessage and react on the UI thread. (If you have multiple UI threads, I don't know the rules, was never brave enough for that.)
I'm programming a little game, and I set the lpfnWndProc to DefWindowProc
and after that, I made a loop in that way:
MSG lastMessage;
while (true)
{
if (PeekMessage(
&lastMessage,
this->getWindow(),
0, 0,
PM_REMOVE))
{
TranslateMessage(&lastMessage);
DispatchMessage(&lastMessage);
}
}
So how do I handle the Close Window event in that case?
First of all, this is not how you write a message loop: it will take 100% CPU while waiting for messages, and won't remove messages for other windows from the queue. It will also never terminate. See here for an example of a message loop.
About closing windows: DefWindowProc will handle WM_CLOSE automatically and destroy your window. If you want your application to terminate when the window is closed, you need to handle WM_DESTROY and call PostQuitMessage(0) from it. This means you will need your own window procedure instead of DefWindowProc.
If you want WindowProc to be handled by a class, you do something like
class CWindow
{
static LRESULT WindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
CWindow* self;
if(uMsg == WM_CREATE)
{
self = (CWindow*)((LPCREATESTRUCT)lParam)->lplpCreateParams;
}
else
self = GetWindowLong(hwnd,GWL_USERDATA);
if(self){
switch(uMsg){
case WM_CREATE:
return self->OnCreate(hwnd,(LPCREATESTRUCT)lParam);
case WM_CLOSE:
self->OnClose();
return 0;
// etc.
}
}
return DefWindowProc(hwnd,uMsg,wParam,lParam);
}
int OnCreate(HWND hwnd,LPCREATESTRUCT lpcs)
{
m_hwnd = hwnd;
SetWindowLong(m_hwnd,GWL_USERDATA,this);
return 0;
}
}
Making sure of course to pass 'this' as the last parameter to CreateWindow(Ex).
Next, In your message loop, you MUST check for WM_QUIT messages and use that as a cue to exit the loop. Also, NEVER do a filter on hwnd as that will prevent your application loop from dispatching messages for other windows on your thread. And many windows libraries create message windows on threads to facilitate inter process (and thread) comms. If you dont process all windows messages then (a) your game will eventually run out of memory, and (b) the entire system may start to act funny as your application will make IPC messages deadlock, or time out.
Also, WM_CLOSE is (usually) sent via SendMessage, not PostMessage. Sent messages are delivered straight to the window proc and can't be filtered in the app loop.