Fw: SetShellWindow() [resend]

Martin Fuchs martin-fuchs at gmx.net
Wed Nov 5 16:27:28 CST 2003


> Hi Alexandre,
> 
> this is a patch for a working SetShellWindow() implementation.
> It fullfills all my test cases. Also explorer runs fine with it.
> 
> It could be a bit more clean when moving the SetWindowPos() calls from 
> SetShellWindow() into the Wine server. But I don't know how to do this 
> correctly. I tried it by calling link_window() but I had to see, this is not 
> enough. If you move it into the server call, you can also remove the "if 
> (GetShellWindow())" in SetShellWindow().

Changelog:
* Move shell window into the background and leave it there forever
* Add tests for Get/SetShellWindow() to the list of dlls/user test
* Handle WS_EX_TOPMOST in conjunction with shell windows

-- 
Martin Fuchs
martin-fuchs at gmx.net
-------------- 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	16 Oct 2003 22:46:57 -0000
@@ -361,6 +361,21 @@
 {
     BOOL ret;
 
+    if (GetShellWindow())
+    	return FALSE;
+
+    if (GetWindowLongW(hwndShell, GWL_EXSTYLE) & WS_EX_TOPMOST)
+        return FALSE;
+
+    if (hwndListView != hwndShell)
+        if (GetWindowLongW(hwndListView, GWL_EXSTYLE) & WS_EX_TOPMOST)
+    	    return FALSE;
+
+    if (hwndListView && hwndListView!=hwndShell)
+        SetWindowPos(hwndListView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
+
+    SetWindowPos(hwndShell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
+
     SERVER_START_REQ(set_global_windows)
     {
         req->flags          = SET_GLOBAL_SHELL_WINDOWS;
@@ -370,13 +385,6 @@
     }
     SERVER_END_REQ;
 
-    if (ret)
-    {
-        if (hwndListView && hwndListView!=hwndShell)
-            SetWindowPos(hwndListView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
-
-        SetWindowPos(hwndShell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
-    }
     return ret;
 }
 
Index: dlls/user/tests/win.c
===================================================================
RCS file: /home/wine/wine/dlls/user/tests/win.c,v
retrieving revision 1.8
diff -u -r1.8 win.c
--- dlls/user/tests/win.c	10 Sep 2003 03:56:47 -0000	1.8
+++ dlls/user/tests/win.c	16 Oct 2003 22:46:57 -0000
@@ -388,6 +388,122 @@
 }
 
 
+static void test_shell_window()
+{
+    BOOL ret;
+    DWORD error;
+    HMODULE hinst, hUser32;
+    BOOL (WINAPI*SetShellWindow)(HWND);
+    BOOL (WINAPI*SetShellWindowEx)(HWND, HWND);
+    HWND hwnd1, hwnd2, hwnd3, hwnd4, hwnd5;
+    HWND shellWindow, nextWnd;
+
+    shellWindow = GetShellWindow();
+    hinst = GetModuleHandle(0);
+    hUser32 = GetModuleHandleA("user32");
+
+    SetShellWindow = (BOOL(WINAPI*)(HWND)) GetProcAddress(hUser32, "SetShellWindow");
+    SetShellWindowEx = (BOOL(WINAPI*)(HWND,HWND)) GetProcAddress(hUser32, "SetShellWindowEx");
+
+    trace("previous shell window: %p\n", shellWindow);
+
+    if (shellWindow) {
+        DWORD pid;
+        HANDLE hProcess;
+
+        ret = DestroyWindow(shellWindow);
+        error = GetLastError();
+
+        ok(!ret, "DestroyWindow(shellWindow)\n");
+        /* passes on Win XP, but not on Win98
+        ok(error==ERROR_ACCESS_DENIED, "ERROR_ACCESS_DENIED after DestroyWindow(shellWindow)\n"); */
+
+        /* close old shell instance */
+        GetWindowThreadProcessId(shellWindow, &pid);
+        hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
+        ret = TerminateProcess(hProcess, 0);
+        ok(ret, "termination of previous shell process failed: GetLastError()=%d", GetLastError());
+        WaitForSingleObject(hProcess, INFINITE);    /* wait for termination */
+        CloseHandle(hProcess);
+    }
+
+    hwnd1 = CreateWindowEx(0, TEXT("#32770"), TEXT("TEST1"), WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/, 100, 100, 300, 200, 0, 0, hinst, 0);
+    trace("created window 1: %p\n", hwnd1);
+
+    ret = SetShellWindow(hwnd1);
+    ok(ret, "first call to SetShellWindow(hwnd1)\n");
+    shellWindow = GetShellWindow();
+    ok(shellWindow==hwnd1, "wrong shell window: %p", shellWindow);
+
+    ret = SetShellWindow(hwnd1);
+    ok(!ret, "second call to SetShellWindow(hwnd1)\n");
+
+    ret = SetShellWindow(0);
+    error = GetLastError();
+    /* passes on Win XP, but not on Win98
+    ok(!ret, "reset shell window by SetShellWindow(0)\n");
+    ok(error==ERROR_INVALID_WINDOW_HANDLE, "ERROR_INVALID_WINDOW_HANDLE after SetShellWindow(0)\n"); */
+
+    ret = SetShellWindow(hwnd1);
+    /* passes on Win XP, but not on Win98
+    ok(!ret, "third call to SetShellWindow(hwnd1)\n"); */
+
+    SetWindowLong(hwnd1, GWL_EXSTYLE, GetWindowLong(hwnd1,GWL_EXSTYLE)|WS_EX_TOPMOST);
+    ret = GetWindowLong(hwnd1,GWL_EXSTYLE)&WS_EX_TOPMOST? TRUE: FALSE;
+    ok(!ret, "SetWindowExStyle(hwnd1, WS_EX_TOPMOST)\n");
+
+    ret = DestroyWindow(hwnd1);
+    ok(ret, "DestroyWindow(hwnd1)\n");
+
+    hwnd2 = CreateWindowEx(WS_EX_TOPMOST, TEXT("#32770"), TEXT("TEST2"), WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/, 150, 250, 300, 200, 0, 0, hinst, 0);
+    trace("created window 2: %p\n", hwnd2);
+    ret = SetShellWindow(hwnd2);
+    ok(!ret, "SetShellWindow(hwnd2) with WS_EX_TOPMOST");
+
+    hwnd3 = CreateWindowEx(0, TEXT("#32770"), TEXT("TEST3"), WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/, 200, 400, 300, 200, 0, 0, hinst, 0);
+    trace("created window 3: %p\n", hwnd3);
+
+    hwnd4 = CreateWindowEx(0, TEXT("#32770"), TEXT("TEST4"), WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/, 250, 500, 300, 200, 0, 0, hinst, 0);
+    trace("created window 4: %p\n", hwnd4);
+
+    nextWnd = GetWindow(hwnd4, GW_HWNDNEXT);
+    ok(nextWnd==hwnd3, "wrong next window for hwnd4: %p - expected hwnd3\n", nextWnd);
+
+    ret = SetShellWindow(hwnd4);
+    ok(ret, "SetShellWindow(hwnd4)\n");
+    shellWindow = GetShellWindow();
+    ok(shellWindow==hwnd4, "wrong shell window: %p - expected hwnd4", shellWindow);
+
+    nextWnd = GetWindow(hwnd4, GW_HWNDNEXT);
+    ok(nextWnd==0, "wrong next window for hwnd4: %p - expected 0\n", nextWnd);
+
+    ret = SetWindowPos(hwnd4, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
+    ok(ret, "SetWindowPos(hwnd4, HWND_TOPMOST)\n");
+
+    ret = SetWindowPos(hwnd4, hwnd3, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
+    ok(ret, "SetWindowPos(hwnd4, hwnd3");
+
+    ret = SetShellWindow(hwnd3);
+    ok(!ret, "SetShellWindow(hwnd3)\n");
+    shellWindow = GetShellWindow();
+    ok(shellWindow==hwnd4, "wrong shell window: %p %p - expected hwnd4", shellWindow);
+
+    hwnd5 = CreateWindowEx(0, TEXT("#32770"), TEXT("TEST5"), WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/, 300, 600, 300, 200, 0, 0, hinst, 0);
+    trace("created window 5: %p\n", hwnd5);
+    ret = SetWindowPos(hwnd4, hwnd5, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
+    ok(ret, "SetWindowPos(hwnd4, hwnd5)\n");
+
+    nextWnd = GetWindow(hwnd4, GW_HWNDNEXT);
+    ok(nextWnd==0, "wrong next window for hwnd4 after SetWindowPos(): %p - expected 0\n", nextWnd);
+
+    /* destroy test windows */
+    DestroyWindow(hwnd2);
+    DestroyWindow(hwnd3);
+    DestroyWindow(hwnd4);
+    DestroyWindow(hwnd5);
+}
+
+
 START_TEST(win)
 {
     pGetAncestor = (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "GetAncestor" );
@@ -408,4 +524,6 @@
     assert( hwndMain2 );
 
     test_parent_owner();
+
+    test_shell_window();
 }
Index: server/window.c
===================================================================
RCS file: /home/wine/wine/server/window.c,v
retrieving revision 1.24
diff -u -r1.24 window.c
--- server/window.c	7 Oct 2003 03:40:23 -0000	1.24
+++ server/window.c	16 Oct 2003 22:47:00 -0000
@@ -114,6 +114,13 @@
 /* link a window into the tree (or unlink it if the new parent is NULL)  */
 static void link_window( struct window *win, struct window *parent, struct window *previous )
 {
+    /* don't change Z-order of shell window */
+    if (win == shell_window)
+    {
+	set_error( STATUS_INVALID_PARAMETER );
+	return;
+    }
+
     unlink_window( win );  /* unlink it from the previous location */
 
     if (parent)
@@ -865,6 +872,13 @@
 
     if (req->flags & SET_GLOBAL_SHELL_WINDOWS)
     {
+    	/* only allow to set the shell window if there is not already one */
+    	if (req->shell_window && shell_window)
+	    set_error(STATUS_ACCESS_DENIED);
+
+    	if (req->shell_listview && shell_listview)
+	    set_error(STATUS_ACCESS_DENIED);
+
         if (!get_new_global_window( &new_shell_window, req->shell_window )) return;
         if (!get_new_global_window( &new_shell_listview, req->shell_listview )) return;
     }
@@ -876,8 +890,9 @@
     {
         if (!get_new_global_window( &new_taskman_window, req->taskman_window )) return;
     }
-    shell_window   = new_shell_window;
+
     shell_listview = new_shell_listview;
+    shell_window   = new_shell_window;
     progman_window = new_progman_window;
     taskman_window = new_taskman_window;
 }
Index: windows/win.c
===================================================================
RCS file: /home/wine/wine/windows/win.c,v
retrieving revision 1.224
diff -u -r1.224 win.c
--- windows/win.c	5 Sep 2003 23:15:39 -0000	1.224
+++ windows/win.c	16 Oct 2003 22:47:03 -0000
@@ -2028,6 +2028,9 @@
             SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
             if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
             newval = style.styleNew;
+	    /* don`t set extended style bit WS_EX_TOPMOST for the shell window */
+	    if (hwnd == GetShellWindow())
+	        newval = newval & ~WS_EX_TOPMOST;
             break;
         case GWL_HWNDPARENT:
             if (wndPtr->parent == GetDesktopWindow())


More information about the wine-patches mailing list