I have a problem with my code, and after several hours, I can't seem to figure it out...
Problem: I'm trying to attempt to connect to a server every ten seconds. When the timer first elapses, the callback function is called just fine, but then it is called again immediately (without waiting ten seconds), and it keeps being called again and again and again repeatedly, as if the timer message is not getting removed from the queue. Can anyone help?
The timer is set here:
SConnect::SConnect()
{
hSimConnect = NULL;
Attempt();
SetTimer(hMainWindow, reinterpret_cast<UINT_PTR>(this), 10000, (TIMERPROC)TimerProc);
}
The (only) application message loop is here:
while (true)
{
PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
if (msg.message == WM_QUIT)
break;
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
//UPDATES
pSCObj->Update();
manager.Update();
Sleep(50);
}
And the timer callback function is here:
void CALLBACK SConnect::TimerProc(HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime){
SConnect *pSC = reinterpret_cast<SConnect *>(idEvent);
MSG wMsg;
if (!pSC->connected)
pSC->Attempt();
else{
pSC->connected = false;
}
}
I really appreciate any help... Please let me know if you need more info...
Sincerely,
Farley
I think this is happening because you are calling PeekMessage() in your message loop instead of GetMessage().
PeekMessage() will return FALSE if there are no messages in the queue. I don't know what the implementation of PeekMessage() is, but I could see it leaving the contents of the msg parameter alone if there are no messages in the queue. This means that when PeekMessage() returns FALSE, msg will contain the previous message in the queue. msg is then blindly passed to DispatchMessage(), which then dutifully will pass that to your window's window procedure. So as long as the WM_TIMER message is the last processed message, your timer callback will be called until another message is added to the queue.
You can fix this by using a more traditional message loop:
BOOL bRet;
while( (bRet = GetMessage( &msg, nullptr, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
pSCObj->Update();
manager.Update();
}
(Message loop adapted from the sample in the GetMessage() documentation.)
Since GetMessage() will block until there is a message in the queue, you don't need to call Sleep(), and your process will not use any CPU when there is nothing for it to do.
Problem is that the return value of PeekMessage() is not checked. On each loop, if there is no new message, PeekMessage leaves the contents of msg unchanged, and it is simply dispatched again.
Dispatching the messages only when PeekMessage() returns true fixes the problem:
while (true)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){
if (msg.message == WM_QUIT)
break;
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
//UPDATES
pSCObj->Update();
manager.Update();
Sleep(50);
}
Related
I'm trying to post message from one thread to a window in another thread via PostThreadMessage:
auto result = PostThreadMessage(mainThreadId, UserMessage::DestroyWindowRequest, 0, 0);
The MSDN says that
Messages sent by PostThreadMessage are not associated with a window. As a general rule, messages that are not associated with a window cannot be dispatched by the DispatchMessage function.
So I cann't just receive my message. Is it safe to handle a message manually in a message loop as in code below?
INT_PTR AbstractWindow::TranslateMessageLoop()
{
MSG msg{0};
BOOL gotMessage = FALSE;
static const BOOL hasError = -1;
PostMessage(windowHandle, UserMessage::MessageLoopTranslated, 0, 0);
while ((gotMessage = GetMessage(&msg, (HWND)NULL, 0, 0)) != 0 && gotMessage != hasError) {
// Here I process a message. I assume that the message is always destined for my main window,
// so I use it's handle - windowHandle.
if (!msg.hwnd && msg.message == UserMessage::DestroyWindowRequest) {
DestroyWindow(windowHandle);
}
else {
if (PreTranslateMessage(&msg) == FALSE) {
if (IsDialogMessage(windowHandle, &msg) == FALSE) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
}
return msg.wParam;
}
I know, MSDN suggest to use custom hooks, but it's a little bit overkill for me now.
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 have a function export OpenUI() in a DLL for UI view which creates the modeless main dialog and also has a modeless child dialog.
I am calling the function export OpenUI() from a separate DLL which is my controller.
How can I possibly execute more code after the function call if the message loop in OpenUI() prevents the function to return unless the dialog is closed?
I cannot remove the message loop because tab stop will not work without it.
I need the function export to return immediately after execution therefore I cannot use a modal dialog. Creating a subthread is also not an option because it caused issues in my application.
Any help is highly appreciated.
Thank you.
Pseudocode for my controller dll
typedef int(*DLL_OPENUI)();
int func()
{
HINSTANCE hinst_dll = LoadLibrary(dll_path);
DLL_OPENUI DllOpenUI = (DLL_OPENUI)GetProcAddress(hinst_dll, "OpenUI");
int ret = DllOpenUI();
//...execute more code here
return ret;
}
Pseudocode for my UI view dll
__declspec(dllexport) OpenUI()
{
hwnd_main = CreateDialog(hinst, IDD_MAIN, MainDlgProc);
ShowWindow(hwnd_main, SW_SHOW);
MSG msg;
while ((GetMessage(&msg, NULL, 0, 0) > 0))
{
if (!IsDialogMessage(hwnd, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return 0;
}
LRESULT CALLBACK MainDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_INITDIALOG:
OnInitDialog();
break;
}
}
void OnInitDialog()
{
CreateDialog(hinst, IDD_NAV_PANE, hwnd_main, NavPaneProc);
CreateDialog(hinst, IDD_NAV_TABS, hwnd_main, NavTabsProc);
CreateDialog(hinst, IDD_TAB_1, hwnd_main, TabOneProc);
CreateDialog(hinst, IDD_TAB_2, hwnd_main, TabTwoProc);
CreateDialog(hinst, IDD_TAB_3, hwnd_main, TabThreeProc);
CreateDialog(hinst, IDD_DETAILS_PANE_BG, hwnd_main, BackgroundProc);
CreateDialog(hinst, IDD_DETAILS_PANE, hwnd_main, DetailsPaneProc);
//...execute more code below
}
You have to have an active message loop, there's no way around that. One way to do it is to have one new function that would PeekMessage and execute the loop code only once. PeekMessage returns non-zero value if subsequent call to GetMessage would actually get a message and not block instead. ProcessOneMessage may look something like this:
BOOL ProcessOneMessage(HWND hwnd)
{
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
return TRUE;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return FALSE;
}
So, in your main code you have to call this function often (once every 10 ms should be fine). Whatever the code does it must call the function once in 10 ms. You will have a live window and run your code at the same time. But once the function returns TRUE the window was closed and you must not call the function again. For more info search for PeekMessage. The code is taken from this link: https://jeffpar.github.io/kbarchive/kb/074/Q74042/
I have a basic window program, the problem is when i try to create a window in a new thread after the message loop has already started the window displays for a second and disappears. does anyone no the reason for this? can a window be created in a separate thread?
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
::hInstance =hInstance; // initialize global variables
::nCmdShow =nCmdShow;
// start thread
HANDLE threadHandle = startThread(StartUp);
MSG msg;
while(GetMessage(&msg, 0, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
::CloseHandle(threadHandle);
return static_cast<int>(msg.wParam);
}
DWORD WINAPI StartUp(LPVOID lpParam) // new thread runs here
{
//code to create a new window...
}
what i figured out so far is that the GetMessage(&msg, 0, 0, 0) returns false if there are no windows in the current thread that it is in... is there a way to get a round this?
GetMessage() does not return FALSE if there are no windows. It is only looking for messages in the calling thread's message queue. You are specifying NULL for its hWnd parameter, so it will not care how messages get queued, whether by PostMessage() to a window, or by PostThreadMessage() to the thread's ID.
Each thread has its own local message queue and thus requires its own message loop. You can most certainly create a new window in a worker thread after the main thread has started its message loop. They are independent of each other. So whatever problem you are having in the main thread is not related to creating a window in a worker thread. Something else is going on.
With that said, keep in mind that GetMessage() returns a BOOL, which is actually an int, not a true bool. GetMessage() can return one of 3 different return values:
-1 if an error occurs
0 if a WM_QUIT message is retrieved
>0 if any other message is retrieved
You are only checking for 0 and != 0, so if GetMessage() returns -1 on error, you are treating it as a success instead of a failure. Even MSDN says not to do that:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms644936.aspx
Because the return value can be nonzero, zero, or -1, avoid code like this:
while (GetMessage( lpMsg, hWnd, 0, 0)) ...
The possibility of a -1 return value means that such code can lead to fatal application errors. Instead, use code like this:
BOOL bRet;
while( (bRet = GetMessage( &msg, hWnd, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
I'm creating game mario like in win32 GDI . I've implemented the new loop for game :
PeekMessage(&msg,NULL,0,0,PM_NOREMOVE);
while (msg.message!=WM_QUIT)
{
if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else // No message to do
{
gGameMain->GameLoop();
}
}
But my game just running until I press Ctrl + Alt + Del ( mouse cursor is rolling ).
I've always been using something like that:
MSG msg;
while (running){
if (PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
try{
onIdle();
}
catch(std::exception& e){
onError(e.what());
close();
}
}
onIdle is actual game lopp implementation, onError() is an error handler (takes error description as argument), and "running" is either a global bool variable or a class member. Setting "running" to false shuts down the game.
I think this really depends on your context. Windows will only send a WM_QUIT in response to your application calling PostQuitMessage. A common (if not great) solution here is to use a bool to exit the message loop when your program wants to end.
I guess the program may ask user for continue or exit, inside GameLoop function call. On exit Post WM_QUIT message to the window.
PostMessage(hWnd, WM_QUIT, 0, 0 );
hWnd-> The handle of the game window
else make a call to
DestroyWindow(hWnd);
This will send a WM_DESTROY to your window procedure. There you can call
PostQuitMessage(0);