Builtin SetActiveWindow may freezes some applications

Jerry Jenkins Jerry_J_Jenkins at hotmail.com
Sun Oct 26 01:31:27 CDT 2003


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















-------------- next part --------------
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
         {



-------------- next part --------------
 #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;
}





More information about the wine-patches mailing list