Windows message pumps and how Operating system sends messages

  • Thread starter Thread starter barman_
  • Start date Start date
B

barman_

Guest
Hi,

I have an application that has many plugins and all added as forms into one window (as sheets of a tabbed pane). The thing is there are many components on each of plug ins and some of these components cause time consuming jobs due to processing of windows messages. There is one message pump (message loop, excuse me if I do not use the terminology correctly). Time consuming jobs on one of the plugins cause complete application to lag.

I am aware that I can try to get rid of time consuming jobs in processing messages. That is at hand, but what I want is different message pumps to run for each plug in and in this way a lag occurring in windows message pump of a plugin will not cause lag in main window.

When I read following in Microsoft documentation:

Window Messages - Windows applications

"For each thread that creates a window, the operating system creates a queue for window messages. This queue holds messages for all the windows that are created on that thread. The queue itself is hidden from your program. You cannot manipulate the queue directly. However, you can pull a message from the queue by calling the GetMessage function."

I thought that if I create each window in separate thread, it will be enough. I tried, create 2 windows in separate threads and saw that their message pumps are not effecting one another. But these 2 windows are completely separated.

When I created one of them as child of the other, although the message pumps are separate, if there is a time consuming job in message loop of child, the parent is also lagged. Somehow the operating system is pausing the message queue of parent window. Below is the way I do it.

Is it possible what I want? Can I create a child window that has a separate message pump and not lagging the parent. And is it the correct way? If not what is the correct way to separate message pumps between parent and child windows?

Note: I try to use win32 api


#ifndef UNICODE
#define UNICODE
#endif

#define _CRT_SECURE_NO_WARNINGS

#include <windows.h>
#include "resource.h"
#include <stdio.h>

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
INT_PTR CALLBACK DialogProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

HWND _hwnd1;
HWND _hwnd2;

DWORD WINAPI threadSvc(LPVOID lpParam);
DWORD WINAPI threadSvc_1(LPVOID lpParam);
DWORD WINAPI threadSvc_2(LPVOID lpParam);

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{



/*Start a thread for trial*/
#if 1
DWORD dwThreadId1 = NULL;
HANDLE myThread1 = CreateThread(NULL, // default security attributes
0, // use default stack size
threadSvc_1, // thread function name
/*pDataArray*/&hInstance,// argument to thread function
0, // use default creation flags
&dwThreadId1); // returns the thread identifier

if (myThread1 == NULL)
OutputDebugStringA("thread 1 failed to start\n");
else
OutputDebugStringA("thread 1 started\n");
#endif
Sleep(2000);

#if 1
DWORD dwThreadId2 = NULL;
HANDLE myThread2 = CreateThread(NULL, // default security attributes
0, // use default stack size
threadSvc_2, // thread function name
/*pDataArray*/&hInstance,// argument to thread function
0, // use default creation flags
&dwThreadId2); // returns the thread identifier
if (myThread2 == NULL)
OutputDebugStringA("thread 2 failed to start\n");
else
OutputDebugStringA("thread 2 started\n");
#endif

// wait
while (1) Sleep(1000);



// Run the message loop. - no need for a message loop as it is does not have a window.
// MSG msg = { };
// while (GetMessage(&msg, NULL, 0, 0))
// {
// TranslateMessage(&msg);
// DispatchMessage(&msg);
// }

return 0;
} //wWinMain returns

LRESULT CALLBACK WindowProc1(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
DWORD threadId = GetCurrentThreadId();
char buf[512] = {};
sprintf(&buf[0], "barman: WindowProc1 [threadId=%08ul] [msgId=%04u]\n", threadId, uMsg);
OutputDebugStringA(buf);

switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;

case WM_SETCURSOR:
OutputDebugStringA("WM_SETCURSOR \n");
return 0;

#if 1
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
EndPaint(hwnd, &ps);
}
return 0;
#endif
}
// to default window processor
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

LRESULT CALLBACK WindowProc2(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
DWORD threadId = GetCurrentThreadId();
char buf[512] = {};
sprintf(&buf[0], "barman: WindowProc2 [threadId=%08ul] [msgId=%04u]\n", threadId, uMsg);
OutputDebugStringA(buf);

switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;

case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 5));
EndPaint(hwnd, &ps);
}
return 0;
#if 0
case WM_NCHITTEST:
{
PostMessage(_hwnd1, WM_NCHITTEST, wParam, lParam);
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
#endif
case WM_LBUTTONDOWN:
{

sprintf(&buf[0], "barman: MOUSE CLICKED... [threadId=%ul]\n", threadId);
OutputDebugStringA(buf);
#if 1
/*To create a lag in msg queue 100 millions*/
for (long i = 0; i < 100000000; i++)
{
printf("de");
}
#endif
}
return 0;

} // switch case ends
// to default window processor
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

