Sign in to follow this  
littlekid

[C++] possible to have win32 message loop on another thread?

Recommended Posts

Hi I am just wondering is it possible to have the win32 message loop on another thread. Currently I tried placing the message loop on another thread and use AttachThreadInput(). However when running, the cursor forever stays in the "hourglass" mode and I can't click or do anything. Here is the e.g full code using PPL to create a agent for the message loop
#include <CodeAnalysis\Warnings.h>

#pragma warning(push)
#pragma warning(disable : ALL_CODE_ANALYSIS_WARNINGS)

#include <iostream>
#include <ppl.h>
#include <agents.h>
#include <Windows.h>

LRESULT __stdcall WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	return DefWindowProc(hwnd, message, wParam, lParam);
}

class MessageAgent : public Concurrency::agent
{
	HWND hWindow;

public:
	MessageAgent(HWND hWindow)
		: hWindow(hWindow)
	{
		
	}

	void run()
	{
		SIZE_T windowThread = GetWindowThreadProcessId(hWindow, nullptr);
		SIZE_T currThread = GetCurrentThreadId();

		std::cout << "Current Thread: " << currThread << "\n";
		std::cout << "Window Thread: " << windowThread << "\n";

		if (AttachThreadInput(currThread, windowThread, TRUE) == FALSE)
			std::cout << "Attach Thread 1 fail\n";

		bool doLoop = true;
		MSG msg;

		while (doLoop)
		{
			while(PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE) != FALSE)
			{
				if (msg.message == WM_QUIT)
				{
					doLoop = false;
				}

				TranslateMessage(&msg);

				DispatchMessage(&msg);
			}
		}

		done();
	}
};

int main()
{
	WNDCLASSEX windowClassEx;

	windowClassEx.cbSize = sizeof(WNDCLASSEX);
	windowClassEx.cbClsExtra = 0;
	windowClassEx.cbWndExtra = 0;
	windowClassEx.style = CS_CLASSDC;
	windowClassEx.hInstance = GetModuleHandle(nullptr);
	windowClassEx.lpfnWndProc = WndProc;
	windowClassEx.lpszMenuName = 0;
	windowClassEx.lpszClassName = L"Window Class Test";
	windowClassEx.hCursor = LoadCursor(nullptr, IDC_ARROW);
	windowClassEx.hIcon = LoadIcon(windowClassEx.hInstance, IDI_APPLICATION);
	windowClassEx.hIconSm = LoadIcon(windowClassEx.hInstance, IDI_APPLICATION);
	windowClassEx.hbrBackground = static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH));

	if (!RegisterClassEx(&windowClassEx))
	{
		std::cout << "Fail to register window class\n";
	}

	SIZE_T windowStyleFlags = WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_OVERLAPPED;

	HWND windowHandle = CreateWindowEx(WS_EX_CLIENTEDGE, L"Window Class Test", L"Parallel Window Test",
		windowStyleFlags , 0, 0, 1024, 768, 0, 0, GetModuleHandle(nullptr), nullptr);

	if (windowHandle == nullptr)
	{
		std::cout << "Fail to create window\n";
	}

	ShowWindow(windowHandle, SW_SHOWNORMAL);
	UpdateWindow(windowHandle);
	SetFocus(windowHandle);

	std::cout << "Current Thread: " << GetCurrentThreadId() << "\n";

	MessageAgent msgAgent(windowHandle);
	msgAgent.start();
	Concurrency::agent::wait(&msgAgent);

	UnregisterClass(L"Window Class Test", GetModuleHandle(nullptr));

	return 0;
}

#pragma warning(pop)


Share this post


Link to post
Share on other sites
It is certainly possible to have the message loop in a different thread, but it can be quite painful to do it that way.

I've found it much easier to leave the message loop in the original thread and run the game and rendering in a different thread (create all contexts in that one). Then it's a no brainer.

Share this post


Link to post
Share on other sites
hmm thats possible, but as a learning experience, is there anyway to make it work such that the message loop is on another thread?

I have read up msdn, and most of the articles just suggest attaching the threads input using AttachThreadInput(). But even after doing so the window still get into the "hourglass cursor" mode and become unresponsive.

Share this post


Link to post
Share on other sites
It probably is possible, but when I tried, I ended up hitting the monitor with the keyboard, shouting "fuck, fuck, fuck!", since a lot of Windows GUI functions assume that they are called from the original thread and silently fail if they aren't. Some of them are well-documented, some aren't. That can be super frustrating if you spend 2 days on something so trivial and have no clue just why for heaven's sake it won't work.

On the other hand, spawning off a thread, creating a context there, and doing the rendering in there was as much as 3 minutes of work.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this