- Go away STDCALL, time has come for WINAPI and NTAPI
[reactos.git] / reactos / dll / win32 / user32 / misc / desktop.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS user32.dll
5 * FILE: lib/user32/misc/desktop.c
6 * PURPOSE: Desktops
7 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * UPDATE HISTORY:
9 * 06-06-2001 CSH Created
10 */
11
12 #include <user32.h>
13
14 #include <wine/debug.h>
15 WINE_DEFAULT_DEBUG_CHANNEL(user32);
16
17 #define DESKTOP_CLASS_ATOM MAKEINTATOMA(32769) /* Desktop */
18 static LRESULT WINAPI DesktopWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );
19
20 /*********************************************************************
21 * desktop class descriptor
22 */
23 const struct builtin_class_descr DESKTOP_builtin_class =
24 {
25 (LPCWSTR) DESKTOP_CLASS_ATOM, /* name */
26 CS_DBLCLKS, /* style */
27 NULL, /* procA (winproc is Unicode only) */
28 (WNDPROC) DesktopWndProc, /* procW */
29 0, /* extra */
30 IDC_ARROW, /* cursor */
31 (HBRUSH)(COLOR_BACKGROUND+1) /* brush */
32 };
33
34 static
35 LRESULT
36 WINAPI
37 DesktopWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
38 {
39 FIXME("Desktop Class Atom!\n");
40 if (message == WM_NCCREATE) return TRUE;
41 return 0; /* all other messages are ignored */
42 }
43
44 VOID
45 WINAPI
46 LogFontA2W(LPLOGFONTW pW, CONST LOGFONTA *pA)
47 {
48 #define COPYS(f,len) MultiByteToWideChar ( CP_THREAD_ACP, 0, pA->f, len, pW->f, len )
49 #define COPYN(f) pW->f = pA->f
50
51 COPYN(lfHeight);
52 COPYN(lfWidth);
53 COPYN(lfEscapement);
54 COPYN(lfOrientation);
55 COPYN(lfWeight);
56 COPYN(lfItalic);
57 COPYN(lfUnderline);
58 COPYN(lfStrikeOut);
59 COPYN(lfCharSet);
60 COPYN(lfOutPrecision);
61 COPYN(lfClipPrecision);
62 COPYN(lfQuality);
63 COPYN(lfPitchAndFamily);
64 COPYS(lfFaceName,LF_FACESIZE);
65
66 #undef COPYN
67 #undef COPYS
68 }
69
70 VOID
71 WINAPI
72 LogFontW2A(LPLOGFONTA pA, CONST LOGFONTW *pW)
73 {
74 #define COPYS(f,len) WideCharToMultiByte ( CP_THREAD_ACP, 0, pW->f, len, pA->f, len, NULL, NULL )
75 #define COPYN(f) pA->f = pW->f
76
77 COPYN(lfHeight);
78 COPYN(lfWidth);
79 COPYN(lfEscapement);
80 COPYN(lfOrientation);
81 COPYN(lfWeight);
82 COPYN(lfItalic);
83 COPYN(lfUnderline);
84 COPYN(lfStrikeOut);
85 COPYN(lfCharSet);
86 COPYN(lfOutPrecision);
87 COPYN(lfClipPrecision);
88 COPYN(lfQuality);
89 COPYN(lfPitchAndFamily);
90 COPYS(lfFaceName,LF_FACESIZE);
91
92 #undef COPYN
93 #undef COPYS
94 }
95
96 /*
97 * @implemented
98 */
99 int WINAPI
100 GetSystemMetrics(int nIndex)
101 {
102 GetConnected();
103 // FIXME("Global Sever Data -> %x\n",g_psi);
104 if (nIndex < 0 || nIndex >= SM_CMETRICS) return 0;
105 return g_psi->SystemMetrics[nIndex];
106 }
107
108
109 /*
110 * @unimplemented
111 */
112 BOOL WINAPI SetDeskWallpaper(LPCSTR filename)
113 {
114 return SystemParametersInfoA(SPI_SETDESKWALLPAPER,0,(PVOID)filename,TRUE);
115 }
116 /*
117 * @implemented
118 */
119 BOOL WINAPI
120 SystemParametersInfoA(UINT uiAction,
121 UINT uiParam,
122 PVOID pvParam,
123 UINT fWinIni)
124 {
125 switch (uiAction)
126 {
127 case SPI_GETHIGHCONTRAST:
128 case SPI_SETHIGHCONTRAST:
129 case SPI_GETSOUNDSENTRY:
130 case SPI_SETSOUNDSENTRY:
131 {
132 /* FIXME: Support this accessibility SPI actions */
133 FIXME("FIXME: Unsupported SPI Code: %lx \n",uiAction );
134 return FALSE;
135 }
136
137 case SPI_GETNONCLIENTMETRICS:
138 {
139 LPNONCLIENTMETRICSA pnclma = (LPNONCLIENTMETRICSA)pvParam;
140 NONCLIENTMETRICSW nclmw;
141 if(pnclma->cbSize != sizeof(NONCLIENTMETRICSA))
142 {
143 SetLastError(ERROR_INVALID_PARAMETER);
144 return FALSE;
145 }
146 nclmw.cbSize = sizeof(NONCLIENTMETRICSW);
147
148 if (!SystemParametersInfoW(uiAction, sizeof(NONCLIENTMETRICSW),
149 &nclmw, fWinIni))
150 return FALSE;
151
152 pnclma->iBorderWidth = nclmw.iBorderWidth;
153 pnclma->iScrollWidth = nclmw.iScrollWidth;
154 pnclma->iScrollHeight = nclmw.iScrollHeight;
155 pnclma->iCaptionWidth = nclmw.iCaptionWidth;
156 pnclma->iCaptionHeight = nclmw.iCaptionHeight;
157 pnclma->iSmCaptionWidth = nclmw.iSmCaptionWidth;
158 pnclma->iSmCaptionHeight = nclmw.iSmCaptionHeight;
159 pnclma->iMenuWidth = nclmw.iMenuWidth;
160 pnclma->iMenuHeight = nclmw.iMenuHeight;
161 LogFontW2A(&(pnclma->lfCaptionFont), &(nclmw.lfCaptionFont));
162 LogFontW2A(&(pnclma->lfSmCaptionFont), &(nclmw.lfSmCaptionFont));
163 LogFontW2A(&(pnclma->lfMenuFont), &(nclmw.lfMenuFont));
164 LogFontW2A(&(pnclma->lfStatusFont), &(nclmw.lfStatusFont));
165 LogFontW2A(&(pnclma->lfMessageFont), &(nclmw.lfMessageFont));
166 return TRUE;
167 }
168 case SPI_SETNONCLIENTMETRICS:
169 {
170 LPNONCLIENTMETRICSA pnclma = (LPNONCLIENTMETRICSA)pvParam;
171 NONCLIENTMETRICSW nclmw;
172 if(pnclma->cbSize != sizeof(NONCLIENTMETRICSA))
173 {
174 SetLastError(ERROR_INVALID_PARAMETER);
175 return FALSE;
176 }
177 nclmw.cbSize = sizeof(NONCLIENTMETRICSW);
178 nclmw.iBorderWidth = pnclma->iBorderWidth;
179 nclmw.iScrollWidth = pnclma->iScrollWidth;
180 nclmw.iScrollHeight = pnclma->iScrollHeight;
181 nclmw.iCaptionWidth = pnclma->iCaptionWidth;
182 nclmw.iCaptionHeight = pnclma->iCaptionHeight;
183 nclmw.iSmCaptionWidth = pnclma->iSmCaptionWidth;
184 nclmw.iSmCaptionHeight = pnclma->iSmCaptionHeight;
185 nclmw.iMenuWidth = pnclma->iMenuWidth;
186 nclmw.iMenuHeight = pnclma->iMenuHeight;
187 LogFontA2W(&(nclmw.lfCaptionFont), &(pnclma->lfCaptionFont));
188 LogFontA2W(&(nclmw.lfSmCaptionFont), &(pnclma->lfSmCaptionFont));
189 LogFontA2W(&(nclmw.lfMenuFont), &(pnclma->lfMenuFont));
190 LogFontA2W(&(nclmw.lfStatusFont), &(pnclma->lfStatusFont));
191 LogFontA2W(&(nclmw.lfMessageFont), &(pnclma->lfMessageFont));
192
193 return SystemParametersInfoW(uiAction, sizeof(NONCLIENTMETRICSW),
194 &nclmw, fWinIni);
195 }
196 case SPI_GETICONMETRICS:
197 {
198 LPICONMETRICSA picma = (LPICONMETRICSA)pvParam;
199 ICONMETRICSW icmw;
200 if(picma->cbSize != sizeof(ICONMETRICSA))
201 {
202 SetLastError(ERROR_INVALID_PARAMETER);
203 return FALSE;
204 }
205 icmw.cbSize = sizeof(ICONMETRICSW);
206 if (!SystemParametersInfoW(uiAction, sizeof(ICONMETRICSW),
207 &icmw, fWinIni))
208 return FALSE;
209
210 picma->iHorzSpacing = icmw.iHorzSpacing;
211 picma->iVertSpacing = icmw.iVertSpacing;
212 picma->iTitleWrap = icmw.iTitleWrap;
213 LogFontW2A(&(picma->lfFont), &(icmw.lfFont));
214 return TRUE;
215 }
216 case SPI_SETICONMETRICS:
217 {
218 LPICONMETRICSA picma = (LPICONMETRICSA)pvParam;
219 ICONMETRICSW icmw;
220 if(picma->cbSize != sizeof(ICONMETRICSA))
221 {
222 SetLastError(ERROR_INVALID_PARAMETER);
223 return FALSE;
224 }
225 icmw.cbSize = sizeof(ICONMETRICSW);
226 icmw.iHorzSpacing = picma->iHorzSpacing;
227 icmw.iVertSpacing = picma->iVertSpacing;
228 icmw.iTitleWrap = picma->iTitleWrap;
229 LogFontA2W(&(icmw.lfFont), &(picma->lfFont));
230
231 return SystemParametersInfoW(uiAction, sizeof(ICONMETRICSW),
232 &icmw, fWinIni);
233 }
234 case SPI_GETICONTITLELOGFONT:
235 {
236 LOGFONTW lfw;
237 if (!SystemParametersInfoW(uiAction, 0, &lfw, fWinIni))
238 return FALSE;
239 LogFontW2A(pvParam, &lfw);
240 return TRUE;
241 }
242 case SPI_SETICONTITLELOGFONT:
243 {
244 LPLOGFONTA plfa = (LPLOGFONTA)pvParam;
245 LOGFONTW lfw;
246 LogFontA2W(&lfw,plfa);
247 return SystemParametersInfoW(uiAction, 0, &lfw, fWinIni);
248 }
249 case SPI_GETDESKWALLPAPER:
250 {
251 HKEY hKey;
252 BOOL Ret = FALSE;
253
254 #if 0
255 /* Get the desktop bitmap handle, this does NOT return the file name! */
256 if(!NtUserSystemParametersInfo(SPI_GETDESKWALLPAPER, 0, &hbmWallpaper, 0))
257 {
258 /* Return an empty string, no wallpapaper is set */
259 *(CHAR*)pvParam = '\0';
260 return TRUE;
261 }
262 #endif
263
264 /* FIXME - Read the registry key for now, but what happens if the wallpaper was
265 changed without SPIF_UPDATEINIFILE?! */
266 if(RegOpenKeyExW(HKEY_CURRENT_USER,
267 L"Control Panel\\Desktop",
268 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
269 {
270 DWORD Type, Size;
271 Size = uiParam;
272 if(RegQueryValueExA(hKey,
273 "Wallpaper",
274 NULL,
275 &Type,
276 (LPBYTE)pvParam,
277 &Size) == ERROR_SUCCESS
278 && Type == REG_SZ)
279 {
280 Ret = TRUE;
281 }
282 RegCloseKey(hKey);
283 }
284 return Ret;
285 }
286 case SPI_SETDESKWALLPAPER:
287 {
288 HBITMAP hNewWallpaper;
289 BOOL Ret;
290 LPSTR lpWallpaper = (LPSTR)pvParam;
291
292 if(lpWallpaper != NULL && *lpWallpaper != '\0')
293 {
294 hNewWallpaper = LoadImageA(0, lpWallpaper, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
295 if(hNewWallpaper == NULL)
296 {
297 return FALSE;
298 }
299 }
300 else
301 {
302 hNewWallpaper = NULL;
303 lpWallpaper = NULL;
304 }
305
306 /* Set the wallpaper bitmap */
307 if(!NtUserSystemParametersInfo(SPI_SETDESKWALLPAPER, 0, &hNewWallpaper, fWinIni & SPIF_SENDCHANGE))
308 {
309 if(hNewWallpaper != NULL)
310 DeleteObject(hNewWallpaper);
311 return FALSE;
312 }
313 /* Do not use the bitmap handle anymore, it doesn't belong to our process anymore! */
314
315 Ret = TRUE;
316 if(fWinIni & SPIF_UPDATEINIFILE)
317 {
318 /* Save the path to the file in the registry */
319 HKEY hKey;
320 if(RegOpenKeyExW(HKEY_CURRENT_USER,
321 L"Control Panel\\Desktop",
322 0, KEY_SET_VALUE, &hKey) == ERROR_SUCCESS)
323 {
324 Ret = RegSetValueExA(hKey, "Wallpaper", 0, REG_SZ, (LPBYTE)(lpWallpaper != NULL ? lpWallpaper : ""),
325 (lpWallpaper != NULL ? (lstrlenA(lpWallpaper) + 1) * sizeof(CHAR) : sizeof(CHAR)) == ERROR_SUCCESS);
326 RegCloseKey(hKey);
327 }
328 }
329
330 RedrawWindow(GetShellWindow(), NULL, NULL, RDW_INVALIDATE | RDW_ERASE);
331
332 return Ret;
333 }
334 }
335 return NtUserSystemParametersInfo(uiAction, uiParam, pvParam, fWinIni);
336 }
337
338
339 /*
340 * @implemented
341 */
342 BOOL WINAPI
343 SystemParametersInfoW(UINT uiAction,
344 UINT uiParam,
345 PVOID pvParam,
346 UINT fWinIni)
347 {
348 switch(uiAction)
349 {
350 case SPI_GETHIGHCONTRAST:
351 case SPI_SETHIGHCONTRAST:
352 case SPI_GETSOUNDSENTRY:
353 case SPI_SETSOUNDSENTRY:
354 {
355 /* FIXME: Support this accessibility SPI actions */
356 FIXME("FIXME: Unsupported SPI Code: %lx \n",uiAction );
357 return FALSE;
358 }
359 case SPI_GETDESKWALLPAPER:
360 {
361 HKEY hKey;
362 BOOL Ret = FALSE;
363
364 #if 0
365 /* Get the desktop bitmap handle, this does NOT return the file name! */
366 if(!NtUserSystemParametersInfo(SPI_GETDESKWALLPAPER, 0, &hbmWallpaper, 0))
367 {
368 /* Return an empty string, no wallpapaper is set */
369 *(WCHAR*)pvParam = L'\0';
370 return TRUE;
371 }
372 #endif
373
374 /* FIXME - Read the registry key for now, but what happens if the wallpaper was
375 changed without SPIF_UPDATEINIFILE?! */
376 if(RegOpenKeyExW(HKEY_CURRENT_USER,
377 L"Control Panel\\Desktop",
378 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
379 {
380 DWORD Type, Size;
381 Size = uiParam * sizeof(WCHAR);
382 if(RegQueryValueExW(hKey,
383 L"Wallpaper",
384 NULL,
385 &Type,
386 (LPBYTE)pvParam,
387 &Size) == ERROR_SUCCESS
388 && Type == REG_SZ)
389 {
390 Ret = TRUE;
391 }
392 RegCloseKey(hKey);
393 }
394 return Ret;
395 }
396 case SPI_SETDESKWALLPAPER:
397 {
398 HBITMAP hNewWallpaper;
399 BOOL Ret;
400 LPWSTR lpWallpaper = (LPWSTR)pvParam;
401
402 if(lpWallpaper != NULL && *lpWallpaper != L'\0')
403 {
404 hNewWallpaper = LoadImageW(0, lpWallpaper, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
405
406 if(hNewWallpaper == NULL)
407 {
408 return FALSE;
409 }
410 }
411 else
412 {
413 hNewWallpaper = NULL;
414 lpWallpaper = NULL;
415 }
416
417 /* Set the wallpaper bitmap */
418 if(!NtUserSystemParametersInfo(SPI_SETDESKWALLPAPER, 0, &hNewWallpaper, fWinIni & SPIF_SENDCHANGE))
419 return FALSE;
420 /* Do not use the bitmap handle anymore, it doesn't belong to our process anymore! */
421 Ret = TRUE;
422 if(fWinIni & SPIF_UPDATEINIFILE)
423 {
424 /* Save the path to the file in the registry */
425 HKEY hKey;
426
427 if(RegOpenKeyExW(HKEY_CURRENT_USER,
428 L"Control Panel\\Desktop",
429 0, KEY_SET_VALUE, &hKey) == ERROR_SUCCESS)
430 {
431 Ret = (RegSetValueExW(hKey, L"Wallpaper", 0, REG_SZ, (lpWallpaper != NULL ? (LPBYTE)lpWallpaper : (LPBYTE)L""),
432 (lpWallpaper != NULL ? (lstrlenW(lpWallpaper) + 1) * sizeof(WCHAR) : sizeof(WCHAR))) == ERROR_SUCCESS);
433 RegCloseKey(hKey);
434 }
435 }
436
437 RedrawWindow(GetShellWindow(), NULL, NULL, RDW_INVALIDATE | RDW_ERASE);
438
439 return Ret;
440 }
441 }
442 return NtUserSystemParametersInfo(uiAction, uiParam, pvParam, fWinIni);
443 }
444
445
446 /*
447 * @implemented
448 */
449 BOOL
450 WINAPI
451 CloseDesktop(
452 HDESK hDesktop)
453 {
454 return NtUserCloseDesktop(hDesktop);
455 }
456
457
458 /*
459 * @implemented
460 */
461 HDESK WINAPI
462 CreateDesktopA(LPCSTR lpszDesktop,
463 LPCSTR lpszDevice,
464 LPDEVMODEA pDevmode,
465 DWORD dwFlags,
466 ACCESS_MASK dwDesiredAccess,
467 LPSECURITY_ATTRIBUTES lpsa)
468 {
469 UNICODE_STRING DesktopNameU;
470 HDESK hDesktop;
471 LPDEVMODEW DevmodeW = NULL;
472
473 if (lpszDesktop)
474 {
475 /* After conversion, the buffer is zero-terminated */
476 RtlCreateUnicodeStringFromAsciiz(&DesktopNameU, lpszDesktop);
477 }
478 else
479 {
480 RtlInitUnicodeString(&DesktopNameU, NULL);
481 }
482
483 if (pDevmode)
484 DevmodeW = GdiConvertToDevmodeW(pDevmode);
485
486 hDesktop = CreateDesktopW(DesktopNameU.Buffer,
487 NULL,
488 DevmodeW,
489 dwFlags,
490 dwDesiredAccess,
491 lpsa);
492
493 /* Free the string, if it was allocated */
494 if (lpszDesktop) RtlFreeUnicodeString(&DesktopNameU);
495
496 return hDesktop;
497 }
498
499
500 /*
501 * @implemented
502 */
503 HDESK WINAPI
504 CreateDesktopW(LPCWSTR lpszDesktop,
505 LPCWSTR lpszDevice,
506 LPDEVMODEW pDevmode,
507 DWORD dwFlags,
508 ACCESS_MASK dwDesiredAccess,
509 LPSECURITY_ATTRIBUTES lpsa)
510 {
511 UNICODE_STRING DesktopName;
512 HWINSTA hWinSta;
513 HDESK hDesktop;
514
515 hWinSta = NtUserGetProcessWindowStation();
516
517 RtlInitUnicodeString(&DesktopName, lpszDesktop);
518
519 hDesktop = NtUserCreateDesktop(&DesktopName,
520 dwFlags,
521 dwDesiredAccess,
522 lpsa,
523 hWinSta);
524
525 return(hDesktop);
526 }
527
528
529 /*
530 * @implemented
531 */
532 BOOL
533 WINAPI
534 EnumDesktopsA(
535 HWINSTA WindowStation,
536 DESKTOPENUMPROCA EnumFunc,
537 LPARAM Context)
538 {
539 return EnumNamesA(WindowStation, EnumFunc, Context, TRUE);
540 }
541
542
543 /*
544 * @implemented
545 */
546 BOOL
547 WINAPI
548 EnumDesktopsW(
549 HWINSTA WindowStation,
550 DESKTOPENUMPROCW EnumFunc,
551 LPARAM Context)
552 {
553 return EnumNamesW(WindowStation, EnumFunc, Context, TRUE);
554 }
555
556
557 /*
558 * @implemented
559 */
560 HDESK
561 WINAPI
562 GetThreadDesktop(
563 DWORD dwThreadId)
564 {
565 return NtUserGetThreadDesktop(dwThreadId, 0);
566 }
567
568
569 /*
570 * @implemented
571 */
572 HDESK
573 WINAPI
574 OpenDesktopA(
575 LPSTR lpszDesktop,
576 DWORD dwFlags,
577 BOOL fInherit,
578 ACCESS_MASK dwDesiredAccess)
579 {
580 UNICODE_STRING DesktopNameU;
581 HDESK hDesktop;
582
583 if (lpszDesktop)
584 {
585 /* After conversion, the buffer is zero-terminated */
586 RtlCreateUnicodeStringFromAsciiz(&DesktopNameU, lpszDesktop);
587 }
588 else
589 {
590 RtlInitUnicodeString(&DesktopNameU, NULL);
591 }
592
593 hDesktop = OpenDesktopW(DesktopNameU.Buffer,
594 dwFlags,
595 fInherit,
596 dwDesiredAccess);
597
598 /* Free the string, if it was allocated */
599 if (lpszDesktop) RtlFreeUnicodeString(&DesktopNameU);
600
601 return hDesktop;
602 }
603
604
605 /*
606 * @implemented
607 */
608 HDESK
609 WINAPI
610 OpenDesktopW(
611 LPWSTR lpszDesktop,
612 DWORD dwFlags,
613 BOOL fInherit,
614 ACCESS_MASK dwDesiredAccess)
615 {
616 UNICODE_STRING DesktopName;
617
618 RtlInitUnicodeString(&DesktopName, lpszDesktop);
619
620 return NtUserOpenDesktop(
621 &DesktopName,
622 dwFlags,
623 dwDesiredAccess);
624 }
625
626
627 /*
628 * @implemented
629 */
630 HDESK
631 WINAPI
632 OpenInputDesktop(
633 DWORD dwFlags,
634 BOOL fInherit,
635 ACCESS_MASK dwDesiredAccess)
636 {
637 return NtUserOpenInputDesktop(
638 dwFlags,
639 fInherit,
640 dwDesiredAccess);
641 }
642
643
644 /*
645 * @implemented
646 */
647 BOOL
648 WINAPI
649 PaintDesktop(
650 HDC hdc)
651 {
652 return NtUserPaintDesktop(hdc);
653 }
654
655
656 /*
657 * @implemented
658 */
659 BOOL
660 WINAPI
661 SetThreadDesktop(
662 HDESK hDesktop)
663 {
664 return NtUserSetThreadDesktop(hDesktop);
665 }
666
667
668 /*
669 * @implemented
670 */
671 BOOL
672 WINAPI
673 SwitchDesktop(
674 HDESK hDesktop)
675 {
676 return NtUserSwitchDesktop(hDesktop);
677 }
678
679
680 /*
681 * @implemented
682 */
683 BOOL WINAPI
684 SetShellWindowEx(HWND hwndShell, HWND hwndShellListView)
685 {
686 return NtUserSetShellWindowEx(hwndShell, hwndShellListView);
687 }
688
689
690 /*
691 * @implemented
692 */
693 BOOL WINAPI
694 SetShellWindow(HWND hwndShell)
695 {
696 return SetShellWindowEx(hwndShell, hwndShell);
697 }
698
699
700 /*
701 * @implemented
702 */
703 HWND WINAPI
704 GetShellWindow(VOID)
705 {
706 PDESKTOPINFO pdi;
707 pdi = GetThreadDesktopInfo();
708 if (pdi) return pdi->hShellWindow;
709 return NULL;
710 }
711
712
713 /* EOF */