/* * Explorer desktop support * * Copyright 2006 Alexandre Julliard * Copyright 2013 Hans Leidekker for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" #include "wine/port.h" #include #define COBJMACROS #define OEMRESOURCE #include #include #include #include #include "exdisp.h" #include "wine/unicode.h" #include "wine/debug.h" #include "explorer_private.h" WINE_DEFAULT_DEBUG_CHANNEL(explorer); #define DESKTOP_CLASS_ATOM ((LPCWSTR)MAKEINTATOM(32769)) #define DESKTOP_ALL_ACCESS 0x01ff #ifdef __APPLE__ static const WCHAR default_driver[] = {'m','a','c',',','x','1','1',0}; #else static const WCHAR default_driver[] = {'x','1','1',0}; #endif static BOOL using_root; struct launcher { WCHAR *path; HICON icon; WCHAR *title; }; static WCHAR *desktop_folder; static WCHAR *desktop_folder_public; static int icon_cx, icon_cy, icon_offset_cx, icon_offset_cy; static int title_cx, title_cy, title_offset_cx, title_offset_cy; static int desktop_width, launcher_size, launchers_per_row; static struct launcher **launchers; static unsigned int nb_launchers, nb_allocated; static REFIID tid_ids[] = { &IID_IShellWindows, &IID_IWebBrowser2 }; typedef enum { IShellWindows_tid, IWebBrowser2_tid, LAST_tid } tid_t; static ITypeLib *typelib; static ITypeInfo *typeinfos[LAST_tid]; static HRESULT load_typelib(void) { HRESULT hres; ITypeLib *tl; hres = LoadRegTypeLib(&LIBID_SHDocVw, 1, 0, LOCALE_SYSTEM_DEFAULT, &tl); if (FAILED(hres)) { ERR("LoadRegTypeLib failed: %08x\n", hres); return hres; } if (InterlockedCompareExchangePointer((void**)&typelib, tl, NULL)) ITypeLib_Release(tl); return hres; } static HRESULT get_typeinfo(tid_t tid, ITypeInfo **typeinfo) { HRESULT hres; if (!typelib) hres = load_typelib(); if (!typelib) return hres; if (!typeinfos[tid]) { ITypeInfo *ti; hres = ITypeLib_GetTypeInfoOfGuid(typelib, tid_ids[tid], &ti); if (FAILED(hres)) { ERR("GetTypeInfoOfGuid(%s) failed: %08x\n", debugstr_guid(tid_ids[tid]), hres); return hres; } if (InterlockedCompareExchangePointer((void**)(typeinfos+tid), ti, NULL)) ITypeInfo_Release(ti); } *typeinfo = typeinfos[tid]; ITypeInfo_AddRef(*typeinfo); return S_OK; } struct shellwindows { IShellWindows IShellWindows_iface; }; /* This is not limited to desktop itself, every file browser window that explorer creates supports that. Desktop instance is special in some aspects, for example navigation is not possible, you can't show/hide it, or bring up a menu. CLSID_ShellBrowserWindow class could be used to create instances like that, and they should be registered with IShellWindows as well. */ struct shellbrowserwindow { IWebBrowser2 IWebBrowser2_iface; IServiceProvider IServiceProvider_iface; IShellBrowser IShellBrowser_iface; IShellView *view; }; static struct shellwindows shellwindows; static struct shellbrowserwindow desktopshellbrowserwindow; static inline struct shellwindows *impl_from_IShellWindows(IShellWindows *iface) { return CONTAINING_RECORD(iface, struct shellwindows, IShellWindows_iface); } static inline struct shellbrowserwindow *impl_from_IWebBrowser2(IWebBrowser2 *iface) { return CONTAINING_RECORD(iface, struct shellbrowserwindow, IWebBrowser2_iface); } static inline struct shellbrowserwindow *impl_from_IServiceProvider(IServiceProvider *iface) { return CONTAINING_RECORD(iface, struct shellbrowserwindow, IServiceProvider_iface); } static inline struct shellbrowserwindow *impl_from_IShellBrowser(IShellBrowser *iface) { return CONTAINING_RECORD(iface, struct shellbrowserwindow, IShellBrowser_iface); } static void shellwindows_init(void); static void desktopshellbrowserwindow_init(void); static RECT get_icon_rect( unsigned int index ) { RECT rect; unsigned int row = index / launchers_per_row; unsigned int col = index % launchers_per_row; rect.left = col * launcher_size + icon_offset_cx; rect.right = rect.left + icon_cx; rect.top = row * launcher_size + icon_offset_cy; rect.bottom = rect.top + icon_cy; return rect; } static RECT get_title_rect( unsigned int index ) { RECT rect; unsigned int row = index / launchers_per_row; unsigned int col = index % launchers_per_row; rect.left = col * launcher_size + title_offset_cx; rect.right = rect.left + title_cx; rect.top = row * launcher_size + title_offset_cy; rect.bottom = rect.top + title_cy; return rect; } static const struct launcher *launcher_from_point( int x, int y ) { RECT icon, title; unsigned int index; if (!nb_launchers) return NULL; index = x / launcher_size + (y / launcher_size) * launchers_per_row; if (index >= nb_launchers) return NULL; icon = get_icon_rect( index ); title = get_title_rect( index ); if ((x < icon.left || x > icon.right || y < icon.top || y > icon.bottom) && (x < title.left || x > title.right || y < title.top || y > title.bottom)) return NULL; return launchers[index]; } static void draw_launchers( HDC hdc, RECT update_rect ) { COLORREF color = SetTextColor( hdc, RGB(255,255,255) ); /* FIXME: depends on background color */ int mode = SetBkMode( hdc, TRANSPARENT ); unsigned int i; LOGFONTW lf; HFONT font; SystemParametersInfoW( SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, 0 ); font = SelectObject( hdc, CreateFontIndirectW( &lf ) ); for (i = 0; i < nb_launchers; i++) { RECT dummy, icon = get_icon_rect( i ), title = get_title_rect( i ); if (IntersectRect( &dummy, &icon, &update_rect )) DrawIconEx( hdc, icon.left, icon.top, launchers[i]->icon, icon_cx, icon_cy, 0, 0, DI_DEFAULTSIZE|DI_NORMAL ); if (IntersectRect( &dummy, &title, &update_rect )) DrawTextW( hdc, launchers[i]->title, -1, &title, DT_CENTER|DT_WORDBREAK|DT_EDITCONTROL|DT_END_ELLIPSIS ); } SelectObject( hdc, font ); SetTextColor( hdc, color ); SetBkMode( hdc, mode ); } static void do_launch( const struct launcher *launcher ) { static const WCHAR openW[] = {'o','p','e','n',0}; ShellExecuteW( NULL, openW, launcher->path, NULL, NULL, 0 ); } static WCHAR *append_path( const WCHAR *path, const WCHAR *filename, int len_filename ) { int len_path = strlenW( path ); WCHAR *ret; if (len_filename == -1) len_filename = strlenW( filename ); if (!(ret = HeapAlloc( GetProcessHeap(), 0, (len_path + len_filename + 2) * sizeof(WCHAR) ))) return NULL; memcpy( ret, path, len_path * sizeof(WCHAR) ); ret[len_path] = '\\'; memcpy( ret + len_path + 1, filename, len_filename * sizeof(WCHAR) ); ret[len_path + 1 + len_filename] = 0; return ret; } static IShellLinkW *load_shelllink( const WCHAR *path ) { HRESULT hr; IShellLinkW *link; IPersistFile *file; hr = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (void **)&link ); if (FAILED( hr )) return NULL; hr = IShellLinkW_QueryInterface( link, &IID_IPersistFile, (void **)&file ); if (FAILED( hr )) { IShellLinkW_Release( link ); return NULL; } hr = IPersistFile_Load( file, path, 0 ); IPersistFile_Release( file ); if (FAILED( hr )) { IShellLinkW_Release( link ); return NULL; } return link; } static HICON extract_icon( IShellLinkW *link ) { WCHAR tmp_path[MAX_PATH], icon_path[MAX_PATH], target_path[MAX_PATH]; HICON icon = NULL; int index; tmp_path[0] = 0; IShellLinkW_GetIconLocation( link, tmp_path, MAX_PATH, &index ); ExpandEnvironmentStringsW( tmp_path, icon_path, MAX_PATH ); if (icon_path[0]) ExtractIconExW( icon_path, index, &icon, NULL, 1 ); if (!icon) { tmp_path[0] = 0; IShellLinkW_GetPath( link, tmp_path, MAX_PATH, NULL, SLGP_RAWPATH ); ExpandEnvironmentStringsW( tmp_path, target_path, MAX_PATH ); ExtractIconExW( target_path, index, &icon, NULL, 1 ); } return icon; } static WCHAR *build_title( const WCHAR *filename, int len ) { const WCHAR *p; WCHAR *ret; if (len == -1) len = strlenW( filename ); for (p = filename + len - 1; p >= filename; p--) { if (*p == '.') { len = p - filename; break; } } if (!(ret = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return NULL; memcpy( ret, filename, len * sizeof(WCHAR) ); ret[len] = 0; return ret; } static BOOL add_launcher( const WCHAR *folder, const WCHAR *filename, int len_filename ) { struct launcher *launcher; IShellLinkW *link; if (nb_launchers == nb_allocated) { unsigned int count = nb_allocated * 2; struct launcher **tmp = HeapReAlloc( GetProcessHeap(), 0, launchers, count * sizeof(*tmp) ); if (!tmp) return FALSE; launchers = tmp; nb_allocated = count; } if (!(launcher = HeapAlloc( GetProcessHeap(), 0, sizeof(*launcher) ))) return FALSE; if (!(launcher->path = append_path( folder, filename, len_filename ))) goto error; if (!(link = load_shelllink( launcher->path ))) goto error; launcher->icon = extract_icon( link ); launcher->title = build_title( filename, len_filename ); IShellLinkW_Release( link ); if (launcher->icon && launcher->title) { launchers[nb_launchers++] = launcher; return TRUE; } HeapFree( GetProcessHeap(), 0, launcher->title ); DestroyIcon( launcher->icon ); error: HeapFree( GetProcessHeap(), 0, launcher->path ); HeapFree( GetProcessHeap(), 0, launcher ); return FALSE; } static void free_launcher( struct launcher *launcher ) { DestroyIcon( launcher->icon ); HeapFree( GetProcessHeap(), 0, launcher->path ); HeapFree( GetProcessHeap(), 0, launcher->title ); HeapFree( GetProcessHeap(), 0, launcher ); } static BOOL remove_launcher( const WCHAR *folder, const WCHAR *filename, int len_filename ) { UINT i; WCHAR *path; BOOL ret = FALSE; if (!(path = append_path( folder, filename, len_filename ))) return FALSE; for (i = 0; i < nb_launchers; i++) { if (!strcmpiW( launchers[i]->path, path )) { free_launcher( launchers[i] ); if (--nb_launchers) memmove( &launchers[i], &launchers[i + 1], sizeof(launchers[i]) * (nb_launchers - i) ); ret = TRUE; break; } } HeapFree( GetProcessHeap(), 0, path ); return ret; } static BOOL get_icon_text_metrics( HWND hwnd, TEXTMETRICW *tm ) { BOOL ret; HDC hdc; LOGFONTW lf; HFONT hfont; hdc = GetDC( hwnd ); SystemParametersInfoW( SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, 0 ); hfont = SelectObject( hdc, CreateFontIndirectW( &lf ) ); ret = GetTextMetricsW( hdc, tm ); SelectObject( hdc, hfont ); ReleaseDC( hwnd, hdc ); return ret; } static BOOL process_changes( const WCHAR *folder, char *buf ) { FILE_NOTIFY_INFORMATION *info = (FILE_NOTIFY_INFORMATION *)buf; BOOL ret = FALSE; for (;;) { switch (info->Action) { case FILE_ACTION_ADDED: case FILE_ACTION_RENAMED_NEW_NAME: if (add_launcher( folder, info->FileName, info->FileNameLength / sizeof(WCHAR) )) ret = TRUE; break; case FILE_ACTION_REMOVED: case FILE_ACTION_RENAMED_OLD_NAME: if (remove_launcher( folder, info->FileName, info->FileNameLength / sizeof(WCHAR) )) ret = TRUE; break; default: WARN( "unexpected action %u\n", info->Action ); break; } if (!info->NextEntryOffset) break; info = (FILE_NOTIFY_INFORMATION *)((char *)info + info->NextEntryOffset); } return ret; } static DWORD CALLBACK watch_desktop_folders( LPVOID param ) { HWND hwnd = param; HRESULT init = CoInitialize( NULL ); HANDLE dir0, dir1, events[2]; OVERLAPPED ovl0, ovl1; char *buf0 = NULL, *buf1 = NULL; DWORD count, size = 4096, error = ERROR_OUTOFMEMORY; BOOL ret, redraw; dir0 = CreateFileW( desktop_folder, FILE_LIST_DIRECTORY|SYNCHRONIZE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED, NULL ); if (dir0 == INVALID_HANDLE_VALUE) return GetLastError(); dir1 = CreateFileW( desktop_folder_public, FILE_LIST_DIRECTORY|SYNCHRONIZE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED, NULL ); if (dir1 == INVALID_HANDLE_VALUE) { CloseHandle( dir0 ); return GetLastError(); } if (!(ovl0.hEvent = events[0] = CreateEventW( NULL, FALSE, FALSE, NULL ))) goto error; if (!(ovl1.hEvent = events[1] = CreateEventW( NULL, FALSE, FALSE, NULL ))) goto error; if (!(buf0 = HeapAlloc( GetProcessHeap(), 0, size ))) goto error; if (!(buf1 = HeapAlloc( GetProcessHeap(), 0, size ))) goto error; for (;;) { ret = ReadDirectoryChangesW( dir0, buf0, size, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME, NULL, &ovl0, NULL ); if (!ret) { error = GetLastError(); goto error; } ret = ReadDirectoryChangesW( dir1, buf1, size, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME, NULL, &ovl1, NULL ); if (!ret) { error = GetLastError(); goto error; } redraw = FALSE; switch ((error = WaitForMultipleObjects( 2, events, FALSE, INFINITE ))) { case WAIT_OBJECT_0: if (!GetOverlappedResult( dir0, &ovl0, &count, FALSE ) || !count) break; if (process_changes( desktop_folder, buf0 )) redraw = TRUE; break; case WAIT_OBJECT_0 + 1: if (!GetOverlappedResult( dir1, &ovl1, &count, FALSE ) || !count) break; if (process_changes( desktop_folder_public, buf1 )) redraw = TRUE; break; default: goto error; } if (redraw) InvalidateRect( hwnd, NULL, TRUE ); } error: CloseHandle( dir0 ); CloseHandle( dir1 ); CloseHandle( events[0] ); CloseHandle( events[1] ); HeapFree( GetProcessHeap(), 0, buf0 ); HeapFree( GetProcessHeap(), 0, buf1 ); if (SUCCEEDED( init )) CoUninitialize(); return error; } static void add_folder( const WCHAR *folder ) { static const WCHAR lnkW[] = {'\\','*','.','l','n','k',0}; int len = strlenW( folder ) + strlenW( lnkW ); WIN32_FIND_DATAW data; HANDLE handle; WCHAR *glob; if (!(glob = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return; strcpyW( glob, folder ); strcatW( glob, lnkW ); if ((handle = FindFirstFileW( glob, &data )) != INVALID_HANDLE_VALUE) { do { add_launcher( folder, data.cFileName, -1 ); } while (FindNextFileW( handle, &data )); FindClose( handle ); } HeapFree( GetProcessHeap(), 0, glob ); } #define BORDER_SIZE 4 #define PADDING_SIZE 4 #define TITLE_CHARS 14 static void initialize_launchers( HWND hwnd ) { HRESULT hr, init; TEXTMETRICW tm; int icon_size; if (!(get_icon_text_metrics( hwnd, &tm ))) return; icon_cx = GetSystemMetrics( SM_CXICON ); icon_cy = GetSystemMetrics( SM_CYICON ); icon_size = max( icon_cx, icon_cy ); title_cy = tm.tmHeight * 2; title_cx = max( tm.tmAveCharWidth * TITLE_CHARS, icon_size + PADDING_SIZE + title_cy ); launcher_size = BORDER_SIZE + title_cx + BORDER_SIZE; icon_offset_cx = (launcher_size - icon_cx) / 2; icon_offset_cy = BORDER_SIZE + (icon_size - icon_cy) / 2; title_offset_cx = BORDER_SIZE; title_offset_cy = BORDER_SIZE + icon_size + PADDING_SIZE; desktop_width = GetSystemMetrics( SM_CXSCREEN ); launchers_per_row = desktop_width / launcher_size; hr = SHGetKnownFolderPath( &FOLDERID_Desktop, KF_FLAG_CREATE, NULL, &desktop_folder ); if (FAILED( hr )) { WINE_ERR("Could not get user desktop folder\n"); return; } hr = SHGetKnownFolderPath( &FOLDERID_PublicDesktop, KF_FLAG_CREATE, NULL, &desktop_folder_public ); if (FAILED( hr )) { WINE_ERR("Could not get public desktop folder\n"); CoTaskMemFree( desktop_folder ); return; } if ((launchers = HeapAlloc( GetProcessHeap(), 0, 2 * sizeof(launchers[0]) ))) { nb_allocated = 2; init = CoInitialize( NULL ); add_folder( desktop_folder ); add_folder( desktop_folder_public ); if (SUCCEEDED( init )) CoUninitialize(); CreateThread( NULL, 0, watch_desktop_folders, hwnd, 0, NULL ); } } /* screen saver handler */ static BOOL start_screensaver( void ) { if (using_root) { const char *argv[3] = { "xdg-screensaver", "activate", NULL }; int pid = _spawnvp( _P_DETACH, argv[0], argv ); if (pid > 0) { WINE_TRACE( "started process %d\n", pid ); return TRUE; } } return FALSE; } /* window procedure for the desktop window */ static LRESULT WINAPI desktop_wnd_proc( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ) { WINE_TRACE( "got msg %04x wp %lx lp %lx\n", message, wp, lp ); switch(message) { case WM_SYSCOMMAND: switch(wp & 0xfff0) { case SC_CLOSE: ExitWindows( 0, 0 ); break; case SC_SCREENSAVE: return start_screensaver(); } return 0; case WM_CLOSE: PostQuitMessage(0); return 0; case WM_SETCURSOR: return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) ); case WM_NCHITTEST: return HTCLIENT; case WM_ERASEBKGND: if (!using_root) PaintDesktop( (HDC)wp ); return TRUE; case WM_SETTINGCHANGE: if (wp == SPI_SETDESKWALLPAPER) SystemParametersInfoW( SPI_SETDESKWALLPAPER, 0, NULL, FALSE ); return 0; case WM_PARENTNOTIFY: if (LOWORD(wp) == WM_DESTROY) cleanup_systray_window( (HWND)lp ); return 0; case WM_LBUTTONDBLCLK: if (!using_root) { const struct launcher *launcher = launcher_from_point( (short)LOWORD(lp), (short)HIWORD(lp) ); if (launcher) do_launch( launcher ); } return 0; case WM_PAINT: { PAINTSTRUCT ps; BeginPaint( hwnd, &ps ); if (!using_root) { if (ps.fErase) PaintDesktop( ps.hdc ); draw_launchers( ps.hdc, ps.rcPaint ); } EndPaint( hwnd, &ps ); } return 0; default: return DefWindowProcW( hwnd, message, wp, lp ); } } /* create the desktop and the associated driver window, and make it the current desktop */ static BOOL create_desktop( HMODULE driver, const WCHAR *name, unsigned int width, unsigned int height ) { static const WCHAR rootW[] = {'r','o','o','t',0}; BOOL ret = FALSE; BOOL (CDECL *create_desktop_func)(unsigned int, unsigned int); /* magic: desktop "root" means use the root window */ if (driver && strcmpiW( name, rootW )) { create_desktop_func = (void *)GetProcAddress( driver, "wine_create_desktop" ); if (create_desktop_func) ret = create_desktop_func( width, height ); } return ret; } /* parse the desktop size specification */ static BOOL parse_size( const WCHAR *size, unsigned int *width, unsigned int *height ) { WCHAR *end; *width = strtoulW( size, &end, 10 ); if (end == size) return FALSE; if (*end != 'x') return FALSE; size = end + 1; *height = strtoulW( size, &end, 10 ); return !*end; } /* retrieve the desktop name to use if not specified on the command line */ static const WCHAR *get_default_desktop_name(void) { static const WCHAR desktopW[] = {'D','e','s','k','t','o','p',0}; static const WCHAR defaultW[] = {'D','e','f','a','u','l','t',0}; static const WCHAR explorer_keyW[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\', 'E','x','p','l','o','r','e','r',0}; static WCHAR buffer[MAX_PATH]; DWORD size = sizeof(buffer); HDESK desk = GetThreadDesktop( GetCurrentThreadId() ); WCHAR *ret = NULL; HKEY hkey; if (desk && GetUserObjectInformationW( desk, UOI_NAME, buffer, sizeof(buffer)/sizeof(WCHAR), NULL )) { if (strcmpiW( buffer, defaultW )) return buffer; } /* @@ Wine registry key: HKCU\Software\Wine\Explorer */ if (!RegOpenKeyW( HKEY_CURRENT_USER, explorer_keyW, &hkey )) { if (!RegQueryValueExW( hkey, desktopW, 0, NULL, (LPBYTE)buffer, &size )) ret = buffer; RegCloseKey( hkey ); } return ret; } /* retrieve the default desktop size from the registry */ static BOOL get_default_desktop_size( const WCHAR *name, unsigned int *width, unsigned int *height ) { static const WCHAR desktop_keyW[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\', 'E','x','p','l','o','r','e','r','\\', 'D','e','s','k','t','o','p','s',0}; HKEY hkey; WCHAR buffer[64]; DWORD size = sizeof(buffer); BOOL found = FALSE; *width = 800; *height = 600; /* @@ Wine registry key: HKCU\Software\Wine\Explorer\Desktops */ if (!RegOpenKeyW( HKEY_CURRENT_USER, desktop_keyW, &hkey )) { if (!RegQueryValueExW( hkey, name, 0, NULL, (LPBYTE)buffer, &size )) { found = TRUE; if (!parse_size( buffer, width, height )) *width = *height = 0; } RegCloseKey( hkey ); } return found; } static BOOL get_default_enable_shell( const WCHAR *name ) { static const WCHAR desktop_keyW[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\', 'E','x','p','l','o','r','e','r','\\', 'D','e','s','k','t','o','p','s',0}; static const WCHAR enable_shellW[] = {'E','n','a','b','l','e','S','h','e','l','l',0}; static const WCHAR shellW[] = {'s','h','e','l','l',0}; HKEY hkey; BOOL found = FALSE; BOOL result; DWORD size = sizeof(result); /* @@ Wine registry key: HKCU\Software\Wine\Explorer\Desktops */ if (!RegOpenKeyW( HKEY_CURRENT_USER, desktop_keyW, &hkey )) { if (!RegGetValueW( hkey, name, enable_shellW, RRF_RT_REG_DWORD, NULL, &result, &size )) found = TRUE; RegCloseKey( hkey ); } /* Default off, except for the magic desktop name "shell" */ if (!found) result = (lstrcmpiW( name, shellW ) == 0); return result; } static HMODULE load_graphics_driver( const WCHAR *driver, const GUID *guid ) { static const WCHAR device_keyW[] = { 'S','y','s','t','e','m','\\', 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', 'C','o','n','t','r','o','l','\\', 'V','i','d','e','o','\\', '{','%','0','8','x','-','%','0','4','x','-','%','0','4','x','-', '%','0','2','x','%','0','2','x','-','%','0','2','x','%','0','2','x','%','0','2','x', '%','0','2','x','%','0','2','x','%','0','2','x','}','\\','0','0','0','0',0}; static const WCHAR graphics_driverW[] = {'G','r','a','p','h','i','c','s','D','r','i','v','e','r',0}; static const WCHAR driversW[] = {'S','o','f','t','w','a','r','e','\\', 'W','i','n','e','\\','D','r','i','v','e','r','s',0}; static const WCHAR graphicsW[] = {'G','r','a','p','h','i','c','s',0}; static const WCHAR drv_formatW[] = {'w','i','n','e','%','s','.','d','r','v',0}; WCHAR buffer[MAX_PATH], libname[32], *name, *next; WCHAR key[sizeof(device_keyW)/sizeof(WCHAR) + 39]; HMODULE module = 0; HKEY hkey; char error[80]; if (!driver) { strcpyW( buffer, default_driver ); /* @@ Wine registry key: HKCU\Software\Wine\Drivers */ if (!RegOpenKeyW( HKEY_CURRENT_USER, driversW, &hkey )) { DWORD count = sizeof(buffer); RegQueryValueExW( hkey, graphicsW, 0, NULL, (LPBYTE)buffer, &count ); RegCloseKey( hkey ); } } else lstrcpynW( buffer, driver, sizeof(buffer)/sizeof(WCHAR) ); name = buffer; while (name) { next = strchrW( name, ',' ); if (next) *next++ = 0; snprintfW( libname, sizeof(libname)/sizeof(WCHAR), drv_formatW, name ); if ((module = LoadLibraryW( libname )) != 0) break; switch (GetLastError()) { case ERROR_MOD_NOT_FOUND: strcpy( error, "The graphics driver is missing. Check your build!" ); break; case ERROR_DLL_INIT_FAILED: strcpy( error, "Make sure that your X server is running and that $DISPLAY is set correctly." ); break; default: sprintf( error, "Unknown error (%u).", GetLastError() ); break; } name = next; } if (module) { GetModuleFileNameW( module, buffer, MAX_PATH ); TRACE( "display %s driver %s\n", debugstr_guid(guid), debugstr_w(buffer) ); } sprintfW( key, device_keyW, guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7] ); if (!RegCreateKeyExW( HKEY_LOCAL_MACHINE, key, 0, NULL, REG_OPTION_VOLATILE, KEY_SET_VALUE, NULL, &hkey, NULL )) { if (module) RegSetValueExW( hkey, graphics_driverW, 0, REG_SZ, (BYTE *)buffer, (strlenW(buffer) + 1) * sizeof(WCHAR) ); else RegSetValueExA( hkey, "DriverError", 0, REG_SZ, (BYTE *)error, strlen(error) + 1 ); RegCloseKey( hkey ); } return module; } static void initialize_display_settings(void) { DEVMODEW dmW; /* Store current display mode in the registry */ if (EnumDisplaySettingsExW( NULL, ENUM_CURRENT_SETTINGS, &dmW, 0 )) { WINE_TRACE( "Current display mode %ux%u %u bpp %u Hz\n", dmW.dmPelsWidth, dmW.dmPelsHeight, dmW.dmBitsPerPel, dmW.dmDisplayFrequency ); ChangeDisplaySettingsExW( NULL, &dmW, 0, CDS_GLOBAL | CDS_NORESET | CDS_UPDATEREGISTRY, NULL ); } } static void set_desktop_window_title( HWND hwnd, const WCHAR *name ) { static const WCHAR desktop_nameW[] = {'W','i','n','e',' ','d','e','s','k','t','o','p',0}; static const WCHAR desktop_name_separatorW[] = {' ', '-', ' ', 0}; WCHAR *window_titleW = NULL; int window_title_len; if (!name[0]) { SetWindowTextW( hwnd, desktop_nameW ); return; } window_title_len = strlenW(name) * sizeof(WCHAR) + sizeof(desktop_name_separatorW) + sizeof(desktop_nameW); window_titleW = HeapAlloc( GetProcessHeap(), 0, window_title_len ); if (!window_titleW) { SetWindowTextW( hwnd, desktop_nameW ); return; } strcpyW( window_titleW, name ); strcatW( window_titleW, desktop_name_separatorW ); strcatW( window_titleW, desktop_nameW ); SetWindowTextW( hwnd, window_titleW ); HeapFree( GetProcessHeap(), 0, window_titleW ); } /* main desktop management function */ void manage_desktop( WCHAR *arg ) { static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0}; HDESK desktop = 0; GUID guid; MSG msg; HWND hwnd; HMODULE graphics_driver; unsigned int width, height; WCHAR *cmdline = NULL, *driver = NULL; WCHAR *p = arg; const WCHAR *name = NULL; BOOL enable_shell = FALSE; /* get the rest of the command line (if any) */ while (*p && !isspace(*p)) p++; if (*p) { *p++ = 0; while (*p && isspace(*p)) p++; if (*p) cmdline = p; } /* parse the desktop option */ /* the option is of the form /desktop=name[,widthxheight[,driver]] */ if (*arg == '=' || *arg == ',') { arg++; name = arg; if ((p = strchrW( arg, ',' ))) { *p++ = 0; if ((driver = strchrW( p, ',' ))) *driver++ = 0; } if (!p || !parse_size( p, &width, &height )) get_default_desktop_size( name, &width, &height ); } else if ((name = get_default_desktop_name())) { if (!get_default_desktop_size( name, &width, &height )) width = height = 0; } if (name) enable_shell = get_default_enable_shell( name ); if (name && width && height) { if (!(desktop = CreateDesktopW( name, NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL ))) { WINE_ERR( "failed to create desktop %s error %d\n", wine_dbgstr_w(name), GetLastError() ); ExitProcess( 1 ); } SetThreadDesktop( desktop ); } UuidCreate( &guid ); TRACE( "display guid %s\n", debugstr_guid(&guid) ); graphics_driver = load_graphics_driver( driver, &guid ); /* create the desktop window */ hwnd = CreateWindowExW( 0, DESKTOP_CLASS_ATOM, NULL, WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, 0, 0, 0, 0, 0, 0, &guid ); if (hwnd) { /* create the HWND_MESSAGE parent */ CreateWindowExW( 0, messageW, NULL, WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, 0, 100, 100, 0, 0, 0, NULL ); using_root = !desktop || !create_desktop( graphics_driver, name, width, height ); SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)desktop_wnd_proc ); SendMessageW( hwnd, WM_SETICON, ICON_BIG, (LPARAM)LoadIconW( 0, MAKEINTRESOURCEW(OIC_WINLOGO))); if (name) set_desktop_window_title( hwnd, name ); SetWindowPos( hwnd, 0, GetSystemMetrics(SM_XVIRTUALSCREEN), GetSystemMetrics(SM_YVIRTUALSCREEN), GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN), SWP_SHOWWINDOW ); SystemParametersInfoW( SPI_SETDESKWALLPAPER, 0, NULL, FALSE ); ClipCursor( NULL ); initialize_display_settings(); initialize_appbar(); if (graphics_driver) { HMODULE shell32; void (WINAPI *pShellDDEInit)( BOOL ); if (using_root) enable_shell = FALSE; initialize_systray( graphics_driver, using_root, enable_shell ); if (!using_root) initialize_launchers( hwnd ); if ((shell32 = LoadLibraryA( "shell32.dll" )) && (pShellDDEInit = (void *)GetProcAddress( shell32, (LPCSTR)188))) { pShellDDEInit( TRUE ); } } } /* if we have a command line, execute it */ if (cmdline) { STARTUPINFOW si; PROCESS_INFORMATION pi; memset( &si, 0, sizeof(si) ); si.cb = sizeof(si); WINE_TRACE( "starting %s\n", wine_dbgstr_w(cmdline) ); if (CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi )) { CloseHandle( pi.hThread ); CloseHandle( pi.hProcess ); } } desktopshellbrowserwindow_init(); shellwindows_init(); /* run the desktop message loop */ if (hwnd) { WINE_TRACE( "desktop message loop starting on hwnd %p\n", hwnd ); while (GetMessageW( &msg, 0, 0, 0 )) DispatchMessageW( &msg ); WINE_TRACE( "desktop message loop exiting for hwnd %p\n", hwnd ); } ExitProcess( 0 ); } /* IShellWindows implementation */ static HRESULT WINAPI shellwindows_QueryInterface(IShellWindows *iface, REFIID riid, void **ppvObject) { struct shellwindows *This = impl_from_IShellWindows(iface); TRACE("%s %p\n", debugstr_guid(riid), ppvObject); if (IsEqualGUID(riid, &IID_IShellWindows) || IsEqualGUID(riid, &IID_IDispatch) || IsEqualGUID(riid, &IID_IUnknown)) { *ppvObject = &This->IShellWindows_iface; } else { WARN("Unsupported interface %s\n", debugstr_guid(riid)); *ppvObject = NULL; } if (*ppvObject) { IUnknown_AddRef((IUnknown*)*ppvObject); return S_OK; } return E_NOINTERFACE; } static ULONG WINAPI shellwindows_AddRef(IShellWindows *iface) { return 2; } static ULONG WINAPI shellwindows_Release(IShellWindows *iface) { return 1; } static HRESULT WINAPI shellwindows_GetTypeInfoCount(IShellWindows *iface, UINT *pctinfo) { TRACE("%p\n", pctinfo); *pctinfo = 1; return S_OK; } static HRESULT WINAPI shellwindows_GetTypeInfo(IShellWindows *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) { TRACE("%d %d %p\n", iTInfo, lcid, ppTInfo); return get_typeinfo(IShellWindows_tid, ppTInfo); } static HRESULT WINAPI shellwindows_GetIDsOfNames(IShellWindows *iface, REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) { ITypeInfo *typeinfo; HRESULT hr; TRACE("%s %p %d %d %p\n", debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId); if (!rgszNames || cNames == 0 || !rgDispId) return E_INVALIDARG; hr = get_typeinfo(IShellWindows_tid, &typeinfo); if (SUCCEEDED(hr)) { hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId); ITypeInfo_Release(typeinfo); } return hr; } static HRESULT WINAPI shellwindows_Invoke(IShellWindows *iface, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) { ITypeInfo *typeinfo; HRESULT hr; TRACE("%d %s %d %08x %p %p %p %p\n", dispIdMember, debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); hr = get_typeinfo(IShellWindows_tid, &typeinfo); if (SUCCEEDED(hr)) { hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); ITypeInfo_Release(typeinfo); } return hr; } static HRESULT WINAPI shellwindows_get_Count(IShellWindows *iface, LONG *count) { FIXME("%p\n", count); return E_NOTIMPL; } static HRESULT WINAPI shellwindows_Item(IShellWindows *iface, VARIANT index, IDispatch **folder) { FIXME("%s %p\n", debugstr_variant(&index), folder); return E_NOTIMPL; } static HRESULT WINAPI shellwindows__NewEnum(IShellWindows *iface, IUnknown **ppunk) { FIXME("%p\n", ppunk); return E_NOTIMPL; } static HRESULT WINAPI shellwindows_Register(IShellWindows *iface, IDispatch *disp, LONG hWnd, int class, LONG *cookie) { FIXME("%p 0x%x 0x%x %p\n", disp, hWnd, class, cookie); return E_NOTIMPL; } static HRESULT WINAPI shellwindows_RegisterPending(IShellWindows *iface, LONG threadid, VARIANT *loc, VARIANT *root, int class, LONG *cookie) { FIXME("0x%x %s %s 0x%x %p\n", threadid, debugstr_variant(loc), debugstr_variant(root), class, cookie); return E_NOTIMPL; } static HRESULT WINAPI shellwindows_Revoke(IShellWindows *iface, LONG cookie) { FIXME("0x%x\n", cookie); return E_NOTIMPL; } static HRESULT WINAPI shellwindows_OnNavigate(IShellWindows *iface, LONG cookie, VARIANT *loc) { FIXME("0x%x %p\n", cookie, debugstr_variant(loc)); return E_NOTIMPL; } static HRESULT WINAPI shellwindows_OnActivated(IShellWindows *iface, LONG cookie, VARIANT_BOOL active) { FIXME("0x%x 0x%x\n", cookie, active); return E_NOTIMPL; } static HRESULT WINAPI shellwindows_FindWindowSW(IShellWindows *iface, VARIANT *loc, VARIANT *root, int class, LONG *hwnd, int options, IDispatch **disp) { TRACE("%s %p 0x%x %p 0x%x %p\n", debugstr_variant(loc), debugstr_variant(root), class, hwnd, options, disp); if (class != SWC_DESKTOP) { WARN("only SWC_DESKTOP class supported.\n"); return E_NOTIMPL; } *hwnd = HandleToLong(GetDesktopWindow()); if (options & SWFO_NEEDDISPATCH) { *disp = (IDispatch*)&desktopshellbrowserwindow.IWebBrowser2_iface; IDispatch_AddRef(*disp); } return S_OK; } static HRESULT WINAPI shellwindows_OnCreated(IShellWindows *iface, LONG cookie, IUnknown *punk) { FIXME("0x%x %p\n", cookie, punk); return E_NOTIMPL; } static HRESULT WINAPI shellwindows_ProcessAttachDetach(IShellWindows *iface, VARIANT_BOOL attach) { FIXME("0x%x\n", attach); return E_NOTIMPL; } static const IShellWindowsVtbl shellwindowsvtbl = { shellwindows_QueryInterface, shellwindows_AddRef, shellwindows_Release, shellwindows_GetTypeInfoCount, shellwindows_GetTypeInfo, shellwindows_GetIDsOfNames, shellwindows_Invoke, shellwindows_get_Count, shellwindows_Item, shellwindows__NewEnum, shellwindows_Register, shellwindows_RegisterPending, shellwindows_Revoke, shellwindows_OnNavigate, shellwindows_OnActivated, shellwindows_FindWindowSW, shellwindows_OnCreated, shellwindows_ProcessAttachDetach }; struct shellwindows_classfactory { IClassFactory IClassFactory_iface; DWORD classreg; }; static inline struct shellwindows_classfactory *impl_from_IClassFactory(IClassFactory *iface) { return CONTAINING_RECORD(iface, struct shellwindows_classfactory, IClassFactory_iface); } static HRESULT WINAPI swclassfactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppvObject) { struct shellwindows_classfactory *This = impl_from_IClassFactory(iface); TRACE("%s %p\n", debugstr_guid(riid), ppvObject); if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IClassFactory)) { *ppvObject = &This->IClassFactory_iface; } else { WARN("Unsupported interface %s\n", debugstr_guid(riid)); *ppvObject = NULL; } if (*ppvObject) { IUnknown_AddRef((IUnknown*)*ppvObject); return S_OK; } return E_NOINTERFACE; } static ULONG WINAPI swclassfactory_AddRef(IClassFactory *iface) { return 2; } static ULONG WINAPI swclassfactory_Release(IClassFactory *iface) { return 1; } static HRESULT WINAPI swclassfactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter, REFIID riid, void **ppvObject) { TRACE("%p %s %p\n", pUnkOuter, debugstr_guid(riid), ppvObject); return IShellWindows_QueryInterface(&shellwindows.IShellWindows_iface, riid, ppvObject); } static HRESULT WINAPI swclassfactory_LockServer(IClassFactory *iface, BOOL lock) { TRACE("%u\n", lock); return E_NOTIMPL; } static const IClassFactoryVtbl swclassfactoryvtbl = { swclassfactory_QueryInterface, swclassfactory_AddRef, swclassfactory_Release, swclassfactory_CreateInstance, swclassfactory_LockServer }; static struct shellwindows_classfactory shellwindows_classfactory = { { &swclassfactoryvtbl } }; static HRESULT WINAPI webbrowser_QueryInterface(IWebBrowser2 *iface, REFIID riid, void **ppv) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); *ppv = NULL; if (IsEqualGUID(&IID_IWebBrowser2, riid) || IsEqualGUID(&IID_IWebBrowserApp, riid) || IsEqualGUID(&IID_IWebBrowser, riid) || IsEqualGUID(&IID_IDispatch, riid) || IsEqualGUID(&IID_IUnknown, riid)) { *ppv = &This->IWebBrowser2_iface; } else if (IsEqualGUID(&IID_IServiceProvider, riid)) { *ppv = &This->IServiceProvider_iface; } if (*ppv) { IUnknown_AddRef((IUnknown*)*ppv); return S_OK; } FIXME("(%p)->(%s %p) interface not supported\n", This, debugstr_guid(riid), ppv); return E_NOINTERFACE; } static ULONG WINAPI webbrowser_AddRef(IWebBrowser2 *iface) { return 2; } static ULONG WINAPI webbrowser_Release(IWebBrowser2 *iface) { return 1; } /* IDispatch methods */ static HRESULT WINAPI webbrowser_GetTypeInfoCount(IWebBrowser2 *iface, UINT *pctinfo) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); TRACE("(%p)->(%p)\n", This, pctinfo); *pctinfo = 1; return S_OK; } static HRESULT WINAPI webbrowser_GetTypeInfo(IWebBrowser2 *iface, UINT iTInfo, LCID lcid, LPTYPEINFO *ppTInfo) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); TRACE("(%p)->(%d %d %p)\n", This, iTInfo, lcid, ppTInfo); return get_typeinfo(IWebBrowser2_tid, ppTInfo); } static HRESULT WINAPI webbrowser_GetIDsOfNames(IWebBrowser2 *iface, REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); ITypeInfo *typeinfo; HRESULT hr; TRACE("(%p)->(%s %p %d %d %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId); if(!rgszNames || cNames == 0 || !rgDispId) return E_INVALIDARG; hr = get_typeinfo(IWebBrowser2_tid, &typeinfo); if (SUCCEEDED(hr)) { hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId); ITypeInfo_Release(typeinfo); } return hr; } static HRESULT WINAPI webbrowser_Invoke(IWebBrowser2 *iface, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); ITypeInfo *typeinfo; HRESULT hr; TRACE("(%p)->(%d %s %d %08x %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); hr = get_typeinfo(IWebBrowser2_tid, &typeinfo); if (SUCCEEDED(hr)) { hr = ITypeInfo_Invoke(typeinfo, &This->IWebBrowser2_iface, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); ITypeInfo_Release(typeinfo); } return hr; } /* IWebBrowser methods */ static HRESULT WINAPI webbrowser_GoBack(IWebBrowser2 *iface) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p): stub\n", This); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_GoForward(IWebBrowser2 *iface) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p): stub\n", This); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_GoHome(IWebBrowser2 *iface) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p): stub\n", This); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_GoSearch(IWebBrowser2 *iface) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)\n", This); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_Navigate(IWebBrowser2 *iface, BSTR szUrl, VARIANT *Flags, VARIANT *TargetFrameName, VARIANT *PostData, VARIANT *Headers) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%s %s %s %s %s): stub\n", This, debugstr_w(szUrl), debugstr_variant(Flags), debugstr_variant(TargetFrameName), debugstr_variant(PostData), debugstr_variant(Headers)); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_Refresh(IWebBrowser2 *iface) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p): stub\n", This); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_Refresh2(IWebBrowser2 *iface, VARIANT *Level) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%s): stub\n", This, debugstr_variant(Level)); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_Stop(IWebBrowser2 *iface) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p): stub\n", This); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_get_Application(IWebBrowser2 *iface, IDispatch **ppDisp) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); TRACE("(%p)->(%p)\n", This, ppDisp); *ppDisp = (IDispatch*)iface; IDispatch_AddRef(*ppDisp); return S_OK; } static HRESULT WINAPI webbrowser_get_Parent(IWebBrowser2 *iface, IDispatch **ppDisp) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%p)\n", This, ppDisp); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_get_Container(IWebBrowser2 *iface, IDispatch **ppDisp) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%p)\n", This, ppDisp); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_get_Document(IWebBrowser2 *iface, IDispatch **ppDisp) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%p)\n", This, ppDisp); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_get_TopLevelContainer(IWebBrowser2 *iface, VARIANT_BOOL *pBool) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%p)\n", This, pBool); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_get_Type(IWebBrowser2 *iface, BSTR *Type) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%p)\n", This, Type); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_get_Left(IWebBrowser2 *iface, LONG *pl) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%p)\n", This, pl); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_put_Left(IWebBrowser2 *iface, LONG Left) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%d)\n", This, Left); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_get_Top(IWebBrowser2 *iface, LONG *pl) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%p)\n", This, pl); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_put_Top(IWebBrowser2 *iface, LONG Top) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%d)\n", This, Top); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_get_Width(IWebBrowser2 *iface, LONG *pl) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%p)\n", This, pl); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_put_Width(IWebBrowser2 *iface, LONG Width) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%d)\n", This, Width); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_get_Height(IWebBrowser2 *iface, LONG *pl) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%p)\n", This, pl); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_put_Height(IWebBrowser2 *iface, LONG Height) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%d)\n", This, Height); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_get_LocationName(IWebBrowser2 *iface, BSTR *LocationName) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%p)\n", This, LocationName); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_get_LocationURL(IWebBrowser2 *iface, BSTR *LocationURL) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%p)\n", This, LocationURL); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_get_Busy(IWebBrowser2 *iface, VARIANT_BOOL *pBool) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%p)\n", This, pBool); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_Quit(IWebBrowser2 *iface) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)\n", This); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_ClientToWindow(IWebBrowser2 *iface, int *pcx, int *pcy) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%p %p)\n", This, pcx, pcy); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_PutProperty(IWebBrowser2 *iface, BSTR szProperty, VARIANT vtValue) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%s %s)\n", This, debugstr_w(szProperty), debugstr_variant(&vtValue)); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_GetProperty(IWebBrowser2 *iface, BSTR szProperty, VARIANT *pvtValue) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%s %s)\n", This, debugstr_w(szProperty), debugstr_variant(pvtValue)); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_get_Name(IWebBrowser2 *iface, BSTR *Name) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%p)\n", This, Name); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_get_HWND(IWebBrowser2 *iface, SHANDLE_PTR *pHWND) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%p)\n", This, pHWND); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_get_FullName(IWebBrowser2 *iface, BSTR *FullName) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%p)\n", This, FullName); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_get_Path(IWebBrowser2 *iface, BSTR *Path) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%p)\n", This, Path); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_get_Visible(IWebBrowser2 *iface, VARIANT_BOOL *pBool) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%p)\n", This, pBool); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_put_Visible(IWebBrowser2 *iface, VARIANT_BOOL Value) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%x)\n", This, Value); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_get_StatusBar(IWebBrowser2 *iface, VARIANT_BOOL *pBool) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%p)\n", This, pBool); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_put_StatusBar(IWebBrowser2 *iface, VARIANT_BOOL Value) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%x)\n", This, Value); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_get_StatusText(IWebBrowser2 *iface, BSTR *StatusText) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%p)\n", This, StatusText); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_put_StatusText(IWebBrowser2 *iface, BSTR StatusText) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%s)\n", This, debugstr_w(StatusText)); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_get_ToolBar(IWebBrowser2 *iface, int *Value) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%p)\n", This, Value); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_put_ToolBar(IWebBrowser2 *iface, int Value) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%x)\n", This, Value); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_get_MenuBar(IWebBrowser2 *iface, VARIANT_BOOL *Value) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%p)\n", This, Value); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_put_MenuBar(IWebBrowser2 *iface, VARIANT_BOOL Value) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%x)\n", This, Value); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_get_FullScreen(IWebBrowser2 *iface, VARIANT_BOOL *pbFullScreen) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%p)\n", This, pbFullScreen); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_put_FullScreen(IWebBrowser2 *iface, VARIANT_BOOL bFullScreen) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%x)\n", This, bFullScreen); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_Navigate2(IWebBrowser2 *iface, VARIANT *URL, VARIANT *Flags, VARIANT *TargetFrameName, VARIANT *PostData, VARIANT *Headers) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%s %s %s %s %s)\n", This, debugstr_variant(URL), debugstr_variant(Flags), debugstr_variant(TargetFrameName), debugstr_variant(PostData), debugstr_variant(Headers)); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_QueryStatusWB(IWebBrowser2 *iface, OLECMDID cmdID, OLECMDF *pcmdf) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%d %p)\n", This, cmdID, pcmdf); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_ExecWB(IWebBrowser2 *iface, OLECMDID cmdID, OLECMDEXECOPT cmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%d %d %s %p)\n", This, cmdID, cmdexecopt, debugstr_variant(pvaIn), pvaOut); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_ShowBrowserBar(IWebBrowser2 *iface, VARIANT *pvaClsid, VARIANT *pvarShow, VARIANT *pvarSize) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%s %s %s)\n", This, debugstr_variant(pvaClsid), debugstr_variant(pvarShow), debugstr_variant(pvarSize)); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_get_ReadyState(IWebBrowser2 *iface, READYSTATE *lpReadyState) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%p)\n", This, lpReadyState); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_get_Offline(IWebBrowser2 *iface, VARIANT_BOOL *pbOffline) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%p)\n", This, pbOffline); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_put_Offline(IWebBrowser2 *iface, VARIANT_BOOL bOffline) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%x)\n", This, bOffline); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_get_Silent(IWebBrowser2 *iface, VARIANT_BOOL *pbSilent) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%p)\n", This, pbSilent); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_put_Silent(IWebBrowser2 *iface, VARIANT_BOOL bSilent) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%x)\n", This, bSilent); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_get_RegisterAsBrowser(IWebBrowser2 *iface, VARIANT_BOOL *pbRegister) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%p)\n", This, pbRegister); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_put_RegisterAsBrowser(IWebBrowser2 *iface, VARIANT_BOOL bRegister) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%x)\n", This, bRegister); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_get_RegisterAsDropTarget(IWebBrowser2 *iface, VARIANT_BOOL *pbRegister) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%p)\n", This, pbRegister); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_put_RegisterAsDropTarget(IWebBrowser2 *iface, VARIANT_BOOL bRegister) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%x)\n", This, bRegister); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_get_TheaterMode(IWebBrowser2 *iface, VARIANT_BOOL *pbRegister) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%p)\n", This, pbRegister); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_put_TheaterMode(IWebBrowser2 *iface, VARIANT_BOOL bRegister) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); TRACE("(%p)->(%x)\n", This, bRegister); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_get_AddressBar(IWebBrowser2 *iface, VARIANT_BOOL *Value) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%p)\n", This, Value); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_put_AddressBar(IWebBrowser2 *iface, VARIANT_BOOL Value) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%x)\n", This, Value); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_get_Resizable(IWebBrowser2 *iface, VARIANT_BOOL *Value) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%p)\n", This, Value); return E_NOTIMPL; } static HRESULT WINAPI webbrowser_put_Resizable(IWebBrowser2 *iface, VARIANT_BOOL Value) { struct shellbrowserwindow *This = impl_from_IWebBrowser2(iface); FIXME("(%p)->(%x)\n", This, Value); return E_NOTIMPL; } static const IWebBrowser2Vtbl webbrowser2vtbl = { webbrowser_QueryInterface, webbrowser_AddRef, webbrowser_Release, webbrowser_GetTypeInfoCount, webbrowser_GetTypeInfo, webbrowser_GetIDsOfNames, webbrowser_Invoke, webbrowser_GoBack, webbrowser_GoForward, webbrowser_GoHome, webbrowser_GoSearch, webbrowser_Navigate, webbrowser_Refresh, webbrowser_Refresh2, webbrowser_Stop, webbrowser_get_Application, webbrowser_get_Parent, webbrowser_get_Container, webbrowser_get_Document, webbrowser_get_TopLevelContainer, webbrowser_get_Type, webbrowser_get_Left, webbrowser_put_Left, webbrowser_get_Top, webbrowser_put_Top, webbrowser_get_Width, webbrowser_put_Width, webbrowser_get_Height, webbrowser_put_Height, webbrowser_get_LocationName, webbrowser_get_LocationURL, webbrowser_get_Busy, webbrowser_Quit, webbrowser_ClientToWindow, webbrowser_PutProperty, webbrowser_GetProperty, webbrowser_get_Name, webbrowser_get_HWND, webbrowser_get_FullName, webbrowser_get_Path, webbrowser_get_Visible, webbrowser_put_Visible, webbrowser_get_StatusBar, webbrowser_put_StatusBar, webbrowser_get_StatusText, webbrowser_put_StatusText, webbrowser_get_ToolBar, webbrowser_put_ToolBar, webbrowser_get_MenuBar, webbrowser_put_MenuBar, webbrowser_get_FullScreen, webbrowser_put_FullScreen, webbrowser_Navigate2, webbrowser_QueryStatusWB, webbrowser_ExecWB, webbrowser_ShowBrowserBar, webbrowser_get_ReadyState, webbrowser_get_Offline, webbrowser_put_Offline, webbrowser_get_Silent, webbrowser_put_Silent, webbrowser_get_RegisterAsBrowser, webbrowser_put_RegisterAsBrowser, webbrowser_get_RegisterAsDropTarget, webbrowser_put_RegisterAsDropTarget, webbrowser_get_TheaterMode, webbrowser_put_TheaterMode, webbrowser_get_AddressBar, webbrowser_put_AddressBar, webbrowser_get_Resizable, webbrowser_put_Resizable }; static HRESULT WINAPI serviceprovider_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv) { struct shellbrowserwindow *This = impl_from_IServiceProvider(iface); return IWebBrowser2_QueryInterface(&This->IWebBrowser2_iface, riid, ppv); } static ULONG WINAPI serviceprovider_AddRef(IServiceProvider *iface) { struct shellbrowserwindow *This = impl_from_IServiceProvider(iface); return IWebBrowser2_AddRef(&This->IWebBrowser2_iface); } static ULONG WINAPI serviceprovider_Release(IServiceProvider *iface) { struct shellbrowserwindow *This = impl_from_IServiceProvider(iface); return IWebBrowser2_Release(&This->IWebBrowser2_iface); } static HRESULT WINAPI serviceprovider_QueryService(IServiceProvider *iface, REFGUID service, REFIID riid, void **ppv) { struct shellbrowserwindow *This = impl_from_IServiceProvider(iface); TRACE("%s %s %p\n", debugstr_guid(service), debugstr_guid(riid), ppv); if (IsEqualGUID(service, &SID_STopLevelBrowser)) return IShellBrowser_QueryInterface(&This->IShellBrowser_iface, riid, ppv); WARN("unknown service id %s\n", debugstr_guid(service)); return E_NOTIMPL; } static const IServiceProviderVtbl serviceprovidervtbl = { serviceprovider_QueryInterface, serviceprovider_AddRef, serviceprovider_Release, serviceprovider_QueryService }; /* IShellBrowser */ static HRESULT WINAPI shellbrowser_QueryInterface(IShellBrowser *iface, REFIID riid, void **ppv) { TRACE("%s %p\n", debugstr_guid(riid), ppv); *ppv = NULL; if (IsEqualGUID(&IID_IShellBrowser, riid) || IsEqualGUID(&IID_IOleWindow, riid) || IsEqualGUID(&IID_IUnknown, riid)) { *ppv = iface; } if (*ppv) { IUnknown_AddRef((IUnknown*)*ppv); return S_OK; } return E_NOINTERFACE; } static ULONG WINAPI shellbrowser_AddRef(IShellBrowser *iface) { struct shellbrowserwindow *This = impl_from_IShellBrowser(iface); return IWebBrowser2_AddRef(&This->IWebBrowser2_iface); } static ULONG WINAPI shellbrowser_Release(IShellBrowser *iface) { struct shellbrowserwindow *This = impl_from_IShellBrowser(iface); return IWebBrowser2_Release(&This->IWebBrowser2_iface); } static HRESULT WINAPI shellbrowser_GetWindow(IShellBrowser *iface, HWND *phwnd) { FIXME("%p\n", phwnd); return E_NOTIMPL; } static HRESULT WINAPI shellbrowser_ContextSensitiveHelp(IShellBrowser *iface, BOOL mode) { FIXME("%d\n", mode); return E_NOTIMPL; } static HRESULT WINAPI shellbrowser_InsertMenusSB(IShellBrowser *iface, HMENU hmenuShared, OLEMENUGROUPWIDTHS *menuwidths) { FIXME("%p %p\n", hmenuShared, menuwidths); return E_NOTIMPL; } static HRESULT WINAPI shellbrowser_SetMenuSB(IShellBrowser *iface, HMENU hmenuShared, HOLEMENU holemenuReserved, HWND hwndActiveObject) { FIXME("%p %p %p\n", hmenuShared, holemenuReserved, hwndActiveObject); return E_NOTIMPL; } static HRESULT WINAPI shellbrowser_RemoveMenusSB(IShellBrowser *iface, HMENU hmenuShared) { FIXME("%p\n", hmenuShared); return E_NOTIMPL; } static HRESULT WINAPI shellbrowser_SetStatusTextSB(IShellBrowser *iface, LPCOLESTR text) { FIXME("%s\n", debugstr_w(text)); return E_NOTIMPL; } static HRESULT WINAPI shellbrowser_EnableModelessSB(IShellBrowser *iface, BOOL enable) { FIXME("%d\n", enable); return E_NOTIMPL; } static HRESULT WINAPI shellbrowser_TranslateAcceleratorSB(IShellBrowser *iface, MSG *pmsg, WORD wID) { FIXME("%p 0x%x\n", pmsg, wID); return E_NOTIMPL; } static HRESULT WINAPI shellbrowser_BrowseObject(IShellBrowser *iface, LPCITEMIDLIST pidl, UINT flags) { FIXME("%p %x\n", pidl, flags); return E_NOTIMPL; } static HRESULT WINAPI shellbrowser_GetViewStateStream(IShellBrowser *iface, DWORD mode, IStream **stream) { FIXME("0x%x %p\n", mode, stream); return E_NOTIMPL; } static HRESULT WINAPI shellbrowser_GetControlWindow(IShellBrowser *iface, UINT id, HWND *phwnd) { FIXME("%d %p\n", id, phwnd); return E_NOTIMPL; } static HRESULT WINAPI shellbrowser_SendControlMsg(IShellBrowser *iface, UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pret) { FIXME("%d %d %lx %lx %p\n", id, uMsg, wParam, lParam, pret); return E_NOTIMPL; } static HRESULT WINAPI shellbrowser_QueryActiveShellView(IShellBrowser *iface, IShellView **view) { TRACE("%p\n", view); *view = desktopshellbrowserwindow.view; IShellView_AddRef(*view); return S_OK; } static HRESULT WINAPI shellbrowser_OnViewWindowActive(IShellBrowser *iface, IShellView *view) { FIXME("%p\n", view); return E_NOTIMPL; } static HRESULT WINAPI shellbrowser_SetToolbarItems(IShellBrowser *iface, LPTBBUTTONSB buttons, UINT count, UINT flags) { FIXME("%p %d 0x%x\n", buttons, count, flags); return E_NOTIMPL; } static const IShellBrowserVtbl shellbrowservtbl = { shellbrowser_QueryInterface, shellbrowser_AddRef, shellbrowser_Release, shellbrowser_GetWindow, shellbrowser_ContextSensitiveHelp, shellbrowser_InsertMenusSB, shellbrowser_SetMenuSB, shellbrowser_RemoveMenusSB, shellbrowser_SetStatusTextSB, shellbrowser_EnableModelessSB, shellbrowser_TranslateAcceleratorSB, shellbrowser_BrowseObject, shellbrowser_GetViewStateStream, shellbrowser_GetControlWindow, shellbrowser_SendControlMsg, shellbrowser_QueryActiveShellView, shellbrowser_OnViewWindowActive, shellbrowser_SetToolbarItems }; static void desktopshellbrowserwindow_init(void) { IShellFolder *folder; desktopshellbrowserwindow.IWebBrowser2_iface.lpVtbl = &webbrowser2vtbl; desktopshellbrowserwindow.IServiceProvider_iface.lpVtbl = &serviceprovidervtbl; desktopshellbrowserwindow.IShellBrowser_iface.lpVtbl = &shellbrowservtbl; if (FAILED(SHGetDesktopFolder(&folder))) return; IShellFolder_CreateViewObject(folder, NULL, &IID_IShellView, (void**)&desktopshellbrowserwindow.view); } static void shellwindows_init(void) { HRESULT hr; CoInitialize(NULL); shellwindows.IShellWindows_iface.lpVtbl = &shellwindowsvtbl; hr = CoRegisterClassObject(&CLSID_ShellWindows, (IUnknown*)&shellwindows_classfactory.IClassFactory_iface, CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &shellwindows_classfactory.classreg); if (FAILED(hr)) WARN("Failed to register ShellWindows object: %08x\n", hr); }