SetShellWindow() and friends

Martin Fuchs martin-fuchs at gmx.net
Sun Oct 12 14:49:34 CDT 2003


Hello Alexandre,

> Yes, if it works under Windows then obviously we need a fix in Wine.
> I think you should investigate exactly how Windows does it, there are
> many places where we could add such checks so we need to find out
> exactly where Windows has them.

OK - wrote a little test program to see, how SetShellWindow() exactly works on Windows. It creates a few windows and tests, what happens when trying to register them as shell window. To run it you have to terminate Windows Explorer at first. Then the output is this the following:

first call to SetShellWindow(hwnd): SUCCESS
second call to SetShellWindow(hwnd): FAILURE
reset shell window by SetShellWindow(0): FAILURE
third call to SetShellWindow(hwnd): FAILURE
SetWindowExStyle(hwnd, WS_EX_TOPMOST): FAILURE
DestroyWindow(hwnd): SUCCESS
SetShellWindow(hwnd2) with WS_EX_TOPMOST: FAILURE
SetShellWindow(hwnd3): SUCCESS
SetWindowPos(hwnd3, HWND_TOPMOST): SUCCESS
SetWindowPos(hwnd3, hwnd4: SUCCESS
SetShellWindow(hwnd4): FAILURE
SetWindowPos(hwnd3, hwnd5): SUCCESS


So we have to taking following rules into account for the SetShellWindow/Ex() implementation:

- SetShellWindow() only succeedes if there is not yet a registered shell window.

- A successfull call moves the window into the background. It becomes the window with the lowest Z-order. This can't be changed by a call to SetWindowPos() or similar functions. The shell window remains at the bottom for ever.

- Shell windows can't be reset by calling SetShellWindow(0). To change the shell window, the current window has to be destroyed.

- Shell windows must not have the extended style bit WS_EX_TOPMOST set. It it is set, SetShellWindow() failes. If you try to set this bit after registering a window as shell window, the bit is ignored and automatically set to zero.

- If you try to move the window into the foreground by calling SetWindowPos() with HWND_TOPMOST this call succeedes, but it does not change anything. The window remains in the background.


--
Martin Fuchs
martin-fuchs at gmx.net
-------------- next part --------------
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#include <iostream>

using namespace std;


static BOOL (WINAPI*SetShellWindow)(HWND);
static BOOL (WINAPI*SetShellWindowEx)(HWND, HWND);


int main()
{
	HINSTANCE shell32 = GetModuleHandle(TEXT("user32"));	// or LoadLibrary()

	SetShellWindow = (BOOL(WINAPI*)(HWND)) GetProcAddress(shell32, "SetShellWindow");
	SetShellWindowEx = (BOOL(WINAPI*)(HWND,HWND)) GetProcAddress(shell32, "SetShellWindowEx");

	HMODULE hinst = GetModuleHandle(0);


	HWND hwnd = CreateWindowEx(0, TEXT("#32770"), TEXT("TEST1"), WS_OVERLAPPEDWINDOW|WS_VISIBLE, 100, 100, 300, 200, 0, 0, hinst, 0);


	BOOL ret = SetShellWindow(hwnd);

	cout << "first call to SetShellWindow(hwnd): " << (ret? "SUCCESS": "FAILURE") << "\n";


	ret = SetShellWindow(hwnd);

	cout << "second call to SetShellWindow(hwnd): " << (ret? "SUCCESS": "FAILURE") << "\n";


	ret = SetShellWindow(0);

	cout << "reset shell window by SetShellWindow(0): " << (ret? "SUCCESS": "FAILURE") << "\n";


	ret = SetShellWindow(hwnd);

	cout << "third call to SetShellWindow(hwnd): " << (ret? "SUCCESS": "FAILURE") << "\n";


	SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd,GWL_EXSTYLE)|WS_EX_TOPMOST);

	ret = GetWindowLong(hwnd,GWL_EXSTYLE)&WS_EX_TOPMOST? TRUE: FALSE;

	cout << "SetWindowExStyle(hwnd, WS_EX_TOPMOST): " << (ret? "SUCCESS": "FAILURE") << "\n";


	ret = DestroyWindow(hwnd);

	cout << "DestroyWindow(hwnd): " << (ret? "SUCCESS": "FAILURE") << "\n";


	HWND hwnd2 = CreateWindowEx(WS_EX_TOPMOST, TEXT("#32770"), TEXT("TEST2"), WS_OVERLAPPEDWINDOW|WS_VISIBLE, 150, 250, 300, 200, 0, 0, hinst, 0);

	ret = SetShellWindow(hwnd2);

	cout << "SetShellWindow(hwnd2) with WS_EX_TOPMOST: " << (ret? "SUCCESS": "FAILURE") << "\n";


	HWND hwnd3 = CreateWindowEx(0, TEXT("#32770"), TEXT("TEST3"), WS_OVERLAPPEDWINDOW|WS_VISIBLE, 200, 400, 300, 200, 0, 0, hinst, 0);

	ret = SetShellWindow(hwnd3);

	cout << "SetShellWindow(hwnd3): " << (ret? "SUCCESS": "FAILURE") << "\n";


	ret = SetWindowPos(hwnd3, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);

	cout << "SetWindowPos(hwnd3, HWND_TOPMOST): " << (ret? "SUCCESS": "FAILURE") << "\n";


	HWND hwnd4 = CreateWindowEx(0, TEXT("#32770"), TEXT("TEST4"), WS_OVERLAPPEDWINDOW|WS_VISIBLE, 250, 500, 300, 200, 0, 0, hinst, 0);


	cout << "SetWindowPos(hwnd3, hwnd4: " << (ret? "SUCCESS": "FAILURE") << "\n";


	ret = SetShellWindow(hwnd4);

	cout << "SetShellWindow(hwnd4): " << (ret? "SUCCESS": "FAILURE") << "\n";


	HWND hwnd5 = CreateWindowEx(0, TEXT("#32770"), TEXT("TEST5"), WS_OVERLAPPEDWINDOW|WS_VISIBLE, 300, 600, 300, 200, 0, 0, hinst, 0);

	ret = SetWindowPos(hwnd3, hwnd5, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
	UpdateWindow(hwnd3);
	UpdateWindow(hwnd4);
	GdiFlush();

	cout << "SetWindowPos(hwnd3, hwnd5): " << (ret? "SUCCESS": "FAILURE") << "\n";


	MSG msg;

	while(GetMessage(&msg, 0, 0, 0)) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}


	return 0;
}


More information about the wine-devel mailing list