/*useless thread*/
DWORD WINAPI threadSvc(LPVOID lpParam)
{
while (1)
{
OutputDebugStringA("thread running\n");
Sleep(500);
}

return 0;
}

// start a window and register it then process its message queue
DWORD WINAPI threadSvc_1(LPVOID lpParam)
{

WNDCLASS wc1 = { };
const wchar_t CLASS_NAME_1[] = L"First sample window class ";
wc1.lpfnWndProc = WindowProc1; // win proc for the message pump
wc1.hInstance = *((HINSTANCE*)lpParam);
wc1.lpszClassName = CLASS_NAME_1;

RegisterClass(&wc1);

_hwnd1 = CreateWindowEx(0, // ex style id DWORD
CLASS_NAME_1, // class name
L"Learn to Program Windows 1 ", // window name
WS_OVERLAPPEDWINDOW // style
| WS_CLIPCHILDREN, // for parent not to overpaint the child window.
CW_USEDEFAULT, // Size and position
CW_USEDEFAULT, // Size and position
CW_USEDEFAULT, // Size and position
CW_USEDEFAULT, // Size and position
NULL, // parent window
NULL, // ?? hMenu
*((HINSTANCE*)lpParam), // hInstance
NULL); // lpParam - type LPVOID->long pointer of type void

if (_hwnd1 == NULL)
{
return 0;
}

ShowWindow(_hwnd1, 5);
MSG msg = { };
#if 1

char buf[512] = {};

BOOL getMessageResult = false;

while (getMessageResult = GetMessage(&msg, NULL, 0, 0) != 0)
{
if (getMessageResult == -1)
{
sprintf(&buf[0], "task 1 message loop get message returned error [threadID:%04ul]\n", GetCurrentThreadId());
OutputDebugStringA(buf);
return 0;
}
else
{
sprintf(&buf[0], "Thread-1 before Dispatch Message [threadId:%04ul] [WHND:%d]\n", GetCurrentThreadId(), msg.hwnd);
OutputDebugStringA(buf);
TranslateMessage(&msg);
DispatchMessage(&msg);
}


sprintf(&buf[0], "Thread-1 after Dispatch Message [threadId:%04ul] [WHND:%d]\n", GetCurrentThreadId(), msg.hwnd);
OutputDebugStringA(buf);
}
#endif


#if 0
//PeekMessage loop example
while (WM_QUIT != msg.message)
{
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) > 0) //Or use an if statement
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
#endif
return 0;
}

DWORD WINAPI threadSvc_2(LPVOID lpParam)
{
WNDCLASS wc2 = { };
const wchar_t CLASS_NAME_2[] = L"Second sample window class";
wc2.lpfnWndProc = WindowProc2;
wc2.hInstance = *((HINSTANCE*)lpParam);
wc2.lpszClassName = CLASS_NAME_2;

RegisterClass(&wc2);

_hwnd2 = CreateWindowEx(0,
CLASS_NAME_2,
L"Learn to Program Windows 2 ",
WS_CHILD // Styles that are used.
| WS_VISIBLE
//| WS_CAPTION
//| WS_SYSMENU
//| WS_THICKFRAME
//| WS_MINIMIZEBOX
//| WS_MAXIMIZEBOX
/* WS_OVERLAPPEDWINDOW*/,
// Size and position
CW_USEDEFAULT, CW_USEDEFAULT, 300, 300,
_hwnd1 /*NULL*/, // parent window
NULL,
*((HINSTANCE*)lpParam),
NULL);

if (_hwnd2 == NULL)
{
return 0;
}

ShowWindow(_hwnd2, 5);
MSG msg = { };

#if 1
while (GetMessage(&msg, NULL, 0, 0))
{
if (msg.hwnd == _hwnd2)
{
TranslateMessage(&msg);
OutputDebugString(L"Thread-2 before Dispatch Message\n");
DispatchMessage(&msg);
OutputDebugString(L"Thread-2 after Dispatch Message\n");
}
else
{
OutputDebugString(L"Thread-2 ignored a msg\n");
}


}
#endif


#if 0
//PeekMessage loop example
while (WM_QUIT != msg.message)
{
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) > 0) //Or use an if statement
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
#endif

return 0;
}

Continue reading...
 
Back
Top