Builtin SetActiveWindow may freezes some applications

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The problem is that set_active_window calls SendMessage to send message to all windows in some cases.

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;
}




[Index of Archives]     [Gimp for Windows]     [Red Hat]     [Samba]     [Yosemite Camping]     [Graphics Cards]     [Wine Home]

  Powered by Linux