From: Jacek Caban jacek@codeweavers.com
Based on winex11.drv. Drivers that don't implement ClipboardWindowProc entry point will disable it by failing to create the window.
Signed-off-by: Jacek Caban jacek@codeweavers.com --- programs/explorer/Makefile.in | 2 +- programs/explorer/desktop.c | 90 +++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 1 deletion(-)
diff --git a/programs/explorer/Makefile.in b/programs/explorer/Makefile.in index 5507d747bb1..3a2ddec3fd4 100644 --- a/programs/explorer/Makefile.in +++ b/programs/explorer/Makefile.in @@ -1,5 +1,5 @@ MODULE = explorer.exe -IMPORTS = rpcrt4 user32 gdi32 advapi32 +IMPORTS = rpcrt4 user32 gdi32 advapi32 win32u DELAYIMPORTS = comctl32 shell32 oleaut32 ole32 shlwapi
EXTRADLLFLAGS = -mwindows -municode diff --git a/programs/explorer/desktop.c b/programs/explorer/desktop.c index 400cc1d560e..96673adc254 100644 --- a/programs/explorer/desktop.c +++ b/programs/explorer/desktop.c @@ -29,6 +29,7 @@ #include <rpc.h> #include <shlobj.h> #include <shellapi.h> +#include <ntuser.h> #include "exdisp.h"
#include "wine/debug.h" @@ -618,6 +619,91 @@ static void initialize_launchers( HWND hwnd ) } }
+/************************************************************************** + * wait_clipboard_mutex + * + * Make sure that there's only one clipboard thread per window station. + */ +static BOOL wait_clipboard_mutex(void) +{ + static const WCHAR prefix[] = L"__wine_clipboard_"; + WCHAR buffer[MAX_PATH + ARRAY_SIZE( prefix )]; + HANDLE mutex; + + memcpy( buffer, prefix, sizeof(prefix) ); + if (!GetUserObjectInformationW( GetProcessWindowStation(), UOI_NAME, + buffer + ARRAY_SIZE( prefix ) - 1, + sizeof(buffer) - sizeof(prefix), NULL )) + { + ERR( "failed to get winstation name\n" ); + return FALSE; + } + mutex = CreateMutexW( NULL, TRUE, buffer ); + if (GetLastError() == ERROR_ALREADY_EXISTS) + { + TRACE( "waiting for mutex %s\n", debugstr_w( buffer )); + WaitForSingleObject( mutex, INFINITE ); + } + return TRUE; +} + + +/************************************************************************** + * clipboard_wndproc + * + * Window procedure for the clipboard manager. + */ +static LRESULT CALLBACK clipboard_wndproc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) +{ + switch (msg) + { + case WM_NCCREATE: + case WM_CLIPBOARDUPDATE: + case WM_RENDERFORMAT: + case WM_TIMER: + case WM_DESTROYCLIPBOARD: + case WM_USER: + return NtUserMessageCall( hwnd, msg, wp, lp, 0, NtUserClipboardWindowProc, FALSE ); + } + + return DefWindowProcW( hwnd, msg, wp, lp ); +} + + +/************************************************************************** + * clipboard_thread + * + * Thread running inside the desktop process to manage the clipboard + */ +static DWORD WINAPI clipboard_thread( void *arg ) +{ + static const WCHAR clipboard_classname[] = L"__wine_clipboard_manager"; + WNDCLASSW class; + ATOM atom; + MSG msg; + + if (!wait_clipboard_mutex()) return 0; + + memset( &class, 0, sizeof(class) ); + class.lpfnWndProc = clipboard_wndproc; + class.lpszClassName = clipboard_classname; + + if (!(atom = RegisterClassW( &class )) && GetLastError() != ERROR_CLASS_ALREADY_EXISTS) + { + ERR( "could not register clipboard window class err %lu\n", GetLastError() ); + return 0; + } + if (!CreateWindowW( clipboard_classname, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, 0, NULL )) + { + TRACE( "failed to create clipboard window err %lu\n", GetLastError() ); + UnregisterClassW( MAKEINTRESOURCEW(atom), NULL ); + return 0; + } + + while (GetMessageW( &msg, 0, 0, 0 )) DispatchMessageW( &msg ); + return 0; +} + static WNDPROC desktop_orig_wndproc;
/* window procedure for the desktop window */ @@ -961,6 +1047,8 @@ void manage_desktop( WCHAR *arg ) BOOL enable_shell = FALSE; void (WINAPI *pShellDDEInit)( BOOL ) = NULL; HMODULE shell32; + HANDLE thread; + DWORD id;
/* get the rest of the command line (if any) */ while (*p && !is_whitespace(*p)) p++; @@ -1025,6 +1113,8 @@ void manage_desktop( WCHAR *arg ) SetWindowPos( hwnd, 0, GetSystemMetrics(SM_XVIRTUALSCREEN), GetSystemMetrics(SM_YVIRTUALSCREEN), GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN), SWP_SHOWWINDOW ); + thread = CreateThread( NULL, 0, clipboard_thread, NULL, 0, &id ); + if (thread) CloseHandle( thread ); SystemParametersInfoW( SPI_SETDESKWALLPAPER, 0, NULL, FALSE ); ClipCursor( NULL ); initialize_display_settings();