I knew it's a bad habit to block a thread that has a window and it will cause serious problems, though that's what I do in the test program. PLEASE SAVE ALL YOUR WORKS before you run my test program. But it's reasonable for a thread to call CoInitialize and then wait for something to happened, they are allowed to do so on native Windows. Since builtin CoInitialize is diffrent from the native one in that the builtin will create an invisible window, and the most important, set_active_window calls SendMessage, the application will be frozen if the thread called CoInitialize is suspended and one of the other threads creates a new visible window which causes SetActiveWindow to be called.
Can we remove the code
/* send palette messages */
if (SendMessageW( hwnd, WM_QUERYNEWPALETTE, 0, 0 ))
SendMessageW( HWND_BROADCAST, WM_PALETTEISCHANGING, (WPARAM)hwnd, 0 );
from set_active_windows? I am really curious about when will an application receive WM_QUERYNEWPALETTE and WM_PALETTEISCHANGING messages. Anyway, MS platform SDK documents say an application can change its palette before others processed the WM_PALETTEISCHANGING message, so it’s safe to replace SendMessage with PostMessage.
The attachments: wnd.c is my test program, SendMessage.diff is the real patch.
ChangeLog: dlls/user/focus.c, dlls/user/dde/client.c, windows/painting.c, windows/syscolor.c, windows/sysparams.c - replace SendMessage with PostMessage or SendMessageTimeout to broadcast a message
Index: dlls/user/focus.c =================================================================== RCS file: /home/wine/wine/dlls/user/focus.c,v retrieving revision 1.6 diff -u -r1.6 focus.c --- dlls/user/focus.c 7 Oct 2003 03:40:23 -0000 1.6 +++ dlls/user/focus.c 26 Oct 2003 05:54:02 -0000 @@ -110,7 +110,7 @@ { /* send palette messages */ if (SendMessageW( hwnd, WM_QUERYNEWPALETTE, 0, 0 )) - SendMessageW( HWND_BROADCAST, WM_PALETTEISCHANGING, (WPARAM)hwnd, 0 ); + PostMessageW( HWND_BROADCAST, WM_PALETTEISCHANGING, (WPARAM)hwnd, 0 ); if (!(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_MANAGED)) SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE ); Index: dlls/user/dde/client.c =================================================================== RCS file: /home/wine/wine/dlls/user/dde/client.c,v retrieving revision 1.16 diff -u -r1.16 client.c --- dlls/user/dde/client.c 5 Sep 2003 23:08:29 -0000 1.16 +++ dlls/user/dde/client.c 26 Oct 2003 05:54:06 -0000 @@ -182,7 +182,9 @@ LeaveCriticalSection(&WDML_CritSect); /* note: sent messages shall not use packing */ - SendMessageA(HWND_BROADCAST, WM_DDE_INITIATE, (WPARAM)hwndClient, MAKELPARAM(aSrv, aTpc)); + /* FIXME: Shall we use a more sensitive timeout value, e.g. + * HKEY_CURRENT_USER\Control Panel\WaitToKillAppTimeout ? */ + SendMessageTimeoutA(HWND_BROADCAST, WM_DDE_INITIATE, (WPARAM)hwndClient, MAKELPARAM(aSrv, aTpc), SMTO_NORMAL, 1000, NULL); EnterCriticalSection(&WDML_CritSect); Index: windows/painting.c =================================================================== RCS file: /home/wine/wine/windows/painting.c,v retrieving revision 1.86 diff -u -r1.86 painting.c --- windows/painting.c 5 Sep 2003 23:15:40 -0000 1.86 +++ windows/painting.c 26 Oct 2003 05:54:22 -0000 @@ -1467,7 +1467,7 @@ { /* send palette change notification */ HWND hWnd = WindowFromDC( hDC ); - if (hWnd) SendMessageA( HWND_BROADCAST, WM_PALETTECHANGED, (WPARAM)hWnd, 0L); + if (hWnd) PostMessageA( HWND_BROADCAST, WM_PALETTECHANGED, (WPARAM)hWnd, 0L); } return realized; } Index: windows/syscolor.c =================================================================== RCS file: /home/wine/wine/windows/syscolor.c,v retrieving revision 1.39 diff -u -r1.39 syscolor.c --- windows/syscolor.c 5 Sep 2003 23:15:39 -0000 1.39 +++ windows/syscolor.c 26 Oct 2003 05:54:24 -0000 @@ -251,8 +251,9 @@ } /* Send WM_SYSCOLORCHANGE message to all windows */ - - SendMessageA( HWND_BROADCAST, WM_SYSCOLORCHANGE, 0, 0 ); + /* FIXME: Shall we use a more sensitive timeout value, e.g. + * HKEY_CURRENT_USER\Control Panel\WaitToKillAppTimeout ? */ + SendMessageTimeoutA( HWND_BROADCAST, WM_SYSCOLORCHANGE, 0, 0, SMTO_NORMAL, 1000, NULL ); /* Repaint affected portions of all visible windows */ @@ -275,8 +276,9 @@ } /* Send WM_SYSCOLORCHANGE message to all windows */ - - SendMessageA( HWND_BROADCAST, WM_SYSCOLORCHANGE, 0, 0 ); + /* FIXME: Shall we use a more sensitive timeout value, e.g. + * HKEY_CURRENT_USER\Control Panel\WaitToKillAppTimeout ? */ + SendMessageTimeoutA( HWND_BROADCAST, WM_SYSCOLORCHANGE, 0, 0, SMTO_NORMAL, 1000, NULL ); /* Repaint affected portions of all visible windows */ Index: windows/sysparams.c =================================================================== RCS file: /home/wine/wine/windows/sysparams.c,v retrieving revision 1.55 diff -u -r1.55 sysparams.c --- windows/sysparams.c 6 Oct 2003 21:03:32 -0000 1.55 +++ windows/sysparams.c 26 Oct 2003 05:54:29 -0000 @@ -359,8 +359,10 @@ if (fWinIni & SPIF_UPDATEINIFILE) { if (fWinIni & (SPIF_SENDWININICHANGE | SPIF_SENDCHANGE)) - SendMessageA(HWND_BROADCAST, WM_SETTINGCHANGE, - uiAction, (LPARAM) ""); + /* FIXME: Shall we use a more sensitive timeout value, e.g. + * HKEY_CURRENT_USER\Control Panel\WaitToKillAppTimeout ? */ + SendMessageTimeoutA(HWND_BROADCAST, WM_SETTINGCHANGE, uiAction, + (LPARAM) "", SMTO_NORMAL, 1000, NULL); } else {
#include <windows.h> #include <stdio.h> HINSTANCE g_hInst; TCHAR g_szWindowClass[] = {"Test"}; LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); DWORD CALLBACK ThreadProc(void *pParam); #define EXIT_ON_ERROR(title, errcode) \ { \ LPTSTR lpMsgBuf = NULL; \ DWORD dwError = errcode; \ FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS\ , NULL \ , dwError \ , MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)\ , (LPTSTR) &lpMsgBuf \ , 0 \ , NULL \ ); \ if (lpMsgBuf != NULL) { \ MessageBox( NULL, lpMsgBuf, title, MB_ICONERROR );\ LocalFree( lpMsgBuf ); \ } \ return dwError; \ } int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { HRESULT hr = NOERROR; DWORD dwThreadId =0; HANDLE hThread = NULL; DWORD dwRet = 0; HWND hWnd = NULL; MSG msg; WNDCLASSEX wcex; g_hInst = hInstance; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; wcex.lpfnWndProc = (WNDPROC)WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = g_hInst; wcex.hIcon = NULL; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = GetSysColorBrush(COLOR_WINDOW); wcex.lpszMenuName = NULL; wcex.lpszClassName = g_szWindowClass; wcex.hIconSm = NULL; if (0 == RegisterClassEx(&wcex)) EXIT_ON_ERROR("RegisterClassEx", GetLastError()); #if 0 hr = CoInitialize(NULL); if (FAILED(hr)) EXIT_ON_ERROR("CoInitialize", hr); #else hWnd = CreateWindowEx(0, g_szWindowClass, "Window 1", WS_POPUP | WS_VISIBLE, 0x106, 0x90, 0x1F4, 0x1DF, NULL, NULL, g_hInst, NULL); if (NULL == hWnd) EXIT_ON_ERROR("CreateWindowEx", GetLastError()); #endif hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, &dwThreadId); if (NULL == hThread) EXIT_ON_ERROR("CreateThread", GetLastError()); dwRet = WaitForSingleObject(hThread, INFINITE); if ( dwRet != WAIT_OBJECT_0) { dwRet = (dwRet == WAIT_FAILED) ? GetLastError() : ERROR_TIMEOUT; EXIT_ON_ERROR("WaitForSingleObject", dwRet); } while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return 0; } DWORD CALLBACK ThreadProc(void *pParam) { MSG msg; HWND hWnd; hWnd = CreateWindowEx(0, g_szWindowClass, "Window 2", WS_POPUP | WS_VISIBLE, 0x106, 0x90, 0x1F4, 0x1DF, NULL, NULL, g_hInst, NULL); if (NULL == hWnd) EXIT_ON_ERROR("CreateWindowEx", GetLastError()); #if 1 SendMessageTimeout(HWND_BROADCAST, WM_PALETTEISCHANGING, (WPARAM)hWnd, 0, SMTO_NORMAL, 1000, NULL); printf("SendMessageTimeout: %d.\n", GetLastError()); #endif while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return 0; } LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; RECT rt; PAINTSTRUCT ps; char szTitle[256]; static const char szMessage[] = {"Press a key or mouse button to exit."}; switch (message) { case WM_PAINT: hdc = BeginPaint(hWnd, &ps); GetClientRect(hWnd, &rt); GetWindowText(hWnd, szTitle, 256); DrawText(hdc, szTitle, strlen(szTitle), &rt, DT_LEFT); DrawText(hdc, szMessage, strlen(szMessage), &rt, DT_CENTER | DT_VCENTER | DT_SINGLELINE); EndPaint(hWnd, &ps); break; case WM_QUERYNEWPALETTE: printf("WM_QUERYNEWPALETTE\n"); OutputDebugString("WM_QUERYNEWPALETTE\n"); return TRUE; case WM_PALETTEISCHANGING: printf("WM_PALETTEISCHANGING\n"); OutputDebugString("WM_PALETTEISCHANGING\n"); return 0; case WM_KEYDOWN: case WM_LBUTTONDOWN: case WM_MBUTTONDOWN: case WM_RBUTTONDOWN: case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; }