[SHELL32]
[reactos.git] / reactos / dll / win32 / shell32 / desktop.c
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[] = {'P','r','o','g','m','a','n'};
30 static const WCHAR szProgmanWindowName[] = {
31 'P','r','o','g','r','a','m',' ','M','a','n','a','g','e','r'
32 };
33
34 static const IShellBrowserVtbl SHDESK_Vtbl;
35 static const ICommDlgBrowserVtbl SHDESK_ICommDlgBrowser_Vtbl;
36 static const IServiceProviderVtbl SHDESK_IServiceProvider_Vtbl;
37
38 typedef struct _SHDESK
39 {
40 DWORD Tag;
41 const IShellBrowserVtbl *lpVtbl;
42 const ICommDlgBrowserVtbl *lpVtblCommDlgBrowser;
43 const IServiceProviderVtbl *lpVtblServiceProvider;
44 LONG Ref;
45 HWND hWnd;
46 HWND hWndShellView;
47 HWND hWndDesktopListView;
48 IShellDesktopTray *ShellDesk;
49 IShellView *DesktopView;
50 IShellBrowser *DefaultShellBrowser;
51 LPITEMIDLIST pidlDesktopDirectory;
52 LPITEMIDLIST pidlDesktop;
53 } SHDESK, *PSHDESK;
54
55 static IUnknown *
56 IUnknown_from_impl(SHDESK *This)
57 {
58 return (IUnknown *)&This->lpVtbl;
59 }
60
61 static IShellBrowser *
62 IShellBrowser_from_impl(SHDESK *This)
63 {
64 return (IShellBrowser *)&This->lpVtbl;
65 }
66
67 static IOleWindow *
68 IOleWindow_from_impl(SHDESK *This)
69 {
70 return (IOleWindow *)&This->lpVtbl;
71 }
72
73 static ICommDlgBrowser *
74 ICommDlgBrowser_from_impl(SHDESK *This)
75 {
76 return (ICommDlgBrowser *)&This->lpVtblCommDlgBrowser;
77 }
78
79 static IServiceProvider *
80 IServiceProvider_from_impl(SHDESK *This)
81 {
82 return (IServiceProvider *)&This->lpVtblServiceProvider;
83 }
84
85 static SHDESK *
86 impl_from_IShellBrowser(IShellBrowser *iface)
87 {
88 return (SHDESK *)((ULONG_PTR)iface - FIELD_OFFSET(SHDESK, lpVtbl));
89 }
90
91 static SHDESK *
92 impl_from_ICommDlgBrowser(ICommDlgBrowser *iface)
93 {
94 return (SHDESK *)((ULONG_PTR)iface - FIELD_OFFSET(SHDESK, lpVtblCommDlgBrowser));
95 }
96
97 static SHDESK *
98 impl_from_IServiceProvider(IServiceProvider *iface)
99 {
100 return (SHDESK *)((ULONG_PTR)iface - FIELD_OFFSET(SHDESK, lpVtblServiceProvider));
101 }
102
103 static void
104 SHDESK_Free(SHDESK *This)
105 {
106 if (This->ShellDesk != NULL)
107 IShellDesktopTray_Release(This->ShellDesk);
108
109 if (This->DesktopView != NULL)
110 {
111 if (This->hWndShellView != NULL)
112 IShellView_DestroyViewWindow(This->DesktopView);
113
114 IShellView_Release(This->DesktopView);
115 This->DesktopView = NULL;
116 This->hWndShellView = NULL;
117 This->hWndDesktopListView = NULL;
118 }
119
120 if (This->pidlDesktopDirectory != NULL)
121 {
122 ILFree(This->pidlDesktopDirectory);
123 This->pidlDesktopDirectory = NULL;
124 }
125
126 if (This->pidlDesktop != NULL)
127 {
128 ILFree(This->pidlDesktop);
129 This->pidlDesktop = NULL;
130 }
131
132 ZeroMemory(This, sizeof(SHDESK));
133 LocalFree((HLOCAL)This);
134 }
135
136 static ULONG STDMETHODCALLTYPE
137 SHDESK_Release(IShellBrowser *iface)
138 {
139 SHDESK *This = impl_from_IShellBrowser(iface);
140 ULONG Ret;
141
142 Ret = InterlockedDecrement(&This->Ref);
143 if (Ret == 0)
144 SHDESK_Free(This);
145
146 return Ret;
147 }
148
149 static ULONG STDMETHODCALLTYPE
150 SHDESK_AddRef(IShellBrowser *iface)
151 {
152 SHDESK *This = impl_from_IShellBrowser(iface);
153
154 return InterlockedIncrement(&This->Ref);
155 }
156
157 static HRESULT STDMETHODCALLTYPE
158 SHDESK_QueryInterface(IShellBrowser *iface, REFIID riid, LPVOID *ppvObj)
159 {
160 SHDESK *This;
161
162 if (ppvObj == NULL)
163 return E_POINTER;
164
165 This = impl_from_IShellBrowser(iface);
166
167 if (IsEqualIID(riid, &IID_IUnknown))
168 {
169 *ppvObj = IUnknown_from_impl(This);
170 }
171 else if (This->DefaultShellBrowser != NULL)
172 {
173 return IShellBrowser_QueryInterface(This->DefaultShellBrowser, riid, ppvObj);
174 }
175 else if (IsEqualIID(riid, &IID_IOleWindow))
176 {
177 *ppvObj = IOleWindow_from_impl(This);
178 }
179 else if (IsEqualIID(riid, &IID_IShellBrowser))
180 {
181 *ppvObj = IShellBrowser_from_impl(This);
182 }
183 else if (IsEqualIID(riid, &IID_ICommDlgBrowser))
184 {
185 *ppvObj = ICommDlgBrowser_from_impl(This);
186 }
187 else if (IsEqualIID(riid, &IID_IServiceProvider))
188 {
189 *ppvObj = IServiceProvider_from_impl(This);
190 }
191 else
192 {
193 *ppvObj = NULL;
194 return E_NOINTERFACE;
195 }
196
197 SHDESK_AddRef(iface);
198 return S_OK;
199 }
200
201 static PSHDESK
202 SHDESK_Create(HWND hWnd, LPCREATESTRUCT lpCreateStruct)
203 {
204 IShellFolder *psfDesktopFolder;
205 IShellDesktopTray *ShellDesk;
206 CSFV csfv;
207 SHDESK *This;
208 HRESULT hRet;
209
210 ShellDesk = (IShellDesktopTray *)lpCreateStruct->lpCreateParams;
211 if (ShellDesk == NULL)
212 {
213 WARN("No IShellDesk interface provided!");
214 return NULL;
215 }
216
217 This = (PSHDESK)LocalAlloc(LMEM_FIXED, sizeof(SHDESK));
218 if (This == NULL)
219 return NULL;
220
221 ZeroMemory(This, sizeof(SHDESK));
222 This->Tag = SHDESK_TAG;
223 This->lpVtbl = &SHDESK_Vtbl;
224 This->lpVtblCommDlgBrowser = &SHDESK_ICommDlgBrowser_Vtbl;
225 This->lpVtblServiceProvider = &SHDESK_IServiceProvider_Vtbl;
226 This->Ref = 1;
227 This->hWnd = hWnd;
228 This->ShellDesk = ShellDesk;
229 IShellDesktopTray_AddRef(ShellDesk);
230
231 This->pidlDesktopDirectory = SHCloneSpecialIDList(This->hWnd, CSIDL_DESKTOPDIRECTORY, FALSE);
232 hRet = SHGetSpecialFolderLocation(This->hWnd, CSIDL_DESKTOP, &This->pidlDesktop);
233 if (!SUCCEEDED(hRet))
234 goto Fail;
235
236 hRet = SHGetDesktopFolder(&psfDesktopFolder);
237 if (!SUCCEEDED(hRet))
238 goto Fail;
239
240 ZeroMemory(&csfv, sizeof(csfv));
241 csfv.cbSize = sizeof(csfv);
242 csfv.pshf = psfDesktopFolder;
243 csfv.psvOuter = NULL;
244
245 hRet = SHCreateShellFolderViewEx(&csfv, &This->DesktopView);
246 IShellFolder_Release(psfDesktopFolder);
247
248 if (!SUCCEEDED(hRet))
249 {
250 Fail:
251 SHDESK_Release(IShellBrowser_from_impl(This));
252 return NULL;
253 }
254
255 return This;
256 }
257
258 static HWND
259 SHDESK_FindDesktopListView (SHDESK *This)
260 {
261 return FindWindowExW(This->hWndShellView,
262 NULL,
263 WC_LISTVIEW,
264 NULL);
265 }
266
267 static BOOL
268 SHDESK_CreateDeskWnd(SHDESK *This)
269 {
270 IShellBrowser *ShellBrowser;
271 FOLDERSETTINGS fs;
272 RECT rcClient;
273 HRESULT hRet;
274
275 if (!GetClientRect(This->hWnd,
276 &rcClient))
277 {
278 return FALSE;
279 }
280
281 ShellBrowser = IShellBrowser_from_impl(This);
282
283 fs.ViewMode = FVM_ICON;
284 fs.fFlags = FWF_DESKTOP | FWF_NOCLIENTEDGE | FWF_NOSCROLL | FWF_TRANSPARENT;
285 hRet = IShellView_CreateViewWindow(This->DesktopView, NULL, &fs, ShellBrowser, &rcClient, &This->hWndShellView);
286 if (!SUCCEEDED(hRet))
287 return FALSE;
288
289 SetShellWindowEx (This->hWnd,
290 SHDESK_FindDesktopListView (This));
291
292 return TRUE;
293 }
294
295 static HRESULT STDMETHODCALLTYPE
296 SHDESK_GetWindow(IShellBrowser *iface, HWND *phwnd)
297 {
298 SHDESK *This = impl_from_IShellBrowser(iface);
299
300 if (This->hWnd != NULL)
301 {
302 *phwnd = This->hWnd;
303 return S_OK;
304 }
305
306 *phwnd = NULL;
307 return E_UNEXPECTED;
308 }
309
310 static HRESULT STDMETHODCALLTYPE
311 SHDESK_ContextSensitiveHelp(IShellBrowser *iface, BOOL fEnterMode)
312 {
313 return E_NOTIMPL;
314 }
315
316 static HRESULT STDMETHODCALLTYPE
317 SHDESK_InsertMenusSB(IShellBrowser *iface, HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths)
318 {
319 return E_NOTIMPL;
320 }
321
322 static HRESULT STDMETHODCALLTYPE
323 SHDESK_SetMenuSB(IShellBrowser *iface, HMENU hmenuShared, HOLEMENU holemenuRes, HWND hwndActiveObject)
324 {
325 return E_NOTIMPL;
326 }
327
328 static HRESULT STDMETHODCALLTYPE
329 SHDESK_RemoveMenusSB(IShellBrowser *iface, HMENU hmenuShared)
330 {
331 return E_NOTIMPL;
332 }
333
334 static HRESULT STDMETHODCALLTYPE
335 SHDESK_SetStatusTextSB(IShellBrowser *iface, LPCOLESTR lpszStatusText)
336 {
337 return E_NOTIMPL;
338 }
339
340 static HRESULT STDMETHODCALLTYPE
341 SHDESK_EnableModelessSB(IShellBrowser *iface, BOOL fEnable)
342 {
343 return E_NOTIMPL;
344 }
345
346 static HRESULT STDMETHODCALLTYPE
347 SHDESK_TranslateAcceleratorSB(IShellBrowser *iface, LPMSG lpmsg, WORD wID)
348 {
349 return S_FALSE;
350 }
351
352 static HRESULT STDMETHODCALLTYPE
353 SHDESK_BrowseObject(IShellBrowser *iface, LPCITEMIDLIST pidl, UINT wFlags)
354 {
355 return E_NOTIMPL;
356 }
357
358 static HRESULT STDMETHODCALLTYPE
359 SHDESK_GetViewStateStream(IShellBrowser *iface, DWORD grfMode, IStream **ppStrm)
360 {
361 return E_NOTIMPL;
362 }
363
364 static HWND
365 DesktopGetWindowControl(IN SHDESK *This,
366 IN UINT id)
367 {
368 switch (id)
369 {
370 case FCW_TOOLBAR:
371 case FCW_STATUS:
372 case FCW_TREE:
373 case FCW_PROGRESS:
374 return NULL;
375
376 default:
377 return NULL;
378 }
379
380 }
381
382 static HRESULT STDMETHODCALLTYPE
383 SHDESK_GetControlWindow(IShellBrowser *iface, UINT id, HWND *lphwnd)
384 {
385 SHDESK *This = impl_from_IShellBrowser(iface);
386 HWND hWnd;
387
388 hWnd = DesktopGetWindowControl(This,
389 id);
390 if (hWnd != NULL)
391 {
392 *lphwnd = hWnd;
393 return S_OK;
394 }
395
396 *lphwnd = NULL;
397 return E_NOTIMPL;
398 }
399
400 static HRESULT STDMETHODCALLTYPE
401 SHDESK_SendControlMsg(IShellBrowser *iface, UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pret)
402 {
403 SHDESK *This = impl_from_IShellBrowser(iface);
404 HWND hWnd;
405
406 if (pret == NULL)
407 return E_POINTER;
408
409 hWnd = DesktopGetWindowControl(This,
410 id);
411 if (hWnd != NULL)
412 {
413 *pret = SendMessageW(hWnd,
414 uMsg,
415 wParam,
416 lParam);
417 return S_OK;
418 }
419
420 return E_NOTIMPL;
421 }
422
423 static HRESULT STDMETHODCALLTYPE
424 SHDESK_QueryActiveShellView(IShellBrowser *iface, IShellView **ppshv)
425 {
426 IShellView *ActiveView;
427 SHDESK *This = impl_from_IShellBrowser(iface);
428
429 ActiveView = This->DesktopView;
430 SHDESK_AddRef(iface);
431 *ppshv = ActiveView;
432
433 return S_OK;
434 }
435
436 static HRESULT STDMETHODCALLTYPE
437 SHDESK_OnViewWindowActive(IShellBrowser *iface, IShellView *ppshv)
438 {
439 return E_NOTIMPL;
440 }
441
442 static HRESULT STDMETHODCALLTYPE
443 SHDESK_SetToolbarItems(IShellBrowser *iface, LPTBBUTTON lpButtons, UINT nButtons, UINT uFlags)
444 {
445 return E_NOTIMPL;
446 }
447
448 static HRESULT STDMETHODCALLTYPE
449 SHDESK_ICommDlgBrowser_QueryInterface(ICommDlgBrowser *iface, REFIID riid, LPVOID *ppvObj)
450 {
451 SHDESK *This = impl_from_ICommDlgBrowser(iface);
452 IShellBrowser *ShellBrowser = IShellBrowser_from_impl(This);
453
454 return SHDESK_QueryInterface(ShellBrowser, riid, ppvObj);
455 }
456
457 static ULONG STDMETHODCALLTYPE
458 SHDESK_ICommDlgBrowser_Release(ICommDlgBrowser *iface)
459 {
460 SHDESK *This = impl_from_ICommDlgBrowser(iface);
461 IShellBrowser *ShellBrowser = IShellBrowser_from_impl(This);
462
463 return SHDESK_Release(ShellBrowser);
464 }
465
466 static ULONG STDMETHODCALLTYPE
467 SHDESK_ICommDlgBrowser_AddRef(ICommDlgBrowser *iface)
468 {
469 SHDESK *This = impl_from_ICommDlgBrowser(iface);
470 IShellBrowser *ShellBrowser = IShellBrowser_from_impl(This);
471
472 return SHDESK_AddRef(ShellBrowser);
473 }
474
475 static HRESULT STDMETHODCALLTYPE
476 SHDESK_ICommDlgBrowser_OnDefaultCommand(ICommDlgBrowser *iface, IShellView *ppshv)
477 {
478 return E_NOTIMPL;
479 }
480
481 static HRESULT STDMETHODCALLTYPE
482 SHDESK_ICommDlgBrowser_OnStateChange(ICommDlgBrowser *iface, IShellView *ppshv, ULONG uChange)
483 {
484 return S_OK;
485 }
486
487 static HRESULT STDMETHODCALLTYPE
488 SHDESK_ICommDlgBrowser_IncludeObject(ICommDlgBrowser *iface, IShellView *ppshv, LPCITEMIDLIST pidl)
489 {
490 return S_OK;
491 }
492
493 static const ICommDlgBrowserVtbl SHDESK_ICommDlgBrowser_Vtbl =
494 {
495 /* IUnknown */
496 SHDESK_ICommDlgBrowser_QueryInterface,
497 SHDESK_ICommDlgBrowser_AddRef,
498 SHDESK_ICommDlgBrowser_Release,
499 /* ICommDlgBrowser */
500 SHDESK_ICommDlgBrowser_OnDefaultCommand,
501 SHDESK_ICommDlgBrowser_OnStateChange,
502 SHDESK_ICommDlgBrowser_IncludeObject
503 };
504
505 static HRESULT STDMETHODCALLTYPE
506 SHDESK_IServiceProvider_QueryInterface(IServiceProvider *iface, REFIID riid, LPVOID *ppvObj)
507 {
508 SHDESK *This = impl_from_IServiceProvider(iface);
509 IShellBrowser *ShellBrowser = IShellBrowser_from_impl(This);
510
511 return SHDESK_QueryInterface(ShellBrowser, riid, ppvObj);
512 }
513
514 static ULONG STDMETHODCALLTYPE
515 SHDESK_IServiceProvider_Release(IServiceProvider *iface)
516 {
517 SHDESK *This = impl_from_IServiceProvider(iface);
518 IShellBrowser *ShellBrowser = IShellBrowser_from_impl(This);
519
520 return SHDESK_Release(ShellBrowser);
521 }
522
523 static ULONG STDMETHODCALLTYPE
524 SHDESK_IServiceProvider_AddRef(IServiceProvider *iface)
525 {
526 SHDESK *This = impl_from_IServiceProvider(iface);
527 IShellBrowser *ShellBrowser = IShellBrowser_from_impl(This);
528
529 return SHDESK_AddRef(ShellBrowser);
530 }
531
532 static HRESULT STDMETHODCALLTYPE
533 SHDESK_IServiceProvider_QueryService(IServiceProvider *iface, REFGUID guidService, REFIID riid, PVOID *ppv)
534 {
535 /* FIXME - handle guidService */
536 return SHDESK_IServiceProvider_QueryInterface(iface, riid, ppv);
537 }
538
539 static const IServiceProviderVtbl SHDESK_IServiceProvider_Vtbl =
540 {
541 /* IUnknown */
542 SHDESK_IServiceProvider_QueryInterface,
543 SHDESK_IServiceProvider_AddRef,
544 SHDESK_IServiceProvider_Release,
545 /* IServiceProvider */
546 SHDESK_IServiceProvider_QueryService
547 };
548
549 static BOOL
550 SHDESK_MessageLoop(SHDESK *This)
551 {
552 MSG Msg;
553 BOOL bRet;
554
555 while ((bRet = GetMessageW(&Msg, NULL, 0, 0)) != 0)
556 {
557 if (bRet != -1)
558 {
559 TranslateMessage(&Msg);
560 DispatchMessageW(&Msg);
561 }
562 }
563
564 return TRUE;
565 }
566
567 static LRESULT CALLBACK
568 ProgmanWindowProc(IN HWND hwnd,
569 IN UINT uMsg,
570 IN WPARAM wParam,
571 IN LPARAM lParam)
572 {
573 SHDESK *This = NULL;
574 LRESULT Ret = FALSE;
575
576 if (uMsg != WM_NCCREATE)
577 {
578 This = (SHDESK*)GetWindowLongPtrW(hwnd,
579 0);
580 if (This == NULL)
581 goto DefMsgHandler;
582 }
583
584 if (This != NULL || uMsg == WM_NCCREATE)
585 {
586 switch (uMsg)
587 {
588 case WM_ERASEBKGND:
589 return (LRESULT)PaintDesktop((HDC)wParam);
590
591 case WM_GETISHELLBROWSER:
592 Ret = (LRESULT)IShellBrowser_from_impl(This);
593 break;
594
595 case WM_SIZE:
596 if (wParam == SIZE_MINIMIZED)
597 {
598 /* Hey, we're the desktop!!! */
599 ShowWindow(hwnd,
600 SW_RESTORE);
601 }
602 else
603 {
604 RECT rcDesktop;
605
606 rcDesktop.left = GetSystemMetrics(SM_XVIRTUALSCREEN);
607 rcDesktop.top = GetSystemMetrics(SM_YVIRTUALSCREEN);
608 rcDesktop.right = GetSystemMetrics(SM_CXVIRTUALSCREEN);
609 rcDesktop.bottom = GetSystemMetrics(SM_CYVIRTUALSCREEN);
610
611 /* FIXME: Update work area */
612 }
613 break;
614
615 case WM_SYSCOLORCHANGE:
616 {
617 InvalidateRect(This->hWnd,
618 NULL,
619 TRUE);
620
621 if (This->hWndShellView != NULL)
622 {
623 /* Forward the message */
624 SendMessageW(This->hWndShellView,
625 WM_SYSCOLORCHANGE,
626 wParam,
627 lParam);
628 }
629 break;
630 }
631
632 case WM_CREATE:
633 {
634 IShellDesktopTray_RegisterDesktopWindow(This->ShellDesk,
635 This->hWnd);
636
637 if (!SHDESK_CreateDeskWnd(This))
638 WARN("Could not create the desktop view control!\n");
639 break;
640 }
641
642 case WM_NCCREATE:
643 {
644 LPCREATESTRUCT CreateStruct = (LPCREATESTRUCT)lParam;
645 This = SHDESK_Create(hwnd, CreateStruct);
646 if (This == NULL)
647 {
648 WARN("Failed to create desktop structure\n");
649 break;
650 }
651
652 SetWindowLongPtrW(hwnd,
653 0,
654 (LONG_PTR)This);
655 Ret = TRUE;
656 break;
657 }
658
659 case WM_NCDESTROY:
660 {
661 SHDESK_Free(This);
662 break;
663 }
664
665 default:
666 DefMsgHandler:
667 Ret = DefWindowProcW(hwnd, uMsg, wParam, lParam);
668 break;
669 }
670 }
671
672 return Ret;
673 }
674
675 static BOOL
676 RegisterProgmanWindowClass(VOID)
677 {
678 WNDCLASSW wcProgman;
679
680 wcProgman.style = CS_DBLCLKS;
681 wcProgman.lpfnWndProc = ProgmanWindowProc;
682 wcProgman.cbClsExtra = 0;
683 wcProgman.cbWndExtra = sizeof(PSHDESK);
684 wcProgman.hInstance = shell32_hInstance;
685 wcProgman.hIcon = NULL;
686 wcProgman.hCursor = LoadCursorW(NULL,
687 IDC_ARROW);
688 wcProgman.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
689 wcProgman.lpszMenuName = NULL;
690 wcProgman.lpszClassName = szProgmanClassName;
691
692 return RegisterClassW(&wcProgman) != 0;
693 }
694
695
696 /*************************************************************************
697 * SHCreateDesktop [SHELL32.200]
698 *
699 */
700 HANDLE WINAPI SHCreateDesktop(IShellDesktopTray *ShellDesk)
701 {
702 HWND hWndDesk;
703 RECT rcDesk;
704
705 if (ShellDesk == NULL)
706 {
707 SetLastError(ERROR_INVALID_PARAMETER);
708 return NULL;
709 }
710
711 if (RegisterProgmanWindowClass() == 0)
712 {
713 WARN("Failed to register the Progman window class!\n");
714 return NULL;
715 }
716
717 rcDesk.left = GetSystemMetrics(SM_XVIRTUALSCREEN);
718 rcDesk.top = GetSystemMetrics(SM_YVIRTUALSCREEN);
719 rcDesk.right = rcDesk.left + GetSystemMetrics(SM_CXVIRTUALSCREEN);
720 rcDesk.bottom = rcDesk.top + GetSystemMetrics(SM_CYVIRTUALSCREEN);
721
722 if (IsRectEmpty(&rcDesk))
723 {
724 rcDesk.left = rcDesk.top = 0;
725 rcDesk.right = GetSystemMetrics(SM_CXSCREEN);
726 rcDesk.bottom = GetSystemMetrics(SM_CYSCREEN);
727 }
728
729 hWndDesk = CreateWindowExW(0, szProgmanClassName, szProgmanWindowName,
730 WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
731 rcDesk.left, rcDesk.top, rcDesk.right, rcDesk.bottom,
732 NULL, NULL, shell32_hInstance, (LPVOID)ShellDesk);
733 if (hWndDesk != NULL)
734 return (HANDLE)GetWindowLongPtrW(hWndDesk, 0);
735
736 return NULL;
737 }
738
739 /*************************************************************************
740 * SHCreateDesktop [SHELL32.201]
741 *
742 */
743 BOOL WINAPI SHDesktopMessageLoop(HANDLE hDesktop)
744 {
745 PSHDESK Desk = (PSHDESK)hDesktop;
746
747 if (Desk == NULL || Desk->Tag != SHDESK_TAG)
748 {
749 SetLastError(ERROR_INVALID_PARAMETER);
750 return FALSE;
751 }
752
753 return SHDESK_MessageLoop(Desk);
754 }
755
756 static const IShellBrowserVtbl SHDESK_Vtbl =
757 {
758 /* IUnknown */
759 SHDESK_QueryInterface,
760 SHDESK_AddRef,
761 SHDESK_Release,
762 /* IOleWindow */
763 SHDESK_GetWindow,
764 SHDESK_ContextSensitiveHelp,
765 /* IShellBrowser */
766 SHDESK_InsertMenusSB,
767 SHDESK_SetMenuSB,
768 SHDESK_RemoveMenusSB,
769 SHDESK_SetStatusTextSB,
770 SHDESK_EnableModelessSB,
771 SHDESK_TranslateAcceleratorSB,
772 SHDESK_BrowseObject,
773 SHDESK_GetViewStateStream,
774 SHDESK_GetControlWindow,
775 SHDESK_SendControlMsg,
776 SHDESK_QueryActiveShellView,
777 SHDESK_OnViewWindowActive,
778 SHDESK_SetToolbarItems
779 };