The title pretty much summarizes what my problem is. I have this function shown below and when I press the button to join the thread the application stops responding. I'm fairly new to multithreading in c++ and I don't really know what I am doing or why this is occurring.
HWND hwnd;
//this stops the declaration of the thread from saying that hwnd doesn't exist
bool stopRaidAction;
void JoinLoop(HWND hwnd)
{
for (std::string tokenString; std::getline(std::cin,tFileContents,'\n');) {
if(stopRaidAction==false)
{
if(tokenString.length()==0){break;}
if(tokenString.length()!=0){
//send post request to join the server using token through proxy
}
}
if(stopRaidAction){break;}
}
}
std::thread joinThread(JoinLoop, hwnd);
The issue is with the "JOIN_RAID" thing
LRESULT CALLBACK WindowProcessMessages(HWND hwnd, UINT msg, WPARAM param, LPARAM lparam) {
switch (msg) {
case WM_CREATE:
Controls(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_COMMAND:
{
if ((HIWORD(param) == BN_CLICKED) && (lparam != 0))
{
switch (LOWORD(param))
{
case JOIN_RAID:
stopRaidAction=false;
MessageBeep(MB_OK);
joinThread.join();
break;
case STOP_RAID:
stopRaidAction=true;
MessageBeep(MB_OK);
break;
}
}
break;
}
default:
return DefWindowProc(hwnd, msg, param, lparam);
}
return 0;
}
joinThread.join() blocks the calling thread until JoinLoop() exits. If you do that call in your main UI thread, you will be blocking your message loop from being able to process new messages. That is why your UI freezes.
JoinLoop() is waiting on 2 conditions - user input being entered, and stopRaidAction being true while processing that input. Even if the user enters input, your main thread is setting stopRaidAction to false before calling join(), so unless JoinLoop() itself, or a 3rd thread, sets stopRaidAction to true then JoinLoop() won't exit, and so join() won't unblock.
Even if stopRaidAction were able to be set to true while join() is waiting, JoinLoop() still won't exit until the next time that user input is entered, so it can see the new stopRaidAction value. There is no way to unlocking a pending std::getline() call. So you should rewrite the way you are handling console input so you can stop waiting for input in a timely manner. See Win32 - read from stdin with timeout, for instance.
std::thread::join() is not something you should be calling until you are ready to terminate the worker thread. Which this code is not doing.
Given the code shown, it may make more sense to not create the thread at all until JOIN_RAID is clicked, and then terminate the thread when `STOP_RAID' is clicked, eg:
bool stopRaidAction = false;
std::thread joinThread;
void JoinLoop(HWND hwnd)
{
std::string tokenString;
while (!stopRaidAction) {
// read input with timeout...
if(tokenString.empty()){ break; }
//send post request to join the server using token through proxy
}
}
LRESULT CALLBACK WindowProcessMessages(HWND hwnd, UINT msg, WPARAM param, LPARAM lparam) {
switch (msg) {
case WM_CREATE:
Controls(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_COMMAND:
{
if ((HIWORD(param) == BN_CLICKED) && (lparam != 0))
{
switch (LOWORD(param))
{
case JOIN_RAID:
stopRaidAction=false;
MessageBeep(MB_OK);
joinThread = std::thread(JoinLoop, hwnd);
break;
case STOP_RAID:
stopRaidAction=true;
MessageBeep(MB_OK);
if (joinThread.joinable()) joinThread.join();
break;
}
}
break;
}
default:
return DefWindowProc(hwnd, msg, param, lparam);
}
return 0;
}
But this is just speculation since you did not explain what you are actually trying to achieve in the first place.
Update:
IT WAS THE FOR LOOP. I am literally dying. I don't even know how many hours I spent debugging only to find out that the for loop was messed up and causing the hangs.
Related
I am making an program and would like to have my program restarted when a person tries to resize the screen.
So far from searching the internet i've found that it's not possible to ''re-run your application'' as with code.
Everyone refers to just close and rerun it, but that's not what i want, i want the code to be doing that.
So i was thinking, can i not re-run winmain? and ' kill ' the current winmain instance in my code, but keep the ''shell (application?)'' active?
this is what i am trying to do:
LRESULT CALLBACK Proc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
switch (Message)
{
case WM_SIZE: //Check if the window has been resized
WinMain(this, this, this, NULL);
// or restart application code.
break;
case WM_PAINT: // we need to paint? lets paint!
if (DrawUI)
Render(true);
else
Render(false);
break;
case WM_CREATE:
return DwmExtendFrameIntoClientArea(hWnd, &pMargin); // extension of window frame into client area
break;
case WM_DESTROY:
PostQuitMessage(0); // We need to use this to exit a message loop
break;
default:
return DefWindowProc(hWnd, Message, wParam, lParam); // Making sure all messages are processed
break;
}
}
please see the code under WM_SIZE: that's what im trying to do, but i don't know how to do this correctly, and how to close the previous winmain.
Hi guys.
I have some overlay with lua support.
I need to create some WndProc callbacks, so I hooked WndProc of target window using SetWindowLong and saving old one
LRESULT CALLBACK nProc(HWND hWnd, UINT _Msg, WPARAM wP, LPARAM lP) // its new wndProc
{
switch (_Msg)
{
case WM_CUT: case WM_COPY: case WM_PASTE: case WM_CLEAR:
return 1;
case WM_DESTROY: case WM_NCDESTROY:
UnhookWndP(); // switching back to original wndProc
return 1;
case WM_KEYDOWN: case WM_KEYUP: case WM_LBUTTONDBLCLK: case WM_LBUTTONDOWN: case WM_LBUTTONUP: case WM_RBUTTONDBLCLK: case WM_RBUTTONDOWN: case WM_RBUTTONUP: case WM_MOUSEWHEEL:
try
{
if (_Msg == WM_KEYUP && wP == 120) // restart LuaState
{
if (LuaInit)
DelLua();
else
CreLua();
}
for (luabridge::LuaRef f : wndCall) // call all our WndProc Lua callbacks
{
if (Msg != NULL && wP != NULL && f.isFunction() && f.isFunction() && lua_gettop(L) == 0)
{
f((int)_Msg, wP); // always in callstack when error occurs
}
}
}
catch (luabridge::LuaException ex) { Msg(ex.what()); }
default:
return CallWindowProc(OriWndP, hWnd, _Msg, wP, lP);
}
}
Created global function for adding callback, which is saving func to wndCall Vector(LuaRef)
Lua part is working fine. It shows messages of WM_KEY... events successfully.
The only problem is: When i hold some button or spamming commands I got Crash with Random error :(
I think its because CALLBACK got hit multiple times at one tick and something got broken in LuaState or idk.
Please help me find a solution or some extra checks for WndProc func.
Is it possible to capture the window messages/events inside the Translate/Dispatch Message loop?
this is the Message process method for the window
LRESULT CALLBACK MsgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_KEYDOWN:
PressedKey[wParam] = true;
break;
case WM_KEYUP:
PressedKey[wParam] = false;
break;
case WM_SIZE:
break;
default:
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
and here is Translate/Dispatch Message loop
void MyScreen::RunScreenMainLoop()
{
while (WM_QUIT != msg.message)
{
//I wanna handle the messages here as well!
switch (msg.message)
{
case WM_SIZE:
show("size event called");
break;
default:
break;
}
if (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
//do other stuff
}
}
}
but it never goes inside the switch statement , is there a work a round to do this?
One obvious problem appears to be that you are reading msg.message before it has been initialized. Note that you are reading msg.message before calling PeekMessage. Of course, since we cannot see where msg has been declared, perhaps the real code doesn't suffer this problem.
Now, the main issue is that WM_SIZE is not a queued message and does not arrive via the message queue. There is an important distinction between asynchronous queued messages like input messages, timer messages, paint messages, and synchronous messages that are delivered direct to the window procedure. And WM_SIZE is non-queued, synchronous.
You can learn that this is so from the documentation which says:
A window receives this message through its WindowProc function.
You won't catch it with GetMessage, PeekMessage etc. The way to intercept this message is from code inside the window proc.
To learn more about queued and non-queued messages, you can start with this topic from MSDN: About Messages and Message Queues.
That is not how your message loop should look. Try this instead:
void MyScreen::RunScreenMainLoop()
{
MSG msg;
while (1)
{
if (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE))
{
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
//do other stuff
}
}
}
Then intercept messages for specific windows by subclassing those windows:
Subclassing Controls
LRESULT CALLBACK MySubWndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
switch (msg)
{
case WM_SIZE:
show("size event called");
break;
case WM_NCDESTROY:
RemoveWindowSubclass(hWnd, MySubWndProc, uIdSubclass);
break;
// other case statements as needed...
}
return DefSubclassProc(hWnd, msg, wParam, lParam); // will dispatch the message to MsgProc()
}
hWnd = CreateWindowEx(...);
SetWindowSubclass(hWnd, MySubWndProc, 0, 0);
You wrote the message pump, so you can freely add code to process messages in you rmessage loop. For instance, if you don't want WM_CHAR conversion, don't call TranslateMessage(). If you want normal windows to have dialog-style tab navigation, call IsDialogMessage(). You can literally go crazy here.
Thread messages work in the same way. Thread messages don't have a window, so DispatchMessage() does nothing to them. You have to handle those in your message pump.
However, keep in mind that if you enter a dialog box or something else that uses its own message pump, your customizations will be lost. Here's an explanation that uses thread messages.
MFC, ATL, Qt, WPF, etc. may also have their own message pump setups that you have to watch for (or their own message pumps, period, in which case you'll have to see if the API provides a hooking mechanism).
if you just wanna handle your messagens in loop, is just access the MSG for get your messages information, like this:
void MyScreen::RunScreenMainLoop()
{
while (WM_QUIT != msg.message)
{
// Handle here your messages
if (msg.message == WM_LBUTTONDOWN) // Mouse Left Button Event
{
MessageBox(NULL, L"You Clicked!", L"Info", MB_OK);
}
//
if (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
//do other stuff
}
}
}
I've read everywhere that using windows messages is preferable to DirectInput. Despite this, there are many DirectInput tutorials and barely any for dealing with keyboard in Windows messaging. After not finding any good sources, I began to try it on my own.
I made two 256 member bool arrays to hold if keys were pressed. I want to make it so that I can look at m_bKeyDown[256] to see if a key was pressed this frame, and m_bKeyDown to see if it is being held down, but not pressed this frame. My MsgProc switch statement is as follows:
LRESULT D3DApp::MsgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
switch(msg){
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_KEYDOWN:
if(m_bKeyPressed[wParam])
m_bKeyDown[wParam] = false;
else
m_bKeyDown[wParam] = true;
break;
m_bKeyPressed[wParam] = true;
case WM_KEYUP:
m_bKeyDown[wParam] = false;
m_bKeyPressed[wParam] = false;
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
I tested it by having it make a sound when I held down the F1 key. Ideally the sound should not repeat until I release the button and press it again:
if(m_bKeyDown[VK_F1])
m_fMod.FPlaySound(testSound);
There seems to be no difference though, the sound repeats when I hold down the button. How do I fix the loop or set up Windows messaging to do this? Am I on the right track or should I go a completely different direction?
Edit: I used iedoc's below example and now it does better, but the sound still plays three times before stopping, like there is a delay for some reason. Any idea how to avoid this?
try this:
LRESULT D3DApp::MsgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
switch(msg){
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_KEYDOWN:
if(!m_bKeyPressed[wParam])
{
m_bKeyDown[wParam] = true;
m_bKeyPressed[wParam] = true;
}
else
m_bKeyDown[wParam] = false;
break;
case WM_KEYUP:
m_bKeyDown[wParam] = false;
m_bKeyPressed[wParam] = false;
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
I'm working on a Windows game, and I have this:
bool game_cont;
LRESULT WINAPI WinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_QUIT: case WM_CLOSE: case WM_DESTROY: game_cont = false; break;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
int WINAPI WinMain(/*lots of parameters*/)
{
//tedious initialization
//game loop
while(game_cont)
{
//give message to WinProc
if(!GameRun()) game_cont = false;
}
return 0;
}
and I am wondering if there is a better way to do this (ignoring timers &c. for right now) than to have game_cont be global. In short, I need to be able to exit the while in WinMain from WinProc, so that if the user presses the closes out of the game in a way other that the game's in game menu, the program wont keep running in memory. (As it did when I tested this without the game_cont.. statement in WinProc.
Oh, and on a side note, GameRun is basically a bool that returns false when the game ends, and true otherwise.
Yes, use PeekMessage, it's the standard in game development.
This is the best approach, I believe:
int Run()
{
MSG msg;
while(true)
{
if(::PeekMessage(&msg,0,0,0 PM_REMOVE))
{
if(msg.message == WM_QUIT ||
msg.message == WM_CLOSE ||
msg.message == WM_DESTROY)
break;
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
else
{
//Run game code
if(!GameRun())
break;
}
}
}
Also, look at this (specially the first answer)
You could use exit.
Use atexit to make sure that WM_CLOSE gets to the message que when its time to exit.
I don't know what's the ultimate design here, but it's an idea.
You could make game_cont static to your main file which has WinMain/WinProc, but I don't know of a significantly better structure.
No, don't do that.
WM_QUIT is your flag. GetMessage return value indicates when WM_QUIT is encountered.
Your main window will never receive WM_QUIT, as it isn't sent to a window. WM_CLOSE will call DestroyWindow by default, so you don't need any special handling for that. Handle WM_DESTROY by calling PostQuitMessage, which results in WM_QUIT on your thread, the special return value from GetMessage, and stops your message dispatch loop.