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

Started by
0 comments, last by littlekid 13 years, 12 months ago
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)


Advertisement
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.
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.
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.

This topic is closed to new replies.

Advertisement