Wrong again. Try the following code with Windows SDK 7.1+ and run on Windows7. In short, you're totally fine calling GUI function from any thread.
As a side note, it's also fine to call GDI function, which I (and many people) did for background GDI text rendering onto textures in game project (however it's a bit complex to demonstrate here).
PS. Can someone please detach this to a new thread?
Code: Select all
#include <Windows.h>
#include <stdio.h>
const TCHAR szAppName[] = L"Test";
CRITICAL_SECTION ListBoxLocker;
HWND hListBox = NULL;
LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp);
// Test Thread to work with list box: it generate some item and append to list box
DWORD WINAPI TestThread(LPVOID lpParameter) {
TCHAR text[256];
int i, num = (int)lpParameter; // ugly casting pointer to int, but hey it's just a test
for ( i=0; i<50; i++ ) {
_snwprintf (text, 256, L"Test Thread #%d", i+num );
// EnterCriticalSection(&ListBoxLocker); // It seems windows do protection and we are good without lock here
SendMessage(hListBox, LB_ADDSTRING, 0, (LPARAM)text);
// LeaveCriticalSection(&ListBoxLocker);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) {
MSG msg;
WNDCLASSEX wc;
HWND hwnd;
// Initialize Our locker
InitializeCriticalSectionAndSpinCount ( &ListBoxLocker, 100 );
// Standard window creation code
wc.cbClsExtra = 0;
wc.cbSize = sizeof(wc);
wc.cbWndExtra = 0;
wc.hbrBackground= (HBRUSH)COLOR_WINDOW;
wc.hCursor = LoadCursor(NULL,IDC_ARROW);
wc.hIcon = NULL;
wc.hIconSm = NULL;
wc.hInstance = hInstance;
wc.lpfnWndProc = WindowProc;
wc.lpszClassName= szAppName;
wc.lpszMenuName = NULL;
wc.style = CS_VREDRAW|CS_HREDRAW;
RegisterClassEx(&wc);
hwnd = CreateWindowEx( 0, szAppName, szAppName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 640, 640,
NULL, NULL,
hInstance, NULL);
ShowWindow(hwnd,SW_SHOW);
UpdateWindow(hwnd);
// Standard message loop
while ( GetMessage(&msg, 0, 0, 0) ) {
TranslateMessage(&msg);
DispatchMessage(&msg);
if ( msg.message == WM_QUIT ) break;
}
return msg.wParam;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
switch(msg) {
case WM_CREATE:
{
CREATESTRUCT* lpcs = (CREATESTRUCT*)lp;
// Create our child list box here
hListBox = CreateWindowEx(WS_EX_CLIENTEDGE, L"Listbox", NULL,
WS_CHILD | WS_VISIBLE | WS_VSCROLL,
10, 10, lpcs->cx-20,
lpcs->cy-20, hwnd, (HMENU)1,
lpcs->hInstance, NULL);
// Let's start some thread to work with list box
CreateThread ( NULL, 0, TestThread, (void*)1, 0, NULL );
CreateThread ( NULL, 0, TestThread, (void*)100, 0, NULL );
CreateThread ( NULL, 0, TestThread, (void*)200, 0, NULL );
} break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd,msg,wp,lp);
}