* Addendum to r65483.
[reactos.git] / base / shell / rshell / CDesktopBrowser.cpp
1 /*
2 * Shell Desktop
3 *
4 * Copyright 2008 Thomas Bluemel
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #include "precomp.h"
22
23 WINE_DEFAULT_DEBUG_CHANNEL(desktop);
24
25 BOOL WINAPI SetShellWindowEx(HWND, HWND);
26
27 #define SHDESK_TAG 0x4b534544
28
29 static const WCHAR szProgmanClassName [] = L"Progman";
30 static const WCHAR szProgmanWindowName [] = L"Program Manager";
31
32 class CDesktopBrowser :
33 public CComObjectRootEx<CComMultiThreadModelNoCS>,
34 public IShellBrowser,
35 public ICommDlgBrowser,
36 public IServiceProvider
37 {
38 public:
39 DWORD Tag;
40 private:
41 HWND hWnd;
42 HWND hWndShellView;
43 HWND hWndDesktopListView;
44 CComPtr<IShellDesktopTray> ShellDesk;
45 CComPtr<IShellView> DesktopView;
46 IShellBrowser *DefaultShellBrowser;
47 LPITEMIDLIST pidlDesktopDirectory;
48 LPITEMIDLIST pidlDesktop;
49 public:
50 CDesktopBrowser();
51 ~CDesktopBrowser();
52 HRESULT Initialize(HWND hWndx, IShellDesktopTray *ShellDeskx);
53 HWND FindDesktopListView();
54 BOOL CreateDeskWnd();
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();
58
59 // *** IOleWindow methods ***
60 virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND *lphwnd);
61 virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode);
62
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);
77
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);
82
83 // *** IServiceProvider methods ***
84 virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService, REFIID riid, void **ppvObject);
85
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)
91 END_COM_MAP()
92 };
93
94 CDesktopBrowser::CDesktopBrowser()
95 {
96 Tag = SHDESK_TAG;
97 hWnd = NULL;
98 hWndShellView = NULL;
99 hWndDesktopListView = NULL;
100 DefaultShellBrowser = NULL;
101 pidlDesktopDirectory = NULL;
102 pidlDesktop = NULL;
103 }
104
105 CDesktopBrowser::~CDesktopBrowser()
106 {
107 if (DesktopView.p != NULL)
108 {
109 if (hWndShellView != NULL)
110 DesktopView->DestroyViewWindow();
111
112 hWndShellView = NULL;
113 hWndDesktopListView = NULL;
114 }
115
116 if (pidlDesktopDirectory != NULL)
117 {
118 ILFree(pidlDesktopDirectory);
119 pidlDesktopDirectory = NULL;
120 }
121
122 if (pidlDesktop != NULL)
123 {
124 ILFree(pidlDesktop);
125 pidlDesktop = NULL;
126 }
127 }
128
129 HRESULT CDesktopBrowser::Initialize(HWND hWndx, IShellDesktopTray *ShellDeskx)
130 {
131 CComPtr<IShellFolder> psfDesktopFolder;
132 CSFV csfv;
133 HRESULT hRet;
134
135 hWnd = hWndx;
136 ShellDesk = ShellDeskx;
137 ShellDesk->AddRef();
138
139 pidlDesktopDirectory = SHCloneSpecialIDList(hWnd, CSIDL_DESKTOPDIRECTORY, FALSE);
140 hRet = SHGetSpecialFolderLocation(hWnd, CSIDL_DESKTOP, &pidlDesktop);
141 if (FAILED(hRet))
142 return hRet;
143
144 hRet = SHGetDesktopFolder(&psfDesktopFolder);
145 if (FAILED(hRet))
146 return hRet;
147
148 ZeroMemory(&csfv, sizeof(csfv));
149 csfv.cbSize = sizeof(csfv);
150 csfv.pshf = psfDesktopFolder;
151 csfv.psvOuter = NULL;
152
153 hRet = SHCreateShellFolderViewEx(&csfv, &DesktopView);
154
155 return hRet;
156 }
157
158 static CDesktopBrowser *SHDESK_Create(HWND hWnd, LPCREATESTRUCT lpCreateStruct)
159 {
160 IShellDesktopTray *ShellDesk;
161 CComObject<CDesktopBrowser> *pThis;
162 HRESULT hRet;
163
164 ShellDesk = static_cast<IShellDesktopTray *>(lpCreateStruct->lpCreateParams);
165 if (ShellDesk == NULL)
166 {
167 WARN("No IShellDesk interface provided!");
168 return NULL;
169 }
170
171 pThis = new CComObject<CDesktopBrowser>;
172 if (pThis == NULL)
173 return NULL;
174 pThis->AddRef();
175
176 hRet = pThis->Initialize(hWnd, ShellDesk);
177 if (FAILED(hRet))
178 {
179 pThis->Release();
180 return NULL;
181 }
182
183 return pThis;
184 }
185
186 HWND CDesktopBrowser::FindDesktopListView()
187 {
188 return FindWindowExW(hWndShellView, NULL, WC_LISTVIEW, NULL);
189 }
190
191 BOOL CDesktopBrowser::CreateDeskWnd()
192 {
193 FOLDERSETTINGS fs;
194 RECT rcClient;
195 HRESULT hRet;
196
197 if (!GetClientRect(hWnd, &rcClient))
198 {
199 return FALSE;
200 }
201
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))
206 return FALSE;
207
208 SetShellWindowEx(hWnd, FindDesktopListView());
209
210 #if 1
211 /* A windows 8 specific hack */
212 ::ShowWindow(hWndShellView, SW_SHOW);
213 ::ShowWindow(FindDesktopListView(), SW_SHOW);
214 #endif
215
216 return TRUE;
217 }
218
219 HRESULT STDMETHODCALLTYPE CDesktopBrowser::GetWindow(HWND *phwnd)
220 {
221 if (hWnd != NULL)
222 {
223 *phwnd = hWnd;
224 return S_OK;
225 }
226
227 *phwnd = NULL;
228 return E_UNEXPECTED;
229 }
230
231 HRESULT STDMETHODCALLTYPE CDesktopBrowser::ContextSensitiveHelp(BOOL fEnterMode)
232 {
233 return E_NOTIMPL;
234 }
235
236 HRESULT STDMETHODCALLTYPE CDesktopBrowser::InsertMenusSB(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths)
237 {
238 return E_NOTIMPL;
239 }
240
241 HRESULT STDMETHODCALLTYPE CDesktopBrowser::SetMenuSB(HMENU hmenuShared, HOLEMENU holemenuRes, HWND hwndActiveObject)
242 {
243 return E_NOTIMPL;
244 }
245
246 HRESULT STDMETHODCALLTYPE CDesktopBrowser::RemoveMenusSB(HMENU hmenuShared)
247 {
248 return E_NOTIMPL;
249 }
250
251 HRESULT STDMETHODCALLTYPE CDesktopBrowser::SetStatusTextSB(LPCOLESTR lpszStatusText)
252 {
253 return E_NOTIMPL;
254 }
255
256 HRESULT STDMETHODCALLTYPE CDesktopBrowser::EnableModelessSB(BOOL fEnable)
257 {
258 return E_NOTIMPL;
259 }
260
261 HRESULT STDMETHODCALLTYPE CDesktopBrowser::TranslateAcceleratorSB(LPMSG lpmsg, WORD wID)
262 {
263 return S_FALSE;
264 }
265
266 typedef HRESULT(WINAPI *SH_OPEN_NEW_FRAME)(LPITEMIDLIST pidl, IUnknown *paramC, long param10, long param14);
267
268 HRESULT STDMETHODCALLTYPE CDesktopBrowser::BrowseObject(LPCITEMIDLIST pidl, UINT wFlags)
269 {
270 /* FIXME: Implement executing filebrowser.exe and somehow pass the pidl to it */
271
272 /* Returning failure here will make windows 7 and 8 to use the default file browser */
273 return E_FAIL;
274 }
275
276 HRESULT STDMETHODCALLTYPE CDesktopBrowser::GetViewStateStream(DWORD grfMode, IStream **ppStrm)
277 {
278 return E_NOTIMPL;
279 }
280
281 HWND CDesktopBrowser::DesktopGetWindowControl(IN UINT id)
282 {
283 switch (id)
284 {
285 case FCW_TOOLBAR:
286 case FCW_STATUS:
287 case FCW_TREE:
288 case FCW_PROGRESS:
289 return NULL;
290
291 default:
292 return NULL;
293 }
294
295 }
296
297 HRESULT STDMETHODCALLTYPE CDesktopBrowser::GetControlWindow(UINT id, HWND *lphwnd)
298 {
299 HWND hWnd;
300
301 hWnd = DesktopGetWindowControl(id);
302 if (hWnd != NULL)
303 {
304 *lphwnd = hWnd;
305 return S_OK;
306 }
307
308 *lphwnd = NULL;
309 return E_NOTIMPL;
310 }
311
312 HRESULT STDMETHODCALLTYPE CDesktopBrowser::SendControlMsg(UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pret)
313 {
314 HWND hWnd;
315
316 if (pret == NULL)
317 return E_POINTER;
318
319 hWnd = DesktopGetWindowControl(id);
320 if (hWnd != NULL)
321 {
322 *pret = SendMessageW(hWnd, uMsg, wParam, lParam);
323 return S_OK;
324 }
325
326 return E_NOTIMPL;
327 }
328
329 HRESULT STDMETHODCALLTYPE CDesktopBrowser::QueryActiveShellView(IShellView **ppshv)
330 {
331 *ppshv = DesktopView;
332 if (DesktopView != NULL)
333 DesktopView->AddRef();
334
335 return S_OK;
336 }
337
338 HRESULT STDMETHODCALLTYPE CDesktopBrowser::OnViewWindowActive(IShellView *ppshv)
339 {
340 return E_NOTIMPL;
341 }
342
343 HRESULT STDMETHODCALLTYPE CDesktopBrowser::SetToolbarItems(LPTBBUTTON lpButtons, UINT nButtons, UINT uFlags)
344 {
345 return E_NOTIMPL;
346 }
347
348 HRESULT STDMETHODCALLTYPE CDesktopBrowser::OnDefaultCommand(IShellView *ppshv)
349 {
350 return E_NOTIMPL;
351 }
352
353 HRESULT STDMETHODCALLTYPE CDesktopBrowser::OnStateChange(IShellView *ppshv, ULONG uChange)
354 {
355 return S_OK;
356 }
357
358 HRESULT STDMETHODCALLTYPE CDesktopBrowser::IncludeObject(IShellView *ppshv, LPCITEMIDLIST pidl)
359 {
360 return S_OK;
361 }
362
363 HRESULT STDMETHODCALLTYPE CDesktopBrowser::QueryService(REFGUID guidService, REFIID riid, PVOID *ppv)
364 {
365 /* FIXME - handle guidService */
366 return QueryInterface(riid, ppv);
367 }
368
369 BOOL CDesktopBrowser::MessageLoop()
370 {
371 MSG Msg;
372 BOOL bRet;
373
374 while ((bRet = GetMessageW(&Msg, NULL, 0, 0)) != 0)
375 {
376 if (bRet != -1)
377 {
378 TranslateMessage(&Msg);
379 DispatchMessageW(&Msg);
380 }
381 }
382
383 return TRUE;
384 }
385
386 LRESULT CALLBACK CDesktopBrowser::ProgmanWindowProc(IN HWND hwnd, IN UINT uMsg, IN WPARAM wParam, IN LPARAM lParam)
387 {
388 CDesktopBrowser *pThis = NULL;
389 LRESULT Ret = FALSE;
390
391 if (uMsg != WM_NCCREATE)
392 {
393 pThis = reinterpret_cast<CDesktopBrowser*>(GetWindowLongPtrW(hwnd, 0));
394 if (pThis == NULL)
395 goto DefMsgHandler;
396 }
397
398 if (pThis != NULL || uMsg == WM_NCCREATE)
399 {
400 switch (uMsg)
401 {
402 case WM_ERASEBKGND:
403 return (LRESULT) PaintDesktop(reinterpret_cast<HDC>(wParam));
404
405 case WM_GETISHELLBROWSER:
406 Ret = reinterpret_cast<LRESULT>(static_cast<IShellBrowser *>(pThis));
407 break;
408
409 case WM_SIZE:
410 if (wParam == SIZE_MINIMIZED)
411 {
412 /* Hey, we're the desktop!!! */
413 ShowWindow(hwnd,
414 SW_RESTORE);
415 }
416 else
417 {
418
419 /* FIXME: Update work area */
420 #if 0
421 RECT rcDesktop;
422
423 rcDesktop.left = GetSystemMetrics(SM_XVIRTUALSCREEN);
424 rcDesktop.top = GetSystemMetrics(SM_YVIRTUALSCREEN);
425 rcDesktop.right = GetSystemMetrics(SM_CXVIRTUALSCREEN);
426 rcDesktop.bottom = GetSystemMetrics(SM_CYVIRTUALSCREEN);
427 #endif
428 }
429 break;
430
431 case WM_SYSCOLORCHANGE:
432 case WM_SETTINGCHANGE:
433 {
434 if (uMsg == WM_SYSCOLORCHANGE || wParam == SPI_SETDESKWALLPAPER || wParam == 0)
435 {
436 if (pThis->hWndShellView != NULL)
437 {
438 /* Forward the message */
439 SendMessageW(pThis->hWndShellView,
440 uMsg,
441 wParam,
442 lParam);
443 }
444 }
445 break;
446 }
447
448 case WM_CREATE:
449 {
450 pThis->ShellDesk->RegisterDesktopWindow(pThis->hWnd);
451
452 if (!pThis->CreateDeskWnd())
453 WARN("Could not create the desktop view control!\n");
454 break;
455 }
456
457 case WM_NCCREATE:
458 {
459 LPCREATESTRUCT CreateStruct = reinterpret_cast<LPCREATESTRUCT>(lParam);
460 pThis = SHDESK_Create(hwnd, CreateStruct);
461 if (pThis == NULL)
462 {
463 WARN("Failed to create desktop structure\n");
464 break;
465 }
466
467 SetWindowLongPtrW(hwnd,
468 0,
469 reinterpret_cast<LONG_PTR>(pThis));
470 Ret = TRUE;
471 break;
472 }
473
474 case WM_NCDESTROY:
475 {
476 pThis->Release();
477 break;
478 }
479
480 default:
481 DefMsgHandler :
482 Ret = DefWindowProcW(hwnd, uMsg, wParam, lParam);
483 break;
484 }
485 }
486
487 return Ret;
488 }
489
490 static BOOL
491 RegisterProgmanWindowClass(VOID)
492 {
493 WNDCLASSW wcProgman;
494
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;
505
506 return RegisterClassW(&wcProgman) != 0;
507 }
508
509
510 /*************************************************************************
511 * SHCreateDesktop [SHELL32.200]
512 *
513 */
514 HANDLE WINAPI SHCreateDesktop(IShellDesktopTray *ShellDesk)
515 {
516 HWND hWndDesk;
517 RECT rcDesk;
518
519 if (ShellDesk == NULL)
520 {
521 SetLastError(ERROR_INVALID_PARAMETER);
522 return NULL;
523 }
524
525 if (RegisterProgmanWindowClass() == 0)
526 {
527 WARN("Failed to register the Progman window class!\n");
528 return NULL;
529 }
530
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);
535
536 if (IsRectEmpty(&rcDesk))
537 {
538 rcDesk.left = rcDesk.top = 0;
539 rcDesk.right = GetSystemMetrics(SM_CXSCREEN);
540 rcDesk.bottom = GetSystemMetrics(SM_CYSCREEN);
541 }
542
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);
549
550 return NULL;
551 }
552
553 /*************************************************************************
554 * SHCreateDesktop [SHELL32.201]
555 *
556 */
557 BOOL WINAPI SHDesktopMessageLoop(HANDLE hDesktop)
558 {
559 CDesktopBrowser *Desk = reinterpret_cast<CDesktopBrowser *>(hDesktop);
560
561 if (Desk == NULL || Desk->Tag != SHDESK_TAG)
562 {
563 SetLastError(ERROR_INVALID_PARAMETER);
564 return FALSE;
565 }
566
567 return Desk->MessageLoop();
568 }