4 * Copyright 2008 Thomas Bluemel
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 WINE_DEFAULT_DEBUG_CHANNEL(desktop
);
25 BOOL WINAPI
SetShellWindowEx(HWND
, HWND
);
27 #define SHDESK_TAG 0x4b534544
29 static const WCHAR szProgmanClassName
[] = L
"Progman";
30 static const WCHAR szProgmanWindowName
[] = L
"Program Manager";
32 class CDesktopBrowser
:
33 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
35 public ICommDlgBrowser
,
36 public IServiceProvider
43 HWND hWndDesktopListView
;
44 CComPtr
<IShellDesktopTray
> ShellDesk
;
45 CComPtr
<IShellView
> DesktopView
;
46 IShellBrowser
*DefaultShellBrowser
;
47 LPITEMIDLIST pidlDesktopDirectory
;
48 LPITEMIDLIST pidlDesktop
;
52 HRESULT
Initialize(HWND hWndx
, IShellDesktopTray
*ShellDeskx
);
53 HWND
FindDesktopListView();
55 HWND
DesktopGetWindowControl(IN UINT id
);
56 static LRESULT CALLBACK
ProgmanWindowProc(IN HWND hwnd
, IN UINT uMsg
, IN WPARAM wParam
, IN LPARAM lParam
);
57 static BOOL
MessageLoop();
59 // *** IOleWindow methods ***
60 virtual HRESULT STDMETHODCALLTYPE
GetWindow(HWND
*lphwnd
);
61 virtual HRESULT STDMETHODCALLTYPE
ContextSensitiveHelp(BOOL fEnterMode
);
63 // *** IShellBrowser methods ***
64 virtual HRESULT STDMETHODCALLTYPE
InsertMenusSB(HMENU hmenuShared
, LPOLEMENUGROUPWIDTHS lpMenuWidths
);
65 virtual HRESULT STDMETHODCALLTYPE
SetMenuSB(HMENU hmenuShared
, HOLEMENU holemenuRes
, HWND hwndActiveObject
);
66 virtual HRESULT STDMETHODCALLTYPE
RemoveMenusSB(HMENU hmenuShared
);
67 virtual HRESULT STDMETHODCALLTYPE
SetStatusTextSB(LPCOLESTR pszStatusText
);
68 virtual HRESULT STDMETHODCALLTYPE
EnableModelessSB(BOOL fEnable
);
69 virtual HRESULT STDMETHODCALLTYPE
TranslateAcceleratorSB(MSG
*pmsg
, WORD wID
);
70 virtual HRESULT STDMETHODCALLTYPE
BrowseObject(LPCITEMIDLIST pidl
, UINT wFlags
);
71 virtual HRESULT STDMETHODCALLTYPE
GetViewStateStream(DWORD grfMode
, IStream
**ppStrm
);
72 virtual HRESULT STDMETHODCALLTYPE
GetControlWindow(UINT id
, HWND
*lphwnd
);
73 virtual HRESULT STDMETHODCALLTYPE
SendControlMsg(UINT id
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*pret
);
74 virtual HRESULT STDMETHODCALLTYPE
QueryActiveShellView(struct IShellView
**ppshv
);
75 virtual HRESULT STDMETHODCALLTYPE
OnViewWindowActive(struct IShellView
*ppshv
);
76 virtual HRESULT STDMETHODCALLTYPE
SetToolbarItems(LPTBBUTTON lpButtons
, UINT nButtons
, UINT uFlags
);
78 // *** ICommDlgBrowser methods ***
79 virtual HRESULT STDMETHODCALLTYPE
OnDefaultCommand(struct IShellView
*ppshv
);
80 virtual HRESULT STDMETHODCALLTYPE
OnStateChange(struct IShellView
*ppshv
, ULONG uChange
);
81 virtual HRESULT STDMETHODCALLTYPE
IncludeObject(struct IShellView
*ppshv
, LPCITEMIDLIST pidl
);
83 // *** IServiceProvider methods ***
84 virtual HRESULT STDMETHODCALLTYPE
QueryService(REFGUID guidService
, REFIID riid
, void **ppvObject
);
86 BEGIN_COM_MAP(CDesktopBrowser
)
87 COM_INTERFACE_ENTRY_IID(IID_IOleWindow
, IOleWindow
)
88 COM_INTERFACE_ENTRY_IID(IID_IShellBrowser
, IShellBrowser
)
89 COM_INTERFACE_ENTRY_IID(IID_ICommDlgBrowser
, ICommDlgBrowser
)
90 COM_INTERFACE_ENTRY_IID(IID_IServiceProvider
, IServiceProvider
)
94 CDesktopBrowser::CDesktopBrowser()
99 hWndDesktopListView
= NULL
;
100 DefaultShellBrowser
= NULL
;
101 pidlDesktopDirectory
= NULL
;
105 CDesktopBrowser::~CDesktopBrowser()
107 if (DesktopView
.p
!= NULL
)
109 if (hWndShellView
!= NULL
)
110 DesktopView
->DestroyViewWindow();
112 hWndShellView
= NULL
;
113 hWndDesktopListView
= NULL
;
116 if (pidlDesktopDirectory
!= NULL
)
118 ILFree(pidlDesktopDirectory
);
119 pidlDesktopDirectory
= NULL
;
122 if (pidlDesktop
!= NULL
)
129 HRESULT
CDesktopBrowser::Initialize(HWND hWndx
, IShellDesktopTray
*ShellDeskx
)
131 CComPtr
<IShellFolder
> psfDesktopFolder
;
136 ShellDesk
= ShellDeskx
;
139 pidlDesktopDirectory
= SHCloneSpecialIDList(hWnd
, CSIDL_DESKTOPDIRECTORY
, FALSE
);
140 hRet
= SHGetSpecialFolderLocation(hWnd
, CSIDL_DESKTOP
, &pidlDesktop
);
144 hRet
= SHGetDesktopFolder(&psfDesktopFolder
);
148 ZeroMemory(&csfv
, sizeof(csfv
));
149 csfv
.cbSize
= sizeof(csfv
);
150 csfv
.pshf
= psfDesktopFolder
;
151 csfv
.psvOuter
= NULL
;
153 hRet
= SHCreateShellFolderViewEx(&csfv
, &DesktopView
);
158 static CDesktopBrowser
*SHDESK_Create(HWND hWnd
, LPCREATESTRUCT lpCreateStruct
)
160 IShellDesktopTray
*ShellDesk
;
161 CComObject
<CDesktopBrowser
> *pThis
;
164 ShellDesk
= static_cast<IShellDesktopTray
*>(lpCreateStruct
->lpCreateParams
);
165 if (ShellDesk
== NULL
)
167 WARN("No IShellDesk interface provided!");
171 pThis
= new CComObject
<CDesktopBrowser
>;
176 hRet
= pThis
->Initialize(hWnd
, ShellDesk
);
186 HWND
CDesktopBrowser::FindDesktopListView()
188 return FindWindowExW(hWndShellView
, NULL
, WC_LISTVIEW
, NULL
);
191 BOOL
CDesktopBrowser::CreateDeskWnd()
197 if (!GetClientRect(hWnd
, &rcClient
))
202 fs
.ViewMode
= FVM_ICON
;
203 fs
.fFlags
= FWF_DESKTOP
| FWF_NOCLIENTEDGE
| FWF_NOSCROLL
| FWF_TRANSPARENT
;
204 hRet
= DesktopView
->CreateViewWindow(NULL
, &fs
, static_cast<IShellBrowser
*>(this), &rcClient
, &hWndShellView
);
205 if (!SUCCEEDED(hRet
))
208 SetShellWindowEx(hWnd
, FindDesktopListView());
211 /* A windows 8 specific hack */
212 ::ShowWindow(hWndShellView
, SW_SHOW
);
213 ::ShowWindow(FindDesktopListView(), SW_SHOW
);
219 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::GetWindow(HWND
*phwnd
)
231 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::ContextSensitiveHelp(BOOL fEnterMode
)
236 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::InsertMenusSB(HMENU hmenuShared
, LPOLEMENUGROUPWIDTHS lpMenuWidths
)
241 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::SetMenuSB(HMENU hmenuShared
, HOLEMENU holemenuRes
, HWND hwndActiveObject
)
246 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::RemoveMenusSB(HMENU hmenuShared
)
251 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::SetStatusTextSB(LPCOLESTR lpszStatusText
)
256 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::EnableModelessSB(BOOL fEnable
)
261 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::TranslateAcceleratorSB(LPMSG lpmsg
, WORD wID
)
266 typedef HRESULT(WINAPI
*SH_OPEN_NEW_FRAME
)(LPITEMIDLIST pidl
, IUnknown
*paramC
, long param10
, long param14
);
268 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::BrowseObject(LPCITEMIDLIST pidl
, UINT wFlags
)
270 /* FIXME: Implement executing filebrowser.exe and somehow pass the pidl to it */
272 /* Returning failure here will make windows 7 and 8 to use the default file browser */
276 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::GetViewStateStream(DWORD grfMode
, IStream
**ppStrm
)
281 HWND
CDesktopBrowser::DesktopGetWindowControl(IN UINT id
)
297 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::GetControlWindow(UINT id
, HWND
*lphwnd
)
301 hWnd
= DesktopGetWindowControl(id
);
312 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::SendControlMsg(UINT id
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*pret
)
319 hWnd
= DesktopGetWindowControl(id
);
322 *pret
= SendMessageW(hWnd
, uMsg
, wParam
, lParam
);
329 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::QueryActiveShellView(IShellView
**ppshv
)
331 *ppshv
= DesktopView
;
332 if (DesktopView
!= NULL
)
333 DesktopView
->AddRef();
338 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::OnViewWindowActive(IShellView
*ppshv
)
343 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::SetToolbarItems(LPTBBUTTON lpButtons
, UINT nButtons
, UINT uFlags
)
348 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::OnDefaultCommand(IShellView
*ppshv
)
353 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::OnStateChange(IShellView
*ppshv
, ULONG uChange
)
358 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::IncludeObject(IShellView
*ppshv
, LPCITEMIDLIST pidl
)
363 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::QueryService(REFGUID guidService
, REFIID riid
, PVOID
*ppv
)
365 /* FIXME - handle guidService */
366 return QueryInterface(riid
, ppv
);
369 BOOL
CDesktopBrowser::MessageLoop()
374 while ((bRet
= GetMessageW(&Msg
, NULL
, 0, 0)) != 0)
378 TranslateMessage(&Msg
);
379 DispatchMessageW(&Msg
);
386 LRESULT CALLBACK
CDesktopBrowser::ProgmanWindowProc(IN HWND hwnd
, IN UINT uMsg
, IN WPARAM wParam
, IN LPARAM lParam
)
388 CDesktopBrowser
*pThis
= NULL
;
391 if (uMsg
!= WM_NCCREATE
)
393 pThis
= reinterpret_cast<CDesktopBrowser
*>(GetWindowLongPtrW(hwnd
, 0));
398 if (pThis
!= NULL
|| uMsg
== WM_NCCREATE
)
403 return (LRESULT
) PaintDesktop(reinterpret_cast<HDC
>(wParam
));
405 case WM_GETISHELLBROWSER
:
406 Ret
= reinterpret_cast<LRESULT
>(static_cast<IShellBrowser
*>(pThis
));
410 if (wParam
== SIZE_MINIMIZED
)
412 /* Hey, we're the desktop!!! */
419 /* FIXME: Update work area */
423 rcDesktop
.left
= GetSystemMetrics(SM_XVIRTUALSCREEN
);
424 rcDesktop
.top
= GetSystemMetrics(SM_YVIRTUALSCREEN
);
425 rcDesktop
.right
= GetSystemMetrics(SM_CXVIRTUALSCREEN
);
426 rcDesktop
.bottom
= GetSystemMetrics(SM_CYVIRTUALSCREEN
);
431 case WM_SYSCOLORCHANGE
:
432 case WM_SETTINGCHANGE
:
434 if (uMsg
== WM_SYSCOLORCHANGE
|| wParam
== SPI_SETDESKWALLPAPER
|| wParam
== 0)
436 if (pThis
->hWndShellView
!= NULL
)
438 /* Forward the message */
439 SendMessageW(pThis
->hWndShellView
,
450 pThis
->ShellDesk
->RegisterDesktopWindow(pThis
->hWnd
);
452 if (!pThis
->CreateDeskWnd())
453 WARN("Could not create the desktop view control!\n");
459 LPCREATESTRUCT CreateStruct
= reinterpret_cast<LPCREATESTRUCT
>(lParam
);
460 pThis
= SHDESK_Create(hwnd
, CreateStruct
);
463 WARN("Failed to create desktop structure\n");
467 SetWindowLongPtrW(hwnd
,
469 reinterpret_cast<LONG_PTR
>(pThis
));
482 Ret
= DefWindowProcW(hwnd
, uMsg
, wParam
, lParam
);
491 RegisterProgmanWindowClass(VOID
)
495 wcProgman
.style
= CS_DBLCLKS
;
496 wcProgman
.lpfnWndProc
= CDesktopBrowser::ProgmanWindowProc
;
497 wcProgman
.cbClsExtra
= 0;
498 wcProgman
.cbWndExtra
= sizeof(CDesktopBrowser
*);
499 wcProgman
.hInstance
= shell32_hInstance
;
500 wcProgman
.hIcon
= NULL
;
501 wcProgman
.hCursor
= LoadCursorW(NULL
, IDC_ARROW
);
502 wcProgman
.hbrBackground
= (HBRUSH
) (COLOR_BACKGROUND
+ 1);
503 wcProgman
.lpszMenuName
= NULL
;
504 wcProgman
.lpszClassName
= szProgmanClassName
;
506 return RegisterClassW(&wcProgman
) != 0;
510 /*************************************************************************
511 * SHCreateDesktop [SHELL32.200]
514 HANDLE WINAPI
SHCreateDesktop(IShellDesktopTray
*ShellDesk
)
519 if (ShellDesk
== NULL
)
521 SetLastError(ERROR_INVALID_PARAMETER
);
525 if (RegisterProgmanWindowClass() == 0)
527 WARN("Failed to register the Progman window class!\n");
531 rcDesk
.left
= GetSystemMetrics(SM_XVIRTUALSCREEN
);
532 rcDesk
.top
= GetSystemMetrics(SM_YVIRTUALSCREEN
);
533 rcDesk
.right
= rcDesk
.left
+ GetSystemMetrics(SM_CXVIRTUALSCREEN
);
534 rcDesk
.bottom
= rcDesk
.top
+ GetSystemMetrics(SM_CYVIRTUALSCREEN
);
536 if (IsRectEmpty(&rcDesk
))
538 rcDesk
.left
= rcDesk
.top
= 0;
539 rcDesk
.right
= GetSystemMetrics(SM_CXSCREEN
);
540 rcDesk
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
543 hWndDesk
= CreateWindowExW(WS_EX_TOOLWINDOW
, szProgmanClassName
, szProgmanWindowName
,
544 WS_POPUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
,
545 rcDesk
.left
, rcDesk
.top
, rcDesk
.right
, rcDesk
.bottom
,
546 NULL
, NULL
, shell32_hInstance
, reinterpret_cast<LPVOID
>(ShellDesk
));
547 if (hWndDesk
!= NULL
)
548 return (HANDLE
) GetWindowLongPtrW(hWndDesk
, 0);
553 /*************************************************************************
554 * SHCreateDesktop [SHELL32.201]
557 BOOL WINAPI
SHDesktopMessageLoop(HANDLE hDesktop
)
559 CDesktopBrowser
*Desk
= reinterpret_cast<CDesktopBrowser
*>(hDesktop
);
561 if (Desk
== NULL
|| Desk
->Tag
!= SHDESK_TAG
)
563 SetLastError(ERROR_INVALID_PARAMETER
);
567 return Desk
->MessageLoop();