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
21 #include "shelldesktop.h"
23 WINE_DEFAULT_DEBUG_CHANNEL(desktop
);
25 #define SHDESK_TAG 'KSED'
27 static const WCHAR szProgmanClassName
[] = L
"Progman";
28 static const WCHAR szProgmanWindowName
[] = L
"Program Manager";
30 class CDesktopBrowser
:
31 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
33 public ICommDlgBrowser
,
34 public IServiceProvider
42 HWND hWndDesktopListView
; // FIXME: Unused
43 CComPtr
<IShellDesktopTray
> ShellDesk
;
44 CComPtr
<IShellView
> DesktopView
;
45 CComPtr
<IShellBrowser
> DefaultShellBrowser
;
46 LPITEMIDLIST pidlDesktopDirectory
;
47 LPITEMIDLIST pidlDesktop
;
49 LRESULT
_NotifyTray(UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
54 HRESULT
Initialize(HWND hWndx
, IShellDesktopTray
*ShellDeskx
);
55 HWND
FindDesktopListView();
57 HWND
DesktopGetWindowControl(IN UINT id
);
58 LRESULT
OnCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
59 static LRESULT CALLBACK
ProgmanWindowProc(IN HWND hwnd
, IN UINT uMsg
, IN WPARAM wParam
, IN LPARAM lParam
);
62 // *** IOleWindow methods ***
63 virtual HRESULT STDMETHODCALLTYPE
GetWindow(HWND
*lphwnd
);
64 virtual HRESULT STDMETHODCALLTYPE
ContextSensitiveHelp(BOOL fEnterMode
);
66 // *** IShellBrowser methods ***
67 virtual HRESULT STDMETHODCALLTYPE
InsertMenusSB(HMENU hmenuShared
, LPOLEMENUGROUPWIDTHS lpMenuWidths
);
68 virtual HRESULT STDMETHODCALLTYPE
SetMenuSB(HMENU hmenuShared
, HOLEMENU holemenuRes
, HWND hwndActiveObject
);
69 virtual HRESULT STDMETHODCALLTYPE
RemoveMenusSB(HMENU hmenuShared
);
70 virtual HRESULT STDMETHODCALLTYPE
SetStatusTextSB(LPCOLESTR pszStatusText
);
71 virtual HRESULT STDMETHODCALLTYPE
EnableModelessSB(BOOL fEnable
);
72 virtual HRESULT STDMETHODCALLTYPE
TranslateAcceleratorSB(MSG
*pmsg
, WORD wID
);
73 virtual HRESULT STDMETHODCALLTYPE
BrowseObject(LPCITEMIDLIST pidl
, UINT wFlags
);
74 virtual HRESULT STDMETHODCALLTYPE
GetViewStateStream(DWORD grfMode
, IStream
**ppStrm
);
75 virtual HRESULT STDMETHODCALLTYPE
GetControlWindow(UINT id
, HWND
*lphwnd
);
76 virtual HRESULT STDMETHODCALLTYPE
SendControlMsg(UINT id
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*pret
);
77 virtual HRESULT STDMETHODCALLTYPE
QueryActiveShellView(struct IShellView
**ppshv
);
78 virtual HRESULT STDMETHODCALLTYPE
OnViewWindowActive(struct IShellView
*ppshv
);
79 virtual HRESULT STDMETHODCALLTYPE
SetToolbarItems(LPTBBUTTON lpButtons
, UINT nButtons
, UINT uFlags
);
81 // *** ICommDlgBrowser methods ***
82 virtual HRESULT STDMETHODCALLTYPE
OnDefaultCommand (struct IShellView
*ppshv
);
83 virtual HRESULT STDMETHODCALLTYPE
OnStateChange (struct IShellView
*ppshv
, ULONG uChange
);
84 virtual HRESULT STDMETHODCALLTYPE
IncludeObject (struct IShellView
*ppshv
, LPCITEMIDLIST pidl
);
86 // *** IServiceProvider methods ***
87 virtual HRESULT STDMETHODCALLTYPE
QueryService(REFGUID guidService
, REFIID riid
, void **ppvObject
);
89 BEGIN_COM_MAP(CDesktopBrowser
)
90 COM_INTERFACE_ENTRY_IID(IID_IOleWindow
, IOleWindow
)
91 COM_INTERFACE_ENTRY_IID(IID_IShellBrowser
, IShellBrowser
)
92 COM_INTERFACE_ENTRY_IID(IID_ICommDlgBrowser
, ICommDlgBrowser
)
93 COM_INTERFACE_ENTRY_IID(IID_IServiceProvider
, IServiceProvider
)
97 CDesktopBrowser::CDesktopBrowser()
101 hWndShellView
= NULL
;
102 hWndDesktopListView
= NULL
;
103 DefaultShellBrowser
= NULL
;
104 pidlDesktopDirectory
= NULL
;
108 CDesktopBrowser::~CDesktopBrowser()
110 if (DesktopView
.p
!= NULL
)
112 if (hWndShellView
!= NULL
)
113 DesktopView
->DestroyViewWindow();
115 hWndShellView
= NULL
;
116 hWndDesktopListView
= NULL
;
119 if (pidlDesktopDirectory
!= NULL
)
121 ILFree(pidlDesktopDirectory
);
122 pidlDesktopDirectory
= NULL
;
125 if (pidlDesktop
!= NULL
)
132 HRESULT
CDesktopBrowser::Initialize(HWND hWndx
, IShellDesktopTray
*ShellDeskx
)
134 CComPtr
<IShellFolder
> psfDesktopFolder
;
139 ShellDesk
= ShellDeskx
;
142 pidlDesktopDirectory
= SHCloneSpecialIDList(hWnd
, CSIDL_DESKTOPDIRECTORY
, FALSE
);
143 hRet
= SHGetSpecialFolderLocation(hWnd
, CSIDL_DESKTOP
, &pidlDesktop
);
147 hRet
= SHGetDesktopFolder(&psfDesktopFolder
);
151 ZeroMemory(&csfv
, sizeof(csfv
));
152 csfv
.cbSize
= sizeof(csfv
);
153 csfv
.pshf
= psfDesktopFolder
;
154 csfv
.psvOuter
= NULL
;
156 hRet
= SHCreateShellFolderViewEx(&csfv
, &DesktopView
);
161 static CDesktopBrowser
*SHDESK_Create(HWND hWnd
, LPCREATESTRUCT lpCreateStruct
)
163 CComPtr
<IShellDesktopTray
> ShellDesk
;
164 CComObject
<CDesktopBrowser
> *pThis
;
167 ShellDesk
= (IShellDesktopTray
*)lpCreateStruct
->lpCreateParams
;
168 if (ShellDesk
== NULL
)
170 WARN("No IShellDesk interface provided!");
174 pThis
= new CComObject
<CDesktopBrowser
>;
179 hRet
= pThis
->Initialize(hWnd
, ShellDesk
);
189 HWND
CDesktopBrowser::FindDesktopListView()
191 return FindWindowExW(hWndShellView
, NULL
, WC_LISTVIEW
, NULL
);
194 BOOL
CDesktopBrowser::CreateDeskWnd()
200 // FIXME: Add support for multi-monitor?
201 SystemParametersInfoW(SPI_GETWORKAREA
,
204 // TODO: Call GetClientRect for the tray window and make small computation
205 // to be sure the tray window rect is removed from the work area!
210 /* Get client rect of the taskbar */
211 hRet
= ShellDesk
->GetTrayWindow(&hWndTray
);
213 GetClientRect(hWndTray
, &rcTray
);
216 fs
.ViewMode
= FVM_ICON
;
217 fs
.fFlags
= FWF_DESKTOP
| FWF_NOCLIENTEDGE
| FWF_NOSCROLL
| FWF_TRANSPARENT
;
218 hRet
= DesktopView
->CreateViewWindow(NULL
, &fs
, (IShellBrowser
*)this, &rcWorkArea
, &hWndShellView
);
219 if (!SUCCEEDED(hRet
))
222 SetShellWindowEx(hWnd
, FindDesktopListView());
225 /* A Windows8+ specific hack */
226 ::ShowWindow(hWndShellView
, SW_SHOW
);
227 ::ShowWindow(FindDesktopListView(), SW_SHOW
);
233 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::GetWindow(HWND
*phwnd
)
245 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::ContextSensitiveHelp(BOOL fEnterMode
)
250 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::InsertMenusSB(HMENU hmenuShared
, LPOLEMENUGROUPWIDTHS lpMenuWidths
)
255 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::SetMenuSB(HMENU hmenuShared
, HOLEMENU holemenuRes
, HWND hwndActiveObject
)
260 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::RemoveMenusSB(HMENU hmenuShared
)
265 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::SetStatusTextSB(LPCOLESTR lpszStatusText
)
270 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::EnableModelessSB(BOOL fEnable
)
275 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::TranslateAcceleratorSB(LPMSG lpmsg
, WORD wID
)
277 if (!::TranslateAcceleratorW(hWnd
, m_hAccel
, lpmsg
))
282 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::BrowseObject(LPCITEMIDLIST pidl
, UINT wFlags
)
285 * We should use IShellWindows interface here in order to attempt to
286 * find an open shell window that shows the requested pidl and activate it
289 return SHOpenNewFrame((LPITEMIDLIST
)pidl
, NULL
, 0, 0);
292 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::GetViewStateStream(DWORD grfMode
, IStream
**ppStrm
)
297 HWND
CDesktopBrowser::DesktopGetWindowControl(IN UINT id
)
313 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::GetControlWindow(UINT id
, HWND
*lphwnd
)
317 hWnd
= DesktopGetWindowControl(id
);
328 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::SendControlMsg(UINT id
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*pret
)
335 hWnd
= DesktopGetWindowControl(id
);
338 *pret
= SendMessageW(hWnd
,
348 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::QueryActiveShellView(IShellView
**ppshv
)
350 *ppshv
= DesktopView
;
351 if (DesktopView
!= NULL
)
352 DesktopView
->AddRef();
357 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::OnViewWindowActive(IShellView
*ppshv
)
362 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::SetToolbarItems(LPTBBUTTON lpButtons
, UINT nButtons
, UINT uFlags
)
367 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::OnDefaultCommand(IShellView
*ppshv
)
372 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::OnStateChange(IShellView
*ppshv
, ULONG uChange
)
377 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::IncludeObject(IShellView
*ppshv
, LPCITEMIDLIST pidl
)
382 HRESULT STDMETHODCALLTYPE
CDesktopBrowser::QueryService(REFGUID guidService
, REFIID riid
, PVOID
*ppv
)
384 /* FIXME - handle guidService */
385 return QueryInterface(riid
, ppv
);
388 BOOL
CDesktopBrowser::MessageLoop()
393 while ((bRet
= GetMessageW(&Msg
, NULL
, 0, 0)) != 0)
397 if (DesktopView
->TranslateAcceleratorW(&Msg
) != S_OK
)
399 TranslateMessage(&Msg
);
400 DispatchMessage(&Msg
);
408 LRESULT
CDesktopBrowser::_NotifyTray(UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
413 hRet
= ShellDesk
->GetTrayWindow(&hWndTray
);
416 PostMessageW(hWndTray
, uMsg
, wParam
, lParam
);
421 LRESULT
CDesktopBrowser::OnCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
423 switch (LOWORD(wParam
))
425 case FCIDM_DESKBROWSER_CLOSE
:
426 return _NotifyTray(TWM_DOEXITWINDOWS
, 0, 0);
427 case FCIDM_DESKBROWSER_FOCUS
:
428 if (GetKeyState(VK_SHIFT
))
429 return _NotifyTray(TWM_CYCLEFOCUS
, 1, 0xFFFFFFFF);
431 return _NotifyTray(TWM_CYCLEFOCUS
, 1, 1);
432 case FCIDM_DESKBROWSER_SEARCH
:
433 SHFindFiles(NULL
, NULL
);
435 case FCIDM_DESKBROWSER_REFRESH
:
442 LRESULT CALLBACK
CDesktopBrowser::ProgmanWindowProc(IN HWND hwnd
, IN UINT uMsg
, IN WPARAM wParam
, IN LPARAM lParam
)
444 CDesktopBrowser
*pThis
= NULL
;
447 if (uMsg
!= WM_NCCREATE
)
449 pThis
= reinterpret_cast<CDesktopBrowser
*>(GetWindowLongPtrW(hwnd
, 0));
454 if (pThis
!= NULL
|| uMsg
== WM_NCCREATE
)
459 return (LRESULT
)PaintDesktop((HDC
)wParam
);
461 case WM_GETISHELLBROWSER
:
462 Ret
= (LRESULT
)((IShellBrowser
*)pThis
);
467 if (wParam
== SIZE_MINIMIZED
)
469 /* Hey, we're the desktop!!! */
470 ShowWindow(hwnd
, SW_RESTORE
);
476 rcDesktop
.left
= GetSystemMetrics(SM_XVIRTUALSCREEN
);
477 rcDesktop
.top
= GetSystemMetrics(SM_YVIRTUALSCREEN
);
478 rcDesktop
.right
= GetSystemMetrics(SM_CXVIRTUALSCREEN
);
479 rcDesktop
.bottom
= GetSystemMetrics(SM_CYVIRTUALSCREEN
);
481 /* FIXME: Update work area */
482 DBG_UNREFERENCED_LOCAL_VARIABLE(rcDesktop
);
487 case WM_SYSCOLORCHANGE
:
488 case WM_SETTINGCHANGE
:
490 if (pThis
->hWndShellView
!= NULL
)
492 /* Forward the message */
493 SendMessageW(pThis
->hWndShellView
,
499 if (uMsg
== WM_SETTINGCHANGE
&& wParam
== SPI_SETWORKAREA
&&
500 pThis
->hWndShellView
!= NULL
)
504 // FIXME: Add support for multi-monitor!
505 // FIXME: Maybe merge with the code that retrieves the
506 // work area in CDesktopBrowser::CreateDeskWnd ?
507 SystemParametersInfoW(SPI_GETWORKAREA
,
510 SetWindowPos(pThis
->hWndShellView
, NULL
,
511 rcWorkArea
.left
, rcWorkArea
.top
,
512 rcWorkArea
.right
- rcWorkArea
.left
,
513 rcWorkArea
.bottom
- rcWorkArea
.top
,
514 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_NOOWNERZORDER
);
521 pThis
->ShellDesk
->RegisterDesktopWindow(pThis
->hWnd
);
523 if (!pThis
->CreateDeskWnd())
524 WARN("Could not create the desktop view control!\n");
526 pThis
->m_hAccel
= LoadAcceleratorsW(shell32_hInstance
, MAKEINTRESOURCEW(IDA_DESKBROWSER
));
533 LPCREATESTRUCT CreateStruct
= (LPCREATESTRUCT
)lParam
;
535 // FIXME: This is a "hack" to enforce the window title
536 // to be set to what it should be *on Windows* only.
537 // I don't understand why it is reset to NULL whereas
538 // the creation of the progman window proper is done in
539 // the standard way... (05/06/2016, hbelusca).
541 ::SetWindowTextW(hwnd
, CreateStruct
->lpszName
);
543 pThis
= SHDESK_Create(hwnd
, CreateStruct
);
546 WARN("Failed to create desktop structure\n");
550 SetWindowLongPtrW(hwnd
, 0, (LONG_PTR
)pThis
);
562 return pThis
->_NotifyTray(TWM_DOEXITWINDOWS
, 0, 0);
564 case WM_EXPLORER_OPEN_NEW_WINDOW
:
565 TRACE("Proxy Desktop message 1035 received.\n");
566 SHOnCWMCommandLine((HANDLE
)lParam
);
570 return pThis
->OnCommand(uMsg
, wParam
, lParam
);
573 SetFocus(pThis
->hWndShellView
);
578 Ret
= DefWindowProcW(hwnd
, uMsg
, wParam
, lParam
);
587 RegisterProgmanWindowClass(VOID
)
591 wcProgman
.style
= CS_DBLCLKS
;
592 wcProgman
.lpfnWndProc
= CDesktopBrowser::ProgmanWindowProc
;
593 wcProgman
.cbClsExtra
= 0;
594 wcProgman
.cbWndExtra
= sizeof(CDesktopBrowser
*);
595 wcProgman
.hInstance
= shell32_hInstance
;
596 wcProgman
.hIcon
= NULL
;
597 wcProgman
.hCursor
= LoadCursorW(NULL
, IDC_ARROW
);
598 wcProgman
.hbrBackground
= (HBRUSH
)(COLOR_DESKTOP
+ 1);
599 wcProgman
.lpszMenuName
= NULL
;
600 wcProgman
.lpszClassName
= szProgmanClassName
;
602 return RegisterClassW(&wcProgman
) != 0;
606 /*************************************************************************
607 * SHCreateDesktop [SHELL32.200]
610 HANDLE WINAPI
SHCreateDesktop(IShellDesktopTray
*ShellDesk
)
615 if (ShellDesk
== NULL
)
617 SetLastError(ERROR_INVALID_PARAMETER
);
621 if (RegisterProgmanWindowClass() == 0)
623 WARN("Failed to register the Progman window class!\n");
627 x
= GetSystemMetrics(SM_XVIRTUALSCREEN
);
628 y
= GetSystemMetrics(SM_YVIRTUALSCREEN
);
629 cx
= GetSystemMetrics(SM_CXVIRTUALSCREEN
);
630 cy
= GetSystemMetrics(SM_CYVIRTUALSCREEN
);
635 cx
= GetSystemMetrics(SM_CXSCREEN
);
636 cy
= GetSystemMetrics(SM_CYSCREEN
);
639 hWndDesk
= ::CreateWindowExW(WS_EX_TOOLWINDOW
, szProgmanClassName
, szProgmanWindowName
,
640 WS_POPUP
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
,
642 NULL
, NULL
, shell32_hInstance
, (LPVOID
)ShellDesk
);
644 if (hWndDesk
!= NULL
)
646 ::ShowWindow(hWndDesk
, SW_SHOW
);
647 ::UpdateWindow(hWndDesk
);
649 return (HANDLE
)GetWindowLongPtrW(hWndDesk
, 0);
655 /*************************************************************************
656 * SHCreateDesktop [SHELL32.201]
659 BOOL WINAPI
SHDesktopMessageLoop(HANDLE hDesktop
)
661 CDesktopBrowser
*Desk
= static_cast<CDesktopBrowser
*>(hDesktop
);
663 if (Desk
== NULL
|| Desk
->Tag
!= SHDESK_TAG
)
665 SetLastError(ERROR_INVALID_PARAMETER
);
669 return Desk
->MessageLoop();