[SHELL32]
[reactos.git] / reactos / dll / win32 / shell32 / shelldesktop / 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 "shelldesktop.h"
22
23 WINE_DEFAULT_DEBUG_CHANNEL(desktop);
24
25 #define SHDESK_TAG 'KSED'
26
27 static const WCHAR szProgmanClassName[] = L"Progman";
28 static const WCHAR szProgmanWindowName[] = L"Program Manager";
29
30 class CDesktopBrowser :
31 public CComObjectRootEx<CComMultiThreadModelNoCS>,
32 public IShellBrowser,
33 public ICommDlgBrowser,
34 public IServiceProvider
35 {
36 public:
37 DWORD Tag;
38 HACCEL m_hAccel;
39 private:
40 HWND hWnd;
41 HWND hWndShellView;
42 HWND hWndDesktopListView; // FIXME: Unused
43 CComPtr<IShellDesktopTray> ShellDesk;
44 CComPtr<IShellView> DesktopView;
45 CComPtr<IShellBrowser> DefaultShellBrowser;
46 LPITEMIDLIST pidlDesktopDirectory;
47 LPITEMIDLIST pidlDesktop;
48
49 LRESULT _NotifyTray(UINT uMsg, WPARAM wParam, LPARAM lParam);
50
51 public:
52 CDesktopBrowser();
53 ~CDesktopBrowser();
54 HRESULT Initialize(HWND hWndx, IShellDesktopTray *ShellDeskx);
55 HWND FindDesktopListView();
56 BOOL CreateDeskWnd();
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);
60 BOOL MessageLoop();
61
62 // *** IOleWindow methods ***
63 virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND *lphwnd);
64 virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode);
65
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);
80
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);
85
86 // *** IServiceProvider methods ***
87 virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService, REFIID riid, void **ppvObject);
88
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)
94 END_COM_MAP()
95 };
96
97 CDesktopBrowser::CDesktopBrowser()
98 {
99 Tag = SHDESK_TAG;
100 hWnd = NULL;
101 hWndShellView = NULL;
102 hWndDesktopListView = NULL;
103 DefaultShellBrowser = NULL;
104 pidlDesktopDirectory = NULL;
105 pidlDesktop = NULL;
106 }
107
108 CDesktopBrowser::~CDesktopBrowser()
109 {
110 if (DesktopView.p != NULL)
111 {
112 if (hWndShellView != NULL)
113 DesktopView->DestroyViewWindow();
114
115 hWndShellView = NULL;
116 hWndDesktopListView = NULL;
117 }
118
119 if (pidlDesktopDirectory != NULL)
120 {
121 ILFree(pidlDesktopDirectory);
122 pidlDesktopDirectory = NULL;
123 }
124
125 if (pidlDesktop != NULL)
126 {
127 ILFree(pidlDesktop);
128 pidlDesktop = NULL;
129 }
130 }
131
132 HRESULT CDesktopBrowser::Initialize(HWND hWndx, IShellDesktopTray *ShellDeskx)
133 {
134 CComPtr<IShellFolder> psfDesktopFolder;
135 CSFV csfv;
136 HRESULT hRet;
137
138 hWnd = hWndx;
139 ShellDesk = ShellDeskx;
140 ShellDesk->AddRef();
141
142 pidlDesktopDirectory = SHCloneSpecialIDList(hWnd, CSIDL_DESKTOPDIRECTORY, FALSE);
143 hRet = SHGetSpecialFolderLocation(hWnd, CSIDL_DESKTOP, &pidlDesktop);
144 if (FAILED(hRet))
145 return hRet;
146
147 hRet = SHGetDesktopFolder(&psfDesktopFolder);
148 if (FAILED(hRet))
149 return hRet;
150
151 ZeroMemory(&csfv, sizeof(csfv));
152 csfv.cbSize = sizeof(csfv);
153 csfv.pshf = psfDesktopFolder;
154 csfv.psvOuter = NULL;
155
156 hRet = SHCreateShellFolderViewEx(&csfv, &DesktopView);
157
158 return hRet;
159 }
160
161 static CDesktopBrowser *SHDESK_Create(HWND hWnd, LPCREATESTRUCT lpCreateStruct)
162 {
163 CComPtr<IShellDesktopTray> ShellDesk;
164 CComObject<CDesktopBrowser> *pThis;
165 HRESULT hRet;
166
167 ShellDesk = (IShellDesktopTray *)lpCreateStruct->lpCreateParams;
168 if (ShellDesk == NULL)
169 {
170 WARN("No IShellDesk interface provided!");
171 return NULL;
172 }
173
174 pThis = new CComObject<CDesktopBrowser>;
175 if (pThis == NULL)
176 return NULL;
177 pThis->AddRef();
178
179 hRet = pThis->Initialize(hWnd, ShellDesk);
180 if (FAILED(hRet))
181 {
182 pThis->Release();
183 return NULL;
184 }
185
186 return pThis;
187 }
188
189 HWND CDesktopBrowser::FindDesktopListView()
190 {
191 return FindWindowExW(hWndShellView, NULL, WC_LISTVIEW, NULL);
192 }
193
194 BOOL CDesktopBrowser::CreateDeskWnd()
195 {
196 FOLDERSETTINGS fs;
197 RECT rcWorkArea;
198 HRESULT hRet;
199
200 // FIXME: Add support for multi-monitor?
201 SystemParametersInfoW(SPI_GETWORKAREA,
202 0, &rcWorkArea, 0);
203
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!
206 #if 0
207 RECT rcTray;
208 HWND hWndTray;
209
210 /* Get client rect of the taskbar */
211 hRet = ShellDesk->GetTrayWindow(&hWndTray);
212 if (SUCCEEDED(hRet))
213 GetClientRect(hWndTray, &rcTray);
214 #endif
215
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))
220 return FALSE;
221
222 SetShellWindowEx(hWnd, FindDesktopListView());
223
224 #if 1
225 /* A Windows8+ specific hack */
226 ::ShowWindow(hWndShellView, SW_SHOW);
227 ::ShowWindow(FindDesktopListView(), SW_SHOW);
228 #endif
229
230 return TRUE;
231 }
232
233 HRESULT STDMETHODCALLTYPE CDesktopBrowser::GetWindow(HWND *phwnd)
234 {
235 if (hWnd != NULL)
236 {
237 *phwnd = hWnd;
238 return S_OK;
239 }
240
241 *phwnd = NULL;
242 return E_UNEXPECTED;
243 }
244
245 HRESULT STDMETHODCALLTYPE CDesktopBrowser::ContextSensitiveHelp(BOOL fEnterMode)
246 {
247 return E_NOTIMPL;
248 }
249
250 HRESULT STDMETHODCALLTYPE CDesktopBrowser::InsertMenusSB(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths)
251 {
252 return E_NOTIMPL;
253 }
254
255 HRESULT STDMETHODCALLTYPE CDesktopBrowser::SetMenuSB(HMENU hmenuShared, HOLEMENU holemenuRes, HWND hwndActiveObject)
256 {
257 return E_NOTIMPL;
258 }
259
260 HRESULT STDMETHODCALLTYPE CDesktopBrowser::RemoveMenusSB(HMENU hmenuShared)
261 {
262 return E_NOTIMPL;
263 }
264
265 HRESULT STDMETHODCALLTYPE CDesktopBrowser::SetStatusTextSB(LPCOLESTR lpszStatusText)
266 {
267 return E_NOTIMPL;
268 }
269
270 HRESULT STDMETHODCALLTYPE CDesktopBrowser::EnableModelessSB(BOOL fEnable)
271 {
272 return E_NOTIMPL;
273 }
274
275 HRESULT STDMETHODCALLTYPE CDesktopBrowser::TranslateAcceleratorSB(LPMSG lpmsg, WORD wID)
276 {
277 if (!::TranslateAcceleratorW(hWnd, m_hAccel, lpmsg))
278 return S_FALSE;
279 return S_OK;
280 }
281
282 HRESULT STDMETHODCALLTYPE CDesktopBrowser::BrowseObject(LPCITEMIDLIST pidl, UINT wFlags)
283 {
284 /*
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
287 */
288
289 return SHOpenNewFrame((LPITEMIDLIST)pidl, NULL, 0, 0);
290 }
291
292 HRESULT STDMETHODCALLTYPE CDesktopBrowser::GetViewStateStream(DWORD grfMode, IStream **ppStrm)
293 {
294 return E_NOTIMPL;
295 }
296
297 HWND CDesktopBrowser::DesktopGetWindowControl(IN UINT id)
298 {
299 switch (id)
300 {
301 case FCW_TOOLBAR:
302 case FCW_STATUS:
303 case FCW_TREE:
304 case FCW_PROGRESS:
305 return NULL;
306
307 default:
308 return NULL;
309 }
310
311 }
312
313 HRESULT STDMETHODCALLTYPE CDesktopBrowser::GetControlWindow(UINT id, HWND *lphwnd)
314 {
315 HWND hWnd;
316
317 hWnd = DesktopGetWindowControl(id);
318 if (hWnd != NULL)
319 {
320 *lphwnd = hWnd;
321 return S_OK;
322 }
323
324 *lphwnd = NULL;
325 return E_NOTIMPL;
326 }
327
328 HRESULT STDMETHODCALLTYPE CDesktopBrowser::SendControlMsg(UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pret)
329 {
330 HWND hWnd;
331
332 if (pret == NULL)
333 return E_POINTER;
334
335 hWnd = DesktopGetWindowControl(id);
336 if (hWnd != NULL)
337 {
338 *pret = SendMessageW(hWnd,
339 uMsg,
340 wParam,
341 lParam);
342 return S_OK;
343 }
344
345 return E_NOTIMPL;
346 }
347
348 HRESULT STDMETHODCALLTYPE CDesktopBrowser::QueryActiveShellView(IShellView **ppshv)
349 {
350 *ppshv = DesktopView;
351 if (DesktopView != NULL)
352 DesktopView->AddRef();
353
354 return S_OK;
355 }
356
357 HRESULT STDMETHODCALLTYPE CDesktopBrowser::OnViewWindowActive(IShellView *ppshv)
358 {
359 return E_NOTIMPL;
360 }
361
362 HRESULT STDMETHODCALLTYPE CDesktopBrowser::SetToolbarItems(LPTBBUTTON lpButtons, UINT nButtons, UINT uFlags)
363 {
364 return E_NOTIMPL;
365 }
366
367 HRESULT STDMETHODCALLTYPE CDesktopBrowser::OnDefaultCommand(IShellView *ppshv)
368 {
369 return E_NOTIMPL;
370 }
371
372 HRESULT STDMETHODCALLTYPE CDesktopBrowser::OnStateChange(IShellView *ppshv, ULONG uChange)
373 {
374 return S_OK;
375 }
376
377 HRESULT STDMETHODCALLTYPE CDesktopBrowser::IncludeObject(IShellView *ppshv, LPCITEMIDLIST pidl)
378 {
379 return S_OK;
380 }
381
382 HRESULT STDMETHODCALLTYPE CDesktopBrowser::QueryService(REFGUID guidService, REFIID riid, PVOID *ppv)
383 {
384 /* FIXME - handle guidService */
385 return QueryInterface(riid, ppv);
386 }
387
388 BOOL CDesktopBrowser::MessageLoop()
389 {
390 MSG Msg;
391 BOOL bRet;
392
393 while ((bRet = GetMessageW(&Msg, NULL, 0, 0)) != 0)
394 {
395 if (bRet != -1)
396 {
397 if (DesktopView->TranslateAcceleratorW(&Msg) != S_OK)
398 {
399 TranslateMessage(&Msg);
400 DispatchMessage(&Msg);
401 }
402 }
403 }
404
405 return TRUE;
406 }
407
408 LRESULT CDesktopBrowser::_NotifyTray(UINT uMsg, WPARAM wParam, LPARAM lParam)
409 {
410 HWND hWndTray;
411 HRESULT hRet;
412
413 hRet = ShellDesk->GetTrayWindow(&hWndTray);
414
415 if (SUCCEEDED(hRet))
416 PostMessageW(hWndTray, uMsg, wParam, lParam);
417
418 return 0;
419 }
420
421 LRESULT CDesktopBrowser::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam)
422 {
423 switch (LOWORD(wParam))
424 {
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);
430 else
431 return _NotifyTray(TWM_CYCLEFOCUS, 1, 1);
432 case FCIDM_DESKBROWSER_SEARCH:
433 SHFindFiles(NULL, NULL);
434 break;
435 case FCIDM_DESKBROWSER_REFRESH:
436 break;
437 }
438
439 return 0;
440 }
441
442 LRESULT CALLBACK CDesktopBrowser::ProgmanWindowProc(IN HWND hwnd, IN UINT uMsg, IN WPARAM wParam, IN LPARAM lParam)
443 {
444 CDesktopBrowser *pThis = NULL;
445 LRESULT Ret = FALSE;
446
447 if (uMsg != WM_NCCREATE)
448 {
449 pThis = reinterpret_cast<CDesktopBrowser *>(GetWindowLongPtrW(hwnd, 0));
450 if (pThis == NULL)
451 goto DefMsgHandler;
452 }
453
454 if (pThis != NULL || uMsg == WM_NCCREATE)
455 {
456 switch (uMsg)
457 {
458 case WM_ERASEBKGND:
459 return (LRESULT)PaintDesktop((HDC)wParam);
460
461 case WM_GETISHELLBROWSER:
462 Ret = (LRESULT)((IShellBrowser *)pThis);
463 break;
464
465 case WM_SIZE:
466 {
467 if (wParam == SIZE_MINIMIZED)
468 {
469 /* Hey, we're the desktop!!! */
470 ShowWindow(hwnd, SW_RESTORE);
471 }
472 else
473 {
474 RECT rcDesktop;
475
476 rcDesktop.left = GetSystemMetrics(SM_XVIRTUALSCREEN);
477 rcDesktop.top = GetSystemMetrics(SM_YVIRTUALSCREEN);
478 rcDesktop.right = GetSystemMetrics(SM_CXVIRTUALSCREEN);
479 rcDesktop.bottom = GetSystemMetrics(SM_CYVIRTUALSCREEN);
480
481 /* FIXME: Update work area */
482 DBG_UNREFERENCED_LOCAL_VARIABLE(rcDesktop);
483 }
484 break;
485 }
486
487 case WM_SYSCOLORCHANGE:
488 case WM_SETTINGCHANGE:
489 {
490 if (pThis->hWndShellView != NULL)
491 {
492 /* Forward the message */
493 SendMessageW(pThis->hWndShellView,
494 uMsg,
495 wParam,
496 lParam);
497 }
498
499 if (uMsg == WM_SETTINGCHANGE && wParam == SPI_SETWORKAREA &&
500 pThis->hWndShellView != NULL)
501 {
502 RECT rcWorkArea;
503
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,
508 0, &rcWorkArea, 0);
509
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);
515 }
516 break;
517 }
518
519 case WM_CREATE:
520 {
521 pThis->ShellDesk->RegisterDesktopWindow(pThis->hWnd);
522
523 if (!pThis->CreateDeskWnd())
524 WARN("Could not create the desktop view control!\n");
525
526 pThis->m_hAccel = LoadAcceleratorsW(shell32_hInstance, MAKEINTRESOURCEW(IDA_DESKBROWSER));
527
528 break;
529 }
530
531 case WM_NCCREATE:
532 {
533 LPCREATESTRUCT CreateStruct = (LPCREATESTRUCT)lParam;
534
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).
540 //
541 ::SetWindowTextW(hwnd, CreateStruct->lpszName);
542
543 pThis = SHDESK_Create(hwnd, CreateStruct);
544 if (pThis == NULL)
545 {
546 WARN("Failed to create desktop structure\n");
547 break;
548 }
549
550 SetWindowLongPtrW(hwnd, 0, (LONG_PTR)pThis);
551 Ret = TRUE;
552 break;
553 }
554
555 case WM_NCDESTROY:
556 {
557 pThis->Release();
558 break;
559 }
560
561 case WM_CLOSE:
562 return pThis->_NotifyTray(TWM_DOEXITWINDOWS, 0, 0);
563
564 case WM_EXPLORER_OPEN_NEW_WINDOW:
565 TRACE("Proxy Desktop message 1035 received.\n");
566 SHOnCWMCommandLine((HANDLE)lParam);
567 break;
568
569 case WM_COMMAND:
570 return pThis->OnCommand(uMsg, wParam, lParam);
571
572 case WM_SETFOCUS:
573 SetFocus(pThis->hWndShellView);
574 break;
575
576 default:
577 DefMsgHandler:
578 Ret = DefWindowProcW(hwnd, uMsg, wParam, lParam);
579 break;
580 }
581 }
582
583 return Ret;
584 }
585
586 static BOOL
587 RegisterProgmanWindowClass(VOID)
588 {
589 WNDCLASSW wcProgman;
590
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;
601
602 return RegisterClassW(&wcProgman) != 0;
603 }
604
605
606 /*************************************************************************
607 * SHCreateDesktop [SHELL32.200]
608 *
609 */
610 HANDLE WINAPI SHCreateDesktop(IShellDesktopTray *ShellDesk)
611 {
612 HWND hWndDesk;
613 int x, y, cx, cy;
614
615 if (ShellDesk == NULL)
616 {
617 SetLastError(ERROR_INVALID_PARAMETER);
618 return NULL;
619 }
620
621 if (RegisterProgmanWindowClass() == 0)
622 {
623 WARN("Failed to register the Progman window class!\n");
624 return NULL;
625 }
626
627 x = GetSystemMetrics(SM_XVIRTUALSCREEN);
628 y = GetSystemMetrics(SM_YVIRTUALSCREEN);
629 cx = GetSystemMetrics(SM_CXVIRTUALSCREEN);
630 cy = GetSystemMetrics(SM_CYVIRTUALSCREEN);
631
632 if (!cx || !cy)
633 {
634 x = y = 0;
635 cx = GetSystemMetrics(SM_CXSCREEN);
636 cy = GetSystemMetrics(SM_CYSCREEN);
637 }
638
639 hWndDesk = ::CreateWindowExW(WS_EX_TOOLWINDOW, szProgmanClassName, szProgmanWindowName,
640 WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
641 x, y, cx, cy,
642 NULL, NULL, shell32_hInstance, (LPVOID)ShellDesk);
643
644 if (hWndDesk != NULL)
645 {
646 ::ShowWindow(hWndDesk, SW_SHOW);
647 ::UpdateWindow(hWndDesk);
648
649 return (HANDLE)GetWindowLongPtrW(hWndDesk, 0);
650 }
651
652 return NULL;
653 }
654
655 /*************************************************************************
656 * SHCreateDesktop [SHELL32.201]
657 *
658 */
659 BOOL WINAPI SHDesktopMessageLoop(HANDLE hDesktop)
660 {
661 CDesktopBrowser *Desk = static_cast<CDesktopBrowser *>(hDesktop);
662
663 if (Desk == NULL || Desk->Tag != SHDESK_TAG)
664 {
665 SetLastError(ERROR_INVALID_PARAMETER);
666 return FALSE;
667 }
668
669 return Desk->MessageLoop();
670 }