2 * SHLWAPI ordinal functions
4 * Copyright 1997 Marcus Meissner
6 * 2001-2003 Jon Griffiths
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "wine/port.h"
43 #include "shdeprecated.h"
50 #include "wine/unicode.h"
51 #include "wine/debug.h"
54 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
56 /* DLL handles for late bound calls */
57 extern HINSTANCE shlwapi_hInstance
;
58 extern DWORD SHLWAPI_ThreadRef_index
;
60 HRESULT WINAPI
IUnknown_QueryService(IUnknown
*,REFGUID
,REFIID
,LPVOID
*);
61 HRESULT WINAPI
SHInvokeCommand(HWND
,IShellFolder
*,LPCITEMIDLIST
,DWORD
);
62 BOOL WINAPI
SHAboutInfoW(LPWSTR
,DWORD
);
65 NOTES: Most functions exported by ordinal seem to be superfluous.
66 The reason for these functions to be there is to provide a wrapper
67 for unicode functions to provide these functions on systems without
68 unicode functions eg. win95/win98. Since we have such functions we just
69 call these. If running Wine with native DLLs, some late bound calls may
70 fail. However, it is better to implement the functions in the forward DLL
71 and recommend the builtin rather than reimplementing the calls here!
74 /*************************************************************************
77 * Copy a sharable memory handle from one process to another.
80 * hShared [I] Shared memory handle to duplicate
81 * dwSrcProcId [I] ID of the process owning hShared
82 * dwDstProcId [I] ID of the process wanting the duplicated handle
83 * dwAccess [I] Desired DuplicateHandle() access
84 * dwOptions [I] Desired DuplicateHandle() options
87 * Success: A handle suitable for use by the dwDstProcId process.
88 * Failure: A NULL handle.
91 HANDLE WINAPI
SHMapHandle(HANDLE hShared
, DWORD dwSrcProcId
, DWORD dwDstProcId
,
92 DWORD dwAccess
, DWORD dwOptions
)
95 DWORD dwMyProcId
= GetCurrentProcessId();
98 TRACE("(%p,%d,%d,%08x,%08x)\n", hShared
, dwDstProcId
, dwSrcProcId
,
103 TRACE("Returning handle NULL\n");
107 /* Get dest process handle */
108 if (dwDstProcId
== dwMyProcId
)
109 hDst
= GetCurrentProcess();
111 hDst
= OpenProcess(PROCESS_DUP_HANDLE
, 0, dwDstProcId
);
115 /* Get src process handle */
116 if (dwSrcProcId
== dwMyProcId
)
117 hSrc
= GetCurrentProcess();
119 hSrc
= OpenProcess(PROCESS_DUP_HANDLE
, 0, dwSrcProcId
);
123 /* Make handle available to dest process */
124 if (!DuplicateHandle(hSrc
, hShared
, hDst
, &hRet
,
125 dwAccess
, 0, dwOptions
| DUPLICATE_SAME_ACCESS
))
128 if (dwSrcProcId
!= dwMyProcId
)
132 if (dwDstProcId
!= dwMyProcId
)
136 TRACE("Returning handle %p\n", hRet
);
140 /*************************************************************************
143 * Create a block of sharable memory and initialise it with data.
146 * lpvData [I] Pointer to data to write
147 * dwSize [I] Size of data
148 * dwProcId [I] ID of process owning data
151 * Success: A shared memory handle
155 * Ordinals 7-11 provide a set of calls to create shared memory between a
156 * group of processes. The shared memory is treated opaquely in that its size
157 * is not exposed to clients who map it. This is accomplished by storing
158 * the size of the map as the first DWORD of mapped data, and then offsetting
159 * the view pointer returned by this size.
162 HANDLE WINAPI
SHAllocShared(LPCVOID lpvData
, DWORD dwSize
, DWORD dwProcId
)
168 TRACE("(%p,%d,%d)\n", lpvData
, dwSize
, dwProcId
);
170 /* Create file mapping of the correct length */
171 hMap
= CreateFileMappingA(INVALID_HANDLE_VALUE
, NULL
, FILE_MAP_READ
, 0,
172 dwSize
+ sizeof(dwSize
), NULL
);
176 /* Get a view in our process address space */
177 pMapped
= MapViewOfFile(hMap
, FILE_MAP_READ
| FILE_MAP_WRITE
, 0, 0, 0);
181 /* Write size of data, followed by the data, to the view */
182 *((DWORD
*)pMapped
) = dwSize
;
184 memcpy((char *) pMapped
+ sizeof(dwSize
), lpvData
, dwSize
);
186 /* Release view. All further views mapped will be opaque */
187 UnmapViewOfFile(pMapped
);
188 hRet
= SHMapHandle(hMap
, GetCurrentProcessId(), dwProcId
,
189 FILE_MAP_ALL_ACCESS
, DUPLICATE_SAME_ACCESS
);
196 /*************************************************************************
199 * Get a pointer to a block of shared memory from a shared memory handle.
202 * hShared [I] Shared memory handle
203 * dwProcId [I] ID of process owning hShared
206 * Success: A pointer to the shared memory
210 PVOID WINAPI
SHLockShared(HANDLE hShared
, DWORD dwProcId
)
215 TRACE("(%p %d)\n", hShared
, dwProcId
);
217 /* Get handle to shared memory for current process */
218 hDup
= SHMapHandle(hShared
, dwProcId
, GetCurrentProcessId(), FILE_MAP_ALL_ACCESS
, 0);
221 pMapped
= MapViewOfFile(hDup
, FILE_MAP_READ
| FILE_MAP_WRITE
, 0, 0, 0);
225 return (char *) pMapped
+ sizeof(DWORD
); /* Hide size */
229 /*************************************************************************
232 * Release a pointer to a block of shared memory.
235 * lpView [I] Shared memory pointer
242 BOOL WINAPI
SHUnlockShared(LPVOID lpView
)
244 TRACE("(%p)\n", lpView
);
245 return UnmapViewOfFile((char *) lpView
- sizeof(DWORD
)); /* Include size */
248 /*************************************************************************
251 * Destroy a block of sharable memory.
254 * hShared [I] Shared memory handle
255 * dwProcId [I] ID of process owning hShared
262 BOOL WINAPI
SHFreeShared(HANDLE hShared
, DWORD dwProcId
)
266 TRACE("(%p %d)\n", hShared
, dwProcId
);
271 /* Get a copy of the handle for our process, closing the source handle */
272 hClose
= SHMapHandle(hShared
, dwProcId
, GetCurrentProcessId(),
273 FILE_MAP_ALL_ACCESS
,DUPLICATE_CLOSE_SOURCE
);
274 /* Close local copy */
275 return CloseHandle(hClose
);
278 /*************************************************************************
281 * Create and register a clipboard enumerator for a web browser.
284 * lpBC [I] Binding context
285 * lpUnknown [I] An object exposing the IWebBrowserApp interface
289 * Failure: An HRESULT error code.
292 * The enumerator is stored as a property of the web browser. If it does not
293 * yet exist, it is created and set before being registered.
295 HRESULT WINAPI
RegisterDefaultAcceptHeaders(LPBC lpBC
, IUnknown
*lpUnknown
)
297 static const WCHAR szProperty
[] = { '{','D','0','F','C','A','4','2','0',
298 '-','D','3','F','5','-','1','1','C','F', '-','B','2','1','1','-','0',
299 '0','A','A','0','0','4','A','E','8','3','7','}','\0' };
301 IEnumFORMATETC
* pIEnumFormatEtc
= NULL
;
304 IWebBrowserApp
* pBrowser
;
306 TRACE("(%p, %p)\n", lpBC
, lpUnknown
);
308 hr
= IUnknown_QueryService(lpUnknown
, &IID_IWebBrowserApp
, &IID_IWebBrowserApp
, (void**)&pBrowser
);
312 V_VT(&var
) = VT_EMPTY
;
314 /* The property we get is the browsers clipboard enumerator */
315 property
= SysAllocString(szProperty
);
316 hr
= IWebBrowserApp_GetProperty(pBrowser
, property
, &var
);
317 SysFreeString(property
);
318 if (FAILED(hr
)) goto exit
;
320 if (V_VT(&var
) == VT_EMPTY
)
322 /* Iterate through accepted documents and RegisterClipBoardFormatA() them */
323 char szKeyBuff
[128], szValueBuff
[128];
324 DWORD dwKeySize
, dwValueSize
, dwRet
= 0, dwCount
= 0, dwNumValues
, dwType
;
325 FORMATETC
* formatList
, *format
;
328 TRACE("Registering formats and creating IEnumFORMATETC instance\n");
330 if (!RegOpenKeyA(HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows\\Current"
331 "Version\\Internet Settings\\Accepted Documents", &hDocs
))
337 /* Get count of values in key */
340 dwKeySize
= sizeof(szKeyBuff
);
341 dwRet
= RegEnumValueA(hDocs
,dwCount
,szKeyBuff
,&dwKeySize
,0,&dwType
,0,0);
345 dwNumValues
= dwCount
;
347 /* Note: dwCount = number of items + 1; The extra item is the end node */
348 format
= formatList
= HeapAlloc(GetProcessHeap(), 0, dwCount
* sizeof(FORMATETC
));
363 /* Register clipboard formats for the values and populate format list */
364 while(!dwRet
&& dwCount
< dwNumValues
)
366 dwKeySize
= sizeof(szKeyBuff
);
367 dwValueSize
= sizeof(szValueBuff
);
368 dwRet
= RegEnumValueA(hDocs
, dwCount
, szKeyBuff
, &dwKeySize
, 0, &dwType
,
369 (PBYTE
)szValueBuff
, &dwValueSize
);
372 HeapFree(GetProcessHeap(), 0, formatList
);
378 format
->cfFormat
= RegisterClipboardFormatA(szValueBuff
);
380 format
->dwAspect
= 1;
391 /* Terminate the (maybe empty) list, last entry has a cfFormat of 0 */
392 format
->cfFormat
= 0;
394 format
->dwAspect
= 1;
398 /* Create a clipboard enumerator */
399 hr
= CreateFormatEnumerator(dwNumValues
, formatList
, &pIEnumFormatEtc
);
400 HeapFree(GetProcessHeap(), 0, formatList
);
401 if (FAILED(hr
)) goto exit
;
403 /* Set our enumerator as the browsers property */
404 V_VT(&var
) = VT_UNKNOWN
;
405 V_UNKNOWN(&var
) = (IUnknown
*)pIEnumFormatEtc
;
407 property
= SysAllocString(szProperty
);
408 hr
= IWebBrowserApp_PutProperty(pBrowser
, property
, var
);
409 SysFreeString(property
);
412 IEnumFORMATETC_Release(pIEnumFormatEtc
);
417 if (V_VT(&var
) == VT_UNKNOWN
)
419 /* Our variant is holding the clipboard enumerator */
420 IUnknown
* pIUnknown
= V_UNKNOWN(&var
);
421 IEnumFORMATETC
* pClone
= NULL
;
423 TRACE("Retrieved IEnumFORMATETC property\n");
425 /* Get an IEnumFormatEtc interface from the variants value */
426 pIEnumFormatEtc
= NULL
;
427 hr
= IUnknown_QueryInterface(pIUnknown
, &IID_IEnumFORMATETC
, (void**)&pIEnumFormatEtc
);
428 if (hr
== S_OK
&& pIEnumFormatEtc
)
430 /* Clone and register the enumerator */
431 hr
= IEnumFORMATETC_Clone(pIEnumFormatEtc
, &pClone
);
432 if (hr
== S_OK
&& pClone
)
434 RegisterFormatEnumerator(lpBC
, pClone
, 0);
436 IEnumFORMATETC_Release(pClone
);
439 IUnknown_Release(pIUnknown
);
441 IUnknown_Release(V_UNKNOWN(&var
));
445 IWebBrowserApp_Release(pBrowser
);
449 /*************************************************************************
452 * Get Explorers "AcceptLanguage" setting.
455 * langbuf [O] Destination for language string
456 * buflen [I] Length of langbuf in characters
457 * [0] Success: used length of langbuf
460 * Success: S_OK. langbuf is set to the language string found.
461 * Failure: E_FAIL, If any arguments are invalid, error occurred, or Explorer
462 * does not contain the setting.
463 * E_NOT_SUFFICIENT_BUFFER, If the buffer is not big enough
465 HRESULT WINAPI
GetAcceptLanguagesW( LPWSTR langbuf
, LPDWORD buflen
)
467 static const WCHAR szkeyW
[] = {
468 'S','o','f','t','w','a','r','e','\\',
469 'M','i','c','r','o','s','o','f','t','\\',
470 'I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r','\\',
471 'I','n','t','e','r','n','a','t','i','o','n','a','l',0};
472 static const WCHAR valueW
[] = {
473 'A','c','c','e','p','t','L','a','n','g','u','a','g','e',0};
474 DWORD mystrlen
, mytype
;
481 TRACE("(%p, %p) *%p: %d\n", langbuf
, buflen
, buflen
, buflen
? *buflen
: -1);
483 if(!langbuf
|| !buflen
|| !*buflen
)
486 mystrlen
= (*buflen
> 20) ? *buflen
: 20 ;
487 len
= mystrlen
* sizeof(WCHAR
);
488 mystr
= HeapAlloc(GetProcessHeap(), 0, len
);
490 RegOpenKeyW(HKEY_CURRENT_USER
, szkeyW
, &mykey
);
491 lres
= RegQueryValueExW(mykey
, valueW
, 0, &mytype
, (PBYTE
)mystr
, &len
);
493 len
= lstrlenW(mystr
);
495 if (!lres
&& (*buflen
> len
)) {
496 lstrcpyW(langbuf
, mystr
);
498 HeapFree(GetProcessHeap(), 0, mystr
);
502 /* Did not find a value in the registry or the user buffer is too small */
503 mylcid
= GetUserDefaultLCID();
504 LcidToRfc1766W(mylcid
, mystr
, mystrlen
);
505 len
= lstrlenW(mystr
);
507 memcpy( langbuf
, mystr
, min(*buflen
, len
+1)*sizeof(WCHAR
) );
508 HeapFree(GetProcessHeap(), 0, mystr
);
516 return E_NOT_SUFFICIENT_BUFFER
;
519 /*************************************************************************
522 * Ascii version of GetAcceptLanguagesW.
524 HRESULT WINAPI
GetAcceptLanguagesA( LPSTR langbuf
, LPDWORD buflen
)
527 DWORD buflenW
, convlen
;
530 TRACE("(%p, %p) *%p: %d\n", langbuf
, buflen
, buflen
, buflen
? *buflen
: -1);
532 if(!langbuf
|| !buflen
|| !*buflen
) return E_FAIL
;
535 langbufW
= HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR
) * buflenW
);
536 retval
= GetAcceptLanguagesW(langbufW
, &buflenW
);
540 convlen
= WideCharToMultiByte(CP_ACP
, 0, langbufW
, -1, langbuf
, *buflen
, NULL
, NULL
);
541 convlen
--; /* do not count the terminating 0 */
543 else /* copy partial string anyway */
545 convlen
= WideCharToMultiByte(CP_ACP
, 0, langbufW
, *buflen
, langbuf
, *buflen
, NULL
, NULL
);
546 if (convlen
< *buflen
)
548 langbuf
[convlen
] = 0;
549 convlen
--; /* do not count the terminating 0 */
556 *buflen
= buflenW
? convlen
: 0;
558 HeapFree(GetProcessHeap(), 0, langbufW
);
562 /*************************************************************************
565 * Convert a GUID to a string.
568 * guid [I] GUID to convert
569 * lpszDest [O] Destination for string
570 * cchMax [I] Length of output buffer
573 * The length of the string created.
575 INT WINAPI
SHStringFromGUIDA(REFGUID guid
, LPSTR lpszDest
, INT cchMax
)
580 TRACE("(%s,%p,%d)\n", debugstr_guid(guid
), lpszDest
, cchMax
);
582 sprintf(xguid
, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
583 guid
->Data1
, guid
->Data2
, guid
->Data3
,
584 guid
->Data4
[0], guid
->Data4
[1], guid
->Data4
[2], guid
->Data4
[3],
585 guid
->Data4
[4], guid
->Data4
[5], guid
->Data4
[6], guid
->Data4
[7]);
587 iLen
= strlen(xguid
) + 1;
591 memcpy(lpszDest
, xguid
, iLen
);
595 /*************************************************************************
598 * Convert a GUID to a string.
601 * guid [I] GUID to convert
602 * str [O] Destination for string
603 * cmax [I] Length of output buffer
606 * The length of the string created.
608 INT WINAPI
SHStringFromGUIDW(REFGUID guid
, LPWSTR lpszDest
, INT cchMax
)
612 static const WCHAR wszFormat
[] = {'{','%','0','8','l','X','-','%','0','4','X','-','%','0','4','X','-',
613 '%','0','2','X','%','0','2','X','-','%','0','2','X','%','0','2','X','%','0','2','X','%','0','2',
614 'X','%','0','2','X','%','0','2','X','}',0};
616 TRACE("(%s,%p,%d)\n", debugstr_guid(guid
), lpszDest
, cchMax
);
618 sprintfW(xguid
, wszFormat
, guid
->Data1
, guid
->Data2
, guid
->Data3
,
619 guid
->Data4
[0], guid
->Data4
[1], guid
->Data4
[2], guid
->Data4
[3],
620 guid
->Data4
[4], guid
->Data4
[5], guid
->Data4
[6], guid
->Data4
[7]);
622 iLen
= strlenW(xguid
) + 1;
626 memcpy(lpszDest
, xguid
, iLen
*sizeof(WCHAR
));
630 /*************************************************************************
633 * Determine if a Unicode character is a blank.
636 * wc [I] Character to check.
639 * TRUE, if wc is a blank,
643 BOOL WINAPI
IsCharBlankW(WCHAR wc
)
647 return GetStringTypeW(CT_CTYPE1
, &wc
, 1, &CharType
) && (CharType
& C1_BLANK
);
650 /*************************************************************************
653 * Determine if a Unicode character is punctuation.
656 * wc [I] Character to check.
659 * TRUE, if wc is punctuation,
662 BOOL WINAPI
IsCharPunctW(WCHAR wc
)
666 return GetStringTypeW(CT_CTYPE1
, &wc
, 1, &CharType
) && (CharType
& C1_PUNCT
);
669 /*************************************************************************
672 * Determine if a Unicode character is a control character.
675 * wc [I] Character to check.
678 * TRUE, if wc is a control character,
681 BOOL WINAPI
IsCharCntrlW(WCHAR wc
)
685 return GetStringTypeW(CT_CTYPE1
, &wc
, 1, &CharType
) && (CharType
& C1_CNTRL
);
688 /*************************************************************************
691 * Determine if a Unicode character is a digit.
694 * wc [I] Character to check.
697 * TRUE, if wc is a digit,
700 BOOL WINAPI
IsCharDigitW(WCHAR wc
)
704 return GetStringTypeW(CT_CTYPE1
, &wc
, 1, &CharType
) && (CharType
& C1_DIGIT
);
707 /*************************************************************************
710 * Determine if a Unicode character is a hex digit.
713 * wc [I] Character to check.
716 * TRUE, if wc is a hex digit,
719 BOOL WINAPI
IsCharXDigitW(WCHAR wc
)
723 return GetStringTypeW(CT_CTYPE1
, &wc
, 1, &CharType
) && (CharType
& C1_XDIGIT
);
726 /*************************************************************************
730 BOOL WINAPI
GetStringType3ExW(LPWSTR src
, INT count
, LPWORD type
)
732 return GetStringTypeW(CT_CTYPE3
, src
, count
, type
);
735 /*************************************************************************
738 * Compare two Ascii strings up to a given length.
741 * lpszSrc [I] Source string
742 * lpszCmp [I] String to compare to lpszSrc
743 * len [I] Maximum length
746 * A number greater than, less than or equal to 0 depending on whether
747 * lpszSrc is greater than, less than or equal to lpszCmp.
749 DWORD WINAPI
StrCmpNCA(LPCSTR lpszSrc
, LPCSTR lpszCmp
, INT len
)
751 return StrCmpNA(lpszSrc
, lpszCmp
, len
);
754 /*************************************************************************
757 * Unicode version of StrCmpNCA.
759 DWORD WINAPI
StrCmpNCW(LPCWSTR lpszSrc
, LPCWSTR lpszCmp
, INT len
)
761 return StrCmpNW(lpszSrc
, lpszCmp
, len
);
764 /*************************************************************************
767 * Compare two Ascii strings up to a given length, ignoring case.
770 * lpszSrc [I] Source string
771 * lpszCmp [I] String to compare to lpszSrc
772 * len [I] Maximum length
775 * A number greater than, less than or equal to 0 depending on whether
776 * lpszSrc is greater than, less than or equal to lpszCmp.
778 DWORD WINAPI
StrCmpNICA(LPCSTR lpszSrc
, LPCSTR lpszCmp
, DWORD len
)
780 return StrCmpNIA(lpszSrc
, lpszCmp
, len
);
783 /*************************************************************************
786 * Unicode version of StrCmpNICA.
788 DWORD WINAPI
StrCmpNICW(LPCWSTR lpszSrc
, LPCWSTR lpszCmp
, DWORD len
)
790 return StrCmpNIW(lpszSrc
, lpszCmp
, len
);
793 /*************************************************************************
796 * Compare two Ascii strings.
799 * lpszSrc [I] Source string
800 * lpszCmp [I] String to compare to lpszSrc
803 * A number greater than, less than or equal to 0 depending on whether
804 * lpszSrc is greater than, less than or equal to lpszCmp.
806 DWORD WINAPI
StrCmpCA(LPCSTR lpszSrc
, LPCSTR lpszCmp
)
808 return lstrcmpA(lpszSrc
, lpszCmp
);
811 /*************************************************************************
814 * Unicode version of StrCmpCA.
816 DWORD WINAPI
StrCmpCW(LPCWSTR lpszSrc
, LPCWSTR lpszCmp
)
818 return lstrcmpW(lpszSrc
, lpszCmp
);
821 /*************************************************************************
824 * Compare two Ascii strings, ignoring case.
827 * lpszSrc [I] Source string
828 * lpszCmp [I] String to compare to lpszSrc
831 * A number greater than, less than or equal to 0 depending on whether
832 * lpszSrc is greater than, less than or equal to lpszCmp.
834 DWORD WINAPI
StrCmpICA(LPCSTR lpszSrc
, LPCSTR lpszCmp
)
836 return lstrcmpiA(lpszSrc
, lpszCmp
);
839 /*************************************************************************
842 * Unicode version of StrCmpICA.
844 DWORD WINAPI
StrCmpICW(LPCWSTR lpszSrc
, LPCWSTR lpszCmp
)
846 return lstrcmpiW(lpszSrc
, lpszCmp
);
849 /*************************************************************************
852 * Get an identification string for the OS and explorer.
855 * lpszDest [O] Destination for Id string
856 * dwDestLen [I] Length of lpszDest
859 * TRUE, If the string was created successfully
862 BOOL WINAPI
SHAboutInfoA(LPSTR lpszDest
, DWORD dwDestLen
)
866 TRACE("(%p,%d)\n", lpszDest
, dwDestLen
);
868 if (lpszDest
&& SHAboutInfoW(buff
, dwDestLen
))
870 WideCharToMultiByte(CP_ACP
, 0, buff
, -1, lpszDest
, dwDestLen
, NULL
, NULL
);
876 /*************************************************************************
879 * Unicode version of SHAboutInfoA.
881 BOOL WINAPI
SHAboutInfoW(LPWSTR lpszDest
, DWORD dwDestLen
)
883 static const WCHAR szIEKey
[] = { 'S','O','F','T','W','A','R','E','\\',
884 'M','i','c','r','o','s','o','f','t','\\','I','n','t','e','r','n','e','t',
885 ' ','E','x','p','l','o','r','e','r','\0' };
886 static const WCHAR szWinNtKey
[] = { 'S','O','F','T','W','A','R','E','\\',
887 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s',' ',
888 'N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\0' };
889 static const WCHAR szWinKey
[] = { 'S','O','F','T','W','A','R','E','\\',
890 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
891 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\0' };
892 static const WCHAR szRegKey
[] = { 'S','O','F','T','W','A','R','E','\\',
893 'M','i','c','r','o','s','o','f','t','\\','I','n','t','e','r','n','e','t',
894 ' ','E','x','p','l','o','r','e','r','\\',
895 'R','e','g','i','s','t','r','a','t','i','o','n','\0' };
896 static const WCHAR szVersion
[] = { 'V','e','r','s','i','o','n','\0' };
897 static const WCHAR szCustomized
[] = { 'C','u','s','t','o','m','i','z','e','d',
898 'V','e','r','s','i','o','n','\0' };
899 static const WCHAR szOwner
[] = { 'R','e','g','i','s','t','e','r','e','d',
900 'O','w','n','e','r','\0' };
901 static const WCHAR szOrg
[] = { 'R','e','g','i','s','t','e','r','e','d',
902 'O','r','g','a','n','i','z','a','t','i','o','n','\0' };
903 static const WCHAR szProduct
[] = { 'P','r','o','d','u','c','t','I','d','\0' };
904 static const WCHAR szUpdate
[] = { 'I','E','A','K',
905 'U','p','d','a','t','e','U','r','l','\0' };
906 static const WCHAR szHelp
[] = { 'I','E','A','K',
907 'H','e','l','p','S','t','r','i','n','g','\0' };
912 TRACE("(%p,%d)\n", lpszDest
, dwDestLen
);
919 /* Try the NT key first, followed by 95/98 key */
920 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, szWinNtKey
, 0, KEY_READ
, &hReg
) &&
921 RegOpenKeyExW(HKEY_LOCAL_MACHINE
, szWinKey
, 0, KEY_READ
, &hReg
))
927 if (!SHGetValueW(HKEY_LOCAL_MACHINE
, szIEKey
, szVersion
, &dwType
, buff
, &dwLen
))
929 DWORD dwStrLen
= strlenW(buff
);
930 dwLen
= 30 - dwStrLen
;
931 SHGetValueW(HKEY_LOCAL_MACHINE
, szIEKey
,
932 szCustomized
, &dwType
, buff
+dwStrLen
, &dwLen
);
934 StrCatBuffW(lpszDest
, buff
, dwDestLen
);
936 /* ~Registered Owner */
939 if (SHGetValueW(hReg
, szOwner
, 0, &dwType
, buff
+1, &dwLen
))
941 StrCatBuffW(lpszDest
, buff
, dwDestLen
);
943 /* ~Registered Organization */
945 if (SHGetValueW(hReg
, szOrg
, 0, &dwType
, buff
+1, &dwLen
))
947 StrCatBuffW(lpszDest
, buff
, dwDestLen
);
949 /* FIXME: Not sure where this number comes from */
953 StrCatBuffW(lpszDest
, buff
, dwDestLen
);
957 if (SHGetValueW(HKEY_LOCAL_MACHINE
, szRegKey
, szProduct
, &dwType
, buff
+1, &dwLen
))
959 StrCatBuffW(lpszDest
, buff
, dwDestLen
);
963 if(SHGetValueW(HKEY_LOCAL_MACHINE
, szWinKey
, szUpdate
, &dwType
, buff
+1, &dwLen
))
965 StrCatBuffW(lpszDest
, buff
, dwDestLen
);
967 /* ~IE Help String */
969 if(SHGetValueW(hReg
, szHelp
, 0, &dwType
, buff
+1, &dwLen
))
971 StrCatBuffW(lpszDest
, buff
, dwDestLen
);
977 /*************************************************************************
980 * Call IOleCommandTarget_QueryStatus() on an object.
983 * lpUnknown [I] Object supporting the IOleCommandTarget interface
984 * pguidCmdGroup [I] GUID for the command group
986 * prgCmds [O] Commands
987 * pCmdText [O] Command text
991 * Failure: E_FAIL, if lpUnknown is NULL.
992 * E_NOINTERFACE, if lpUnknown does not support IOleCommandTarget.
993 * Otherwise, an error code from IOleCommandTarget_QueryStatus().
995 HRESULT WINAPI
IUnknown_QueryStatus(IUnknown
* lpUnknown
, REFGUID pguidCmdGroup
,
996 ULONG cCmds
, OLECMD
*prgCmds
, OLECMDTEXT
* pCmdText
)
998 HRESULT hRet
= E_FAIL
;
1000 TRACE("(%p,%p,%d,%p,%p)\n",lpUnknown
, pguidCmdGroup
, cCmds
, prgCmds
, pCmdText
);
1004 IOleCommandTarget
* lpOle
;
1006 hRet
= IUnknown_QueryInterface(lpUnknown
, &IID_IOleCommandTarget
,
1009 if (SUCCEEDED(hRet
) && lpOle
)
1011 hRet
= IOleCommandTarget_QueryStatus(lpOle
, pguidCmdGroup
, cCmds
,
1013 IOleCommandTarget_Release(lpOle
);
1019 /*************************************************************************
1022 * Call IOleCommandTarget_Exec() on an object.
1025 * lpUnknown [I] Object supporting the IOleCommandTarget interface
1026 * pguidCmdGroup [I] GUID for the command group
1030 * Failure: E_FAIL, if lpUnknown is NULL.
1031 * E_NOINTERFACE, if lpUnknown does not support IOleCommandTarget.
1032 * Otherwise, an error code from IOleCommandTarget_Exec().
1034 HRESULT WINAPI
IUnknown_Exec(IUnknown
* lpUnknown
, REFGUID pguidCmdGroup
,
1035 DWORD nCmdID
, DWORD nCmdexecopt
, VARIANT
* pvaIn
,
1038 HRESULT hRet
= E_FAIL
;
1040 TRACE("(%p,%p,%d,%d,%p,%p)\n",lpUnknown
, pguidCmdGroup
, nCmdID
,
1041 nCmdexecopt
, pvaIn
, pvaOut
);
1045 IOleCommandTarget
* lpOle
;
1047 hRet
= IUnknown_QueryInterface(lpUnknown
, &IID_IOleCommandTarget
,
1049 if (SUCCEEDED(hRet
) && lpOle
)
1051 hRet
= IOleCommandTarget_Exec(lpOle
, pguidCmdGroup
, nCmdID
,
1052 nCmdexecopt
, pvaIn
, pvaOut
);
1053 IOleCommandTarget_Release(lpOle
);
1059 /*************************************************************************
1062 * Retrieve, modify, and re-set a value from a window.
1065 * hWnd [I] Window to get value from
1066 * offset [I] Offset of value
1067 * mask [I] Mask for flags
1068 * flags [I] Bits to set in window value
1071 * The new value as it was set, or 0 if any parameter is invalid.
1074 * Only bits specified in mask are affected - set if present in flags and
1077 LONG WINAPI
SHSetWindowBits(HWND hwnd
, INT offset
, UINT mask
, UINT flags
)
1079 LONG ret
= GetWindowLongW(hwnd
, offset
);
1080 LONG new_flags
= (flags
& mask
) | (ret
& ~mask
);
1082 TRACE("%p %d %x %x\n", hwnd
, offset
, mask
, flags
);
1084 if (new_flags
!= ret
)
1085 ret
= SetWindowLongW(hwnd
, offset
, new_flags
);
1089 /*************************************************************************
1092 * Change a window's parent.
1095 * hWnd [I] Window to change parent of
1096 * hWndParent [I] New parent window
1099 * The old parent of hWnd.
1102 * If hWndParent is NULL (desktop), the window style is changed to WS_POPUP.
1103 * If hWndParent is NOT NULL then we set the WS_CHILD style.
1105 HWND WINAPI
SHSetParentHwnd(HWND hWnd
, HWND hWndParent
)
1107 TRACE("%p, %p\n", hWnd
, hWndParent
);
1109 if(GetParent(hWnd
) == hWndParent
)
1113 SHSetWindowBits(hWnd
, GWL_STYLE
, WS_CHILD
| WS_POPUP
, WS_CHILD
);
1115 SHSetWindowBits(hWnd
, GWL_STYLE
, WS_CHILD
| WS_POPUP
, WS_POPUP
);
1117 return hWndParent
? SetParent(hWnd
, hWndParent
) : NULL
;
1120 /*************************************************************************
1123 * Locate and advise a connection point in an IConnectionPointContainer object.
1126 * lpUnkSink [I] Sink for the connection point advise call
1127 * riid [I] REFIID of connection point to advise
1128 * fConnect [I] TRUE = Connection being establisted, FALSE = broken
1129 * lpUnknown [I] Object supporting the IConnectionPointContainer interface
1130 * lpCookie [O] Pointer to connection point cookie
1131 * lppCP [O] Destination for the IConnectionPoint found
1134 * Success: S_OK. If lppCP is non-NULL, it is filled with the IConnectionPoint
1135 * that was advised. The caller is responsible for releasing it.
1136 * Failure: E_FAIL, if any arguments are invalid.
1137 * E_NOINTERFACE, if lpUnknown isn't an IConnectionPointContainer,
1138 * Or an HRESULT error code if any call fails.
1140 HRESULT WINAPI
ConnectToConnectionPoint(IUnknown
* lpUnkSink
, REFIID riid
, BOOL fConnect
,
1141 IUnknown
* lpUnknown
, LPDWORD lpCookie
,
1142 IConnectionPoint
**lppCP
)
1145 IConnectionPointContainer
* lpContainer
;
1146 IConnectionPoint
*lpCP
;
1148 if(!lpUnknown
|| (fConnect
&& !lpUnkSink
))
1154 hRet
= IUnknown_QueryInterface(lpUnknown
, &IID_IConnectionPointContainer
,
1155 (void**)&lpContainer
);
1156 if (SUCCEEDED(hRet
))
1158 hRet
= IConnectionPointContainer_FindConnectionPoint(lpContainer
, riid
, &lpCP
);
1160 if (SUCCEEDED(hRet
))
1163 hRet
= IConnectionPoint_Unadvise(lpCP
, *lpCookie
);
1165 hRet
= IConnectionPoint_Advise(lpCP
, lpUnkSink
, lpCookie
);
1170 if (lppCP
&& SUCCEEDED(hRet
))
1171 *lppCP
= lpCP
; /* Caller keeps the interface */
1173 IConnectionPoint_Release(lpCP
); /* Release it */
1176 IConnectionPointContainer_Release(lpContainer
);
1181 /*************************************************************************
1184 * Release an interface and zero a supplied pointer.
1187 * lpUnknown [I] Object to release
1192 void WINAPI
IUnknown_AtomicRelease(IUnknown
** lpUnknown
)
1194 TRACE("(%p)\n", lpUnknown
);
1196 if(!lpUnknown
|| !*lpUnknown
) return;
1198 TRACE("doing Release\n");
1200 IUnknown_Release(*lpUnknown
);
1204 /*************************************************************************
1207 * Skip '//' if present in a string.
1210 * lpszSrc [I] String to check for '//'
1213 * Success: The next character after the '//' or the string if not present
1214 * Failure: NULL, if lpszStr is NULL.
1216 LPCSTR WINAPI
PathSkipLeadingSlashesA(LPCSTR lpszSrc
)
1218 if (lpszSrc
&& lpszSrc
[0] == '/' && lpszSrc
[1] == '/')
1223 /*************************************************************************
1226 * Check if two interfaces come from the same object.
1229 * lpInt1 [I] Interface to check against lpInt2.
1230 * lpInt2 [I] Interface to check against lpInt1.
1233 * TRUE, If the interfaces come from the same object.
1236 BOOL WINAPI
SHIsSameObject(IUnknown
* lpInt1
, IUnknown
* lpInt2
)
1238 IUnknown
*lpUnknown1
, *lpUnknown2
;
1241 TRACE("(%p %p)\n", lpInt1
, lpInt2
);
1243 if (!lpInt1
|| !lpInt2
)
1246 if (lpInt1
== lpInt2
)
1249 if (IUnknown_QueryInterface(lpInt1
, &IID_IUnknown
, (void**)&lpUnknown1
) != S_OK
)
1252 if (IUnknown_QueryInterface(lpInt2
, &IID_IUnknown
, (void**)&lpUnknown2
) != S_OK
)
1254 IUnknown_Release(lpUnknown1
);
1258 ret
= lpUnknown1
== lpUnknown2
;
1260 IUnknown_Release(lpUnknown1
);
1261 IUnknown_Release(lpUnknown2
);
1266 /*************************************************************************
1269 * Get the window handle of an object.
1272 * lpUnknown [I] Object to get the window handle of
1273 * lphWnd [O] Destination for window handle
1276 * Success: S_OK. lphWnd contains the objects window handle.
1277 * Failure: An HRESULT error code.
1280 * lpUnknown is expected to support one of the following interfaces:
1281 * IOleWindow(), IInternetSecurityMgrSite(), or IShellView().
1283 HRESULT WINAPI
IUnknown_GetWindow(IUnknown
*lpUnknown
, HWND
*lphWnd
)
1286 HRESULT hRet
= E_FAIL
;
1288 TRACE("(%p,%p)\n", lpUnknown
, lphWnd
);
1293 hRet
= IUnknown_QueryInterface(lpUnknown
, &IID_IOleWindow
, (void**)&lpOle
);
1297 hRet
= IUnknown_QueryInterface(lpUnknown
,&IID_IShellView
, (void**)&lpOle
);
1301 hRet
= IUnknown_QueryInterface(lpUnknown
, &IID_IInternetSecurityMgrSite
,
1306 if (SUCCEEDED(hRet
))
1308 /* Laziness here - Since GetWindow() is the first method for the above 3
1309 * interfaces, we use the same call for them all.
1311 hRet
= IOleWindow_GetWindow((IOleWindow
*)lpOle
, lphWnd
);
1312 IUnknown_Release(lpOle
);
1314 TRACE("Returning HWND=%p\n", *lphWnd
);
1320 /*************************************************************************
1323 * Call a SetOwner method of IShellService from specified object.
1326 * iface [I] Object that supports IShellService
1327 * pUnk [I] Argument for the SetOwner call
1330 * Corresponding return value from last call or E_FAIL for null input
1332 HRESULT WINAPI
IUnknown_SetOwner(IUnknown
*iface
, IUnknown
*pUnk
)
1334 IShellService
*service
;
1337 TRACE("(%p, %p)\n", iface
, pUnk
);
1339 if (!iface
) return E_FAIL
;
1341 hr
= IUnknown_QueryInterface(iface
, &IID_IShellService
, (void**)&service
);
1344 hr
= IShellService_SetOwner(service
, pUnk
);
1345 IShellService_Release(service
);
1351 /*************************************************************************
1354 * Call either IObjectWithSite_SetSite() or IInternetSecurityManager_SetSecuritySite() on
1358 HRESULT WINAPI
IUnknown_SetSite(
1359 IUnknown
*obj
, /* [in] OLE object */
1360 IUnknown
*site
) /* [in] Site interface */
1363 IObjectWithSite
*iobjwithsite
;
1364 IInternetSecurityManager
*isecmgr
;
1366 if (!obj
) return E_FAIL
;
1368 hr
= IUnknown_QueryInterface(obj
, &IID_IObjectWithSite
, (LPVOID
*)&iobjwithsite
);
1369 TRACE("IID_IObjectWithSite QI ret=%08x, %p\n", hr
, iobjwithsite
);
1372 hr
= IObjectWithSite_SetSite(iobjwithsite
, site
);
1373 TRACE("done IObjectWithSite_SetSite ret=%08x\n", hr
);
1374 IObjectWithSite_Release(iobjwithsite
);
1378 hr
= IUnknown_QueryInterface(obj
, &IID_IInternetSecurityManager
, (LPVOID
*)&isecmgr
);
1379 TRACE("IID_IInternetSecurityManager QI ret=%08x, %p\n", hr
, isecmgr
);
1380 if (FAILED(hr
)) return hr
;
1382 hr
= IInternetSecurityManager_SetSecuritySite(isecmgr
, (IInternetSecurityMgrSite
*)site
);
1383 TRACE("done IInternetSecurityManager_SetSecuritySite ret=%08x\n", hr
);
1384 IInternetSecurityManager_Release(isecmgr
);
1389 /*************************************************************************
1392 * Call IPersist_GetClassID() on an object.
1395 * lpUnknown [I] Object supporting the IPersist interface
1396 * clsid [O] Destination for Class Id
1399 * Success: S_OK. lpClassId contains the Class Id requested.
1400 * Failure: E_FAIL, If lpUnknown is NULL,
1401 * E_NOINTERFACE If lpUnknown does not support IPersist,
1402 * Or an HRESULT error code.
1404 HRESULT WINAPI
IUnknown_GetClassID(IUnknown
*lpUnknown
, CLSID
*clsid
)
1409 TRACE("(%p, %p)\n", lpUnknown
, clsid
);
1413 memset(clsid
, 0, sizeof(*clsid
));
1417 hr
= IUnknown_QueryInterface(lpUnknown
, &IID_IPersist
, (void**)&persist
);
1420 hr
= IUnknown_QueryInterface(lpUnknown
, &IID_IPersistFolder
, (void**)&persist
);
1425 hr
= IPersist_GetClassID(persist
, clsid
);
1426 IPersist_Release(persist
);
1430 /*************************************************************************
1433 * Retrieve a Service Interface from an object.
1436 * lpUnknown [I] Object to get an IServiceProvider interface from
1437 * sid [I] Service ID for IServiceProvider_QueryService() call
1438 * riid [I] Function requested for QueryService call
1439 * lppOut [O] Destination for the service interface pointer
1442 * Success: S_OK. lppOut contains an object providing the requested service
1443 * Failure: An HRESULT error code
1446 * lpUnknown is expected to support the IServiceProvider interface.
1448 HRESULT WINAPI
IUnknown_QueryService(IUnknown
* lpUnknown
, REFGUID sid
, REFIID riid
,
1451 IServiceProvider
* pService
= NULL
;
1462 hRet
= IUnknown_QueryInterface(lpUnknown
, &IID_IServiceProvider
,
1463 (LPVOID
*)&pService
);
1465 if (hRet
== S_OK
&& pService
)
1467 TRACE("QueryInterface returned (IServiceProvider*)%p\n", pService
);
1469 /* Get a Service interface from the object */
1470 hRet
= IServiceProvider_QueryService(pService
, sid
, riid
, lppOut
);
1472 TRACE("(IServiceProvider*)%p returned (IUnknown*)%p\n", pService
, *lppOut
);
1474 IServiceProvider_Release(pService
);
1479 /*************************************************************************
1482 * Calls IOleCommandTarget::Exec() for specified service object.
1485 * lpUnknown [I] Object to get an IServiceProvider interface from
1486 * service [I] Service ID for IServiceProvider_QueryService() call
1487 * group [I] Group ID for IOleCommandTarget::Exec() call
1488 * cmdId [I] Command ID for IOleCommandTarget::Exec() call
1489 * cmdOpt [I] Options flags for command
1490 * pIn [I] Input arguments for command
1491 * pOut [O] Output arguments for command
1494 * Success: S_OK. lppOut contains an object providing the requested service
1495 * Failure: An HRESULT error code
1498 * lpUnknown is expected to support the IServiceProvider interface.
1500 HRESULT WINAPI
IUnknown_QueryServiceExec(IUnknown
*lpUnknown
, REFIID service
,
1501 const GUID
*group
, DWORD cmdId
, DWORD cmdOpt
, VARIANT
*pIn
, VARIANT
*pOut
)
1503 IOleCommandTarget
*target
;
1506 TRACE("%p %s %s %d %08x %p %p\n", lpUnknown
, debugstr_guid(service
),
1507 debugstr_guid(group
), cmdId
, cmdOpt
, pIn
, pOut
);
1509 hr
= IUnknown_QueryService(lpUnknown
, service
, &IID_IOleCommandTarget
, (void**)&target
);
1512 hr
= IOleCommandTarget_Exec(target
, group
, cmdId
, cmdOpt
, pIn
, pOut
);
1513 IOleCommandTarget_Release(target
);
1516 TRACE("<-- hr=0x%08x\n", hr
);
1521 /*************************************************************************
1524 * Calls IProfferService methods to proffer/revoke specified service.
1527 * lpUnknown [I] Object to get an IServiceProvider interface from
1528 * service [I] Service ID for IProfferService::Proffer/Revoke calls
1529 * pService [I] Service to proffer. If NULL ::Revoke is called
1530 * pCookie [IO] Group ID for IOleCommandTarget::Exec() call
1533 * Success: S_OK. IProffer method returns S_OK
1534 * Failure: An HRESULT error code
1537 * lpUnknown is expected to support the IServiceProvider interface.
1539 HRESULT WINAPI
IUnknown_ProfferService(IUnknown
*lpUnknown
, REFGUID service
, IServiceProvider
*pService
, DWORD
*pCookie
)
1541 IProfferService
*proffer
;
1544 TRACE("%p %s %p %p\n", lpUnknown
, debugstr_guid(service
), pService
, pCookie
);
1546 hr
= IUnknown_QueryService(lpUnknown
, &IID_IProfferService
, &IID_IProfferService
, (void**)&proffer
);
1550 hr
= IProfferService_ProfferService(proffer
, service
, pService
, pCookie
);
1553 hr
= IProfferService_RevokeService(proffer
, *pCookie
);
1557 IProfferService_Release(proffer
);
1563 /*************************************************************************
1566 * Call an object's UIActivateIO method.
1569 * unknown [I] Object to call the UIActivateIO method on
1570 * activate [I] Parameter for UIActivateIO call
1571 * msg [I] Parameter for UIActivateIO call
1574 * Success: Value of UI_ActivateIO call
1575 * Failure: An HRESULT error code
1578 * unknown is expected to support the IInputObject interface.
1580 HRESULT WINAPI
IUnknown_UIActivateIO(IUnknown
*unknown
, BOOL activate
, LPMSG msg
)
1582 IInputObject
* object
= NULL
;
1588 /* Get an IInputObject interface from the object */
1589 ret
= IUnknown_QueryInterface(unknown
, &IID_IInputObject
, (LPVOID
*) &object
);
1593 ret
= IInputObject_UIActivateIO(object
, activate
, msg
);
1594 IInputObject_Release(object
);
1600 /*************************************************************************
1603 * Loads a popup menu.
1606 * hInst [I] Instance handle
1607 * szName [I] Menu name
1613 BOOL WINAPI
SHLoadMenuPopup(HINSTANCE hInst
, LPCWSTR szName
)
1617 TRACE("%p %s\n", hInst
, debugstr_w(szName
));
1619 if ((hMenu
= LoadMenuW(hInst
, szName
)))
1621 if (GetSubMenu(hMenu
, 0))
1622 RemoveMenu(hMenu
, 0, MF_BYPOSITION
);
1630 typedef struct _enumWndData
1635 LRESULT (WINAPI
*pfnPost
)(HWND
,UINT
,WPARAM
,LPARAM
);
1638 /* Callback for SHLWAPI_178 */
1639 static BOOL CALLBACK
SHLWAPI_EnumChildProc(HWND hWnd
, LPARAM lParam
)
1641 enumWndData
*data
= (enumWndData
*)lParam
;
1643 TRACE("(%p,%p)\n", hWnd
, data
);
1644 data
->pfnPost(hWnd
, data
->uiMsgId
, data
->wParam
, data
->lParam
);
1648 /*************************************************************************
1651 * Send or post a message to every child of a window.
1654 * hWnd [I] Window whose children will get the messages
1655 * uiMsgId [I] Message Id
1656 * wParam [I] WPARAM of message
1657 * lParam [I] LPARAM of message
1658 * bSend [I] TRUE = Use SendMessageA(), FALSE = Use PostMessageA()
1664 * The appropriate ASCII or Unicode function is called for the window.
1666 void WINAPI
SHPropagateMessage(HWND hWnd
, UINT uiMsgId
, WPARAM wParam
, LPARAM lParam
, BOOL bSend
)
1670 TRACE("(%p,%u,%ld,%ld,%d)\n", hWnd
, uiMsgId
, wParam
, lParam
, bSend
);
1674 data
.uiMsgId
= uiMsgId
;
1675 data
.wParam
= wParam
;
1676 data
.lParam
= lParam
;
1679 data
.pfnPost
= IsWindowUnicode(hWnd
) ? (void*)SendMessageW
: (void*)SendMessageA
;
1681 data
.pfnPost
= IsWindowUnicode(hWnd
) ? (void*)PostMessageW
: (void*)PostMessageA
;
1683 EnumChildWindows(hWnd
, SHLWAPI_EnumChildProc
, (LPARAM
)&data
);
1687 /*************************************************************************
1690 * Remove all sub-menus from a menu.
1693 * hMenu [I] Menu to remove sub-menus from
1696 * Success: 0. All sub-menus under hMenu are removed
1697 * Failure: -1, if any parameter is invalid
1699 DWORD WINAPI
SHRemoveAllSubMenus(HMENU hMenu
)
1701 int iItemCount
= GetMenuItemCount(hMenu
) - 1;
1703 TRACE("%p\n", hMenu
);
1705 while (iItemCount
>= 0)
1707 HMENU hSubMenu
= GetSubMenu(hMenu
, iItemCount
);
1709 RemoveMenu(hMenu
, iItemCount
, MF_BYPOSITION
);
1715 /*************************************************************************
1718 * Enable or disable a menu item.
1721 * hMenu [I] Menu holding menu item
1722 * uID [I] ID of menu item to enable/disable
1723 * bEnable [I] Whether to enable (TRUE) or disable (FALSE) the item.
1726 * The return code from EnableMenuItem.
1728 UINT WINAPI
SHEnableMenuItem(HMENU hMenu
, UINT wItemID
, BOOL bEnable
)
1730 TRACE("%p, %u, %d\n", hMenu
, wItemID
, bEnable
);
1731 return EnableMenuItem(hMenu
, wItemID
, bEnable
? MF_ENABLED
: MF_GRAYED
);
1734 /*************************************************************************
1737 * Check or uncheck a menu item.
1740 * hMenu [I] Menu holding menu item
1741 * uID [I] ID of menu item to check/uncheck
1742 * bCheck [I] Whether to check (TRUE) or uncheck (FALSE) the item.
1745 * The return code from CheckMenuItem.
1747 DWORD WINAPI
SHCheckMenuItem(HMENU hMenu
, UINT uID
, BOOL bCheck
)
1749 TRACE("%p, %u, %d\n", hMenu
, uID
, bCheck
);
1750 return CheckMenuItem(hMenu
, uID
, bCheck
? MF_CHECKED
: MF_UNCHECKED
);
1753 /*************************************************************************
1756 * Register a window class if it isn't already.
1759 * lpWndClass [I] Window class to register
1762 * The result of the RegisterClassA call.
1764 DWORD WINAPI
SHRegisterClassA(WNDCLASSA
*wndclass
)
1767 if (GetClassInfoA(wndclass
->hInstance
, wndclass
->lpszClassName
, &wca
))
1769 return (DWORD
)RegisterClassA(wndclass
);
1772 /*************************************************************************
1775 BOOL WINAPI
SHSimulateDrop(IDropTarget
*pDrop
, IDataObject
*pDataObj
,
1776 DWORD grfKeyState
, PPOINTL lpPt
, DWORD
* pdwEffect
)
1778 DWORD dwEffect
= DROPEFFECT_LINK
| DROPEFFECT_MOVE
| DROPEFFECT_COPY
;
1779 POINTL pt
= { 0, 0 };
1781 TRACE("%p %p 0x%08x %p %p\n", pDrop
, pDataObj
, grfKeyState
, lpPt
, pdwEffect
);
1787 pdwEffect
= &dwEffect
;
1789 IDropTarget_DragEnter(pDrop
, pDataObj
, grfKeyState
, *lpPt
, pdwEffect
);
1791 if (*pdwEffect
!= DROPEFFECT_NONE
)
1792 return IDropTarget_Drop(pDrop
, pDataObj
, grfKeyState
, *lpPt
, pdwEffect
);
1794 IDropTarget_DragLeave(pDrop
);
1798 /*************************************************************************
1801 * Call IPersistPropertyBag_Load() on an object.
1804 * lpUnknown [I] Object supporting the IPersistPropertyBag interface
1805 * lpPropBag [O] Destination for loaded IPropertyBag
1809 * Failure: An HRESULT error code, or E_FAIL if lpUnknown is NULL.
1811 DWORD WINAPI
SHLoadFromPropertyBag(IUnknown
*lpUnknown
, IPropertyBag
* lpPropBag
)
1813 IPersistPropertyBag
* lpPPBag
;
1814 HRESULT hRet
= E_FAIL
;
1816 TRACE("(%p,%p)\n", lpUnknown
, lpPropBag
);
1820 hRet
= IUnknown_QueryInterface(lpUnknown
, &IID_IPersistPropertyBag
,
1822 if (SUCCEEDED(hRet
) && lpPPBag
)
1824 hRet
= IPersistPropertyBag_Load(lpPPBag
, lpPropBag
, NULL
);
1825 IPersistPropertyBag_Release(lpPPBag
);
1831 /*************************************************************************
1834 * Call IOleControlSite_TranslateAccelerator() on an object.
1837 * lpUnknown [I] Object supporting the IOleControlSite interface.
1838 * lpMsg [I] Key message to be processed.
1839 * dwModifiers [I] Flags containing the state of the modifier keys.
1843 * Failure: An HRESULT error code, or E_INVALIDARG if lpUnknown is NULL.
1845 HRESULT WINAPI
IUnknown_TranslateAcceleratorOCS(IUnknown
*lpUnknown
, LPMSG lpMsg
, DWORD dwModifiers
)
1847 IOleControlSite
* lpCSite
= NULL
;
1848 HRESULT hRet
= E_INVALIDARG
;
1850 TRACE("(%p,%p,0x%08x)\n", lpUnknown
, lpMsg
, dwModifiers
);
1853 hRet
= IUnknown_QueryInterface(lpUnknown
, &IID_IOleControlSite
,
1855 if (SUCCEEDED(hRet
) && lpCSite
)
1857 hRet
= IOleControlSite_TranslateAccelerator(lpCSite
, lpMsg
, dwModifiers
);
1858 IOleControlSite_Release(lpCSite
);
1865 /*************************************************************************
1868 * Call IOleControlSite_OnFocus() on an object.
1871 * lpUnknown [I] Object supporting the IOleControlSite interface.
1872 * fGotFocus [I] Whether focus was gained (TRUE) or lost (FALSE).
1876 * Failure: An HRESULT error code, or E_FAIL if lpUnknown is NULL.
1878 HRESULT WINAPI
IUnknown_OnFocusOCS(IUnknown
*lpUnknown
, BOOL fGotFocus
)
1880 IOleControlSite
* lpCSite
= NULL
;
1881 HRESULT hRet
= E_FAIL
;
1883 TRACE("(%p, %d)\n", lpUnknown
, fGotFocus
);
1886 hRet
= IUnknown_QueryInterface(lpUnknown
, &IID_IOleControlSite
,
1888 if (SUCCEEDED(hRet
) && lpCSite
)
1890 hRet
= IOleControlSite_OnFocus(lpCSite
, fGotFocus
);
1891 IOleControlSite_Release(lpCSite
);
1897 /*************************************************************************
1900 HRESULT WINAPI
IUnknown_HandleIRestrict(LPUNKNOWN lpUnknown
, PVOID lpArg1
,
1901 PVOID lpArg2
, PVOID lpArg3
, PVOID lpArg4
)
1903 /* FIXME: {D12F26B2-D90A-11D0-830D-00AA005B4383} - What object does this represent? */
1904 static const DWORD service_id
[] = { 0xd12f26b2, 0x11d0d90a, 0xaa000d83, 0x83435b00 };
1905 /* FIXME: {D12F26B1-D90A-11D0-830D-00AA005B4383} - Also Unknown/undocumented */
1906 static const DWORD function_id
[] = { 0xd12f26b1, 0x11d0d90a, 0xaa000d83, 0x83435b00 };
1907 HRESULT hRet
= E_INVALIDARG
;
1908 LPUNKNOWN lpUnkInner
= NULL
; /* FIXME: Real type is unknown */
1910 TRACE("(%p,%p,%p,%p,%p)\n", lpUnknown
, lpArg1
, lpArg2
, lpArg3
, lpArg4
);
1912 if (lpUnknown
&& lpArg4
)
1914 hRet
= IUnknown_QueryService(lpUnknown
, (REFGUID
)service_id
,
1915 (REFGUID
)function_id
, (void**)&lpUnkInner
);
1917 if (SUCCEEDED(hRet
) && lpUnkInner
)
1919 /* FIXME: The type of service object requested is unknown, however
1920 * testing shows that its first method is called with 4 parameters.
1921 * Fake this by using IParseDisplayName_ParseDisplayName since the
1922 * signature and position in the vtable matches our unknown object type.
1924 hRet
= IParseDisplayName_ParseDisplayName((LPPARSEDISPLAYNAME
)lpUnkInner
,
1925 lpArg1
, lpArg2
, lpArg3
, lpArg4
);
1926 IUnknown_Release(lpUnkInner
);
1932 /*************************************************************************
1935 * Get a sub-menu from a menu item.
1938 * hMenu [I] Menu to get sub-menu from
1939 * uID [I] ID of menu item containing sub-menu
1942 * The sub-menu of the item, or a NULL handle if any parameters are invalid.
1944 HMENU WINAPI
SHGetMenuFromID(HMENU hMenu
, UINT uID
)
1948 TRACE("(%p,%u)\n", hMenu
, uID
);
1950 mi
.cbSize
= sizeof(mi
);
1951 mi
.fMask
= MIIM_SUBMENU
;
1953 if (!GetMenuItemInfoW(hMenu
, uID
, FALSE
, &mi
))
1959 /*************************************************************************
1962 * Get the color depth of the primary display.
1968 * The color depth of the primary display.
1970 DWORD WINAPI
SHGetCurColorRes(void)
1978 ret
= GetDeviceCaps(hdc
, BITSPIXEL
) * GetDeviceCaps(hdc
, PLANES
);
1983 /*************************************************************************
1986 * Wait for a message to arrive, with a timeout.
1989 * hand [I] Handle to query
1990 * dwTimeout [I] Timeout in ticks or INFINITE to never timeout
1993 * STATUS_TIMEOUT if no message is received before dwTimeout ticks passes.
1994 * Otherwise returns the value from MsgWaitForMultipleObjectsEx when a
1995 * message is available.
1997 DWORD WINAPI
SHWaitForSendMessageThread(HANDLE hand
, DWORD dwTimeout
)
1999 DWORD dwEndTicks
= GetTickCount() + dwTimeout
;
2002 while ((dwRet
= MsgWaitForMultipleObjectsEx(1, &hand
, dwTimeout
, QS_SENDMESSAGE
, 0)) == 1)
2006 PeekMessageW(&msg
, NULL
, 0, 0, PM_NOREMOVE
);
2008 if (dwTimeout
!= INFINITE
)
2010 if ((int)(dwTimeout
= dwEndTicks
- GetTickCount()) <= 0)
2011 return WAIT_TIMEOUT
;
2018 /*************************************************************************
2021 * Determine if a shell folder can be expanded.
2024 * lpFolder [I] Parent folder containing the object to test.
2025 * pidl [I] Id of the object to test.
2028 * Success: S_OK, if the object is expandable, S_FALSE otherwise.
2029 * Failure: E_INVALIDARG, if any argument is invalid.
2032 * If the object to be tested does not expose the IQueryInfo() interface it
2033 * will not be identified as an expandable folder.
2035 HRESULT WINAPI
SHIsExpandableFolder(LPSHELLFOLDER lpFolder
, LPCITEMIDLIST pidl
)
2037 HRESULT hRet
= E_INVALIDARG
;
2040 if (lpFolder
&& pidl
)
2042 hRet
= IShellFolder_GetUIObjectOf(lpFolder
, NULL
, 1, &pidl
, &IID_IQueryInfo
,
2043 NULL
, (void**)&lpInfo
);
2045 hRet
= S_FALSE
; /* Doesn't expose IQueryInfo */
2050 /* MSDN states of IQueryInfo_GetInfoFlags() that "This method is not
2051 * currently used". Really? You wouldn't be holding out on me would you?
2053 hRet
= IQueryInfo_GetInfoFlags(lpInfo
, &dwFlags
);
2055 if (SUCCEEDED(hRet
))
2057 /* 0x2 is an undocumented flag apparently indicating expandability */
2058 hRet
= dwFlags
& 0x2 ? S_OK
: S_FALSE
;
2061 IQueryInfo_Release(lpInfo
);
2067 /*************************************************************************
2070 * Blank out a region of text by drawing the background only.
2073 * hDC [I] Device context to draw in
2074 * pRect [I] Area to draw in
2075 * cRef [I] Color to draw in
2080 DWORD WINAPI
SHFillRectClr(HDC hDC
, LPCRECT pRect
, COLORREF cRef
)
2082 COLORREF cOldColor
= SetBkColor(hDC
, cRef
);
2083 ExtTextOutA(hDC
, 0, 0, ETO_OPAQUE
, pRect
, 0, 0, 0);
2084 SetBkColor(hDC
, cOldColor
);
2088 /*************************************************************************
2091 * Return the value associated with a key in a map.
2094 * lpKeys [I] A list of keys of length iLen
2095 * lpValues [I] A list of values associated with lpKeys, of length iLen
2096 * iLen [I] Length of both lpKeys and lpValues
2097 * iKey [I] The key value to look up in lpKeys
2100 * The value in lpValues associated with iKey, or -1 if iKey is not
2104 * - If two elements in the map share the same key, this function returns
2105 * the value closest to the start of the map
2106 * - The native version of this function crashes if lpKeys or lpValues is NULL.
2108 int WINAPI
SHSearchMapInt(const int *lpKeys
, const int *lpValues
, int iLen
, int iKey
)
2110 if (lpKeys
&& lpValues
)
2116 if (lpKeys
[i
] == iKey
)
2117 return lpValues
[i
]; /* Found */
2121 return -1; /* Not found */
2125 /*************************************************************************
2128 * Copy an interface pointer
2131 * lppDest [O] Destination for copy
2132 * lpUnknown [I] Source for copy
2137 VOID WINAPI
IUnknown_Set(IUnknown
**lppDest
, IUnknown
*lpUnknown
)
2139 TRACE("(%p,%p)\n", lppDest
, lpUnknown
);
2141 IUnknown_AtomicRelease(lppDest
);
2145 IUnknown_AddRef(lpUnknown
);
2146 *lppDest
= lpUnknown
;
2150 /*************************************************************************
2154 HRESULT WINAPI
MayQSForward(IUnknown
* lpUnknown
, PVOID lpReserved
,
2155 REFGUID riidCmdGrp
, ULONG cCmds
,
2156 OLECMD
*prgCmds
, OLECMDTEXT
* pCmdText
)
2158 FIXME("(%p,%p,%p,%d,%p,%p) - stub\n",
2159 lpUnknown
, lpReserved
, riidCmdGrp
, cCmds
, prgCmds
, pCmdText
);
2161 /* FIXME: Calls IsQSForward & IUnknown_QueryStatus */
2162 return DRAGDROP_E_NOTREGISTERED
;
2165 /*************************************************************************
2169 HRESULT WINAPI
MayExecForward(IUnknown
* lpUnknown
, INT iUnk
, REFGUID pguidCmdGroup
,
2170 DWORD nCmdID
, DWORD nCmdexecopt
, VARIANT
* pvaIn
,
2173 FIXME("(%p,%d,%p,%d,%d,%p,%p) - stub!\n", lpUnknown
, iUnk
, pguidCmdGroup
,
2174 nCmdID
, nCmdexecopt
, pvaIn
, pvaOut
);
2175 return DRAGDROP_E_NOTREGISTERED
;
2178 /*************************************************************************
2182 HRESULT WINAPI
IsQSForward(REFGUID pguidCmdGroup
,ULONG cCmds
, OLECMD
*prgCmds
)
2184 FIXME("(%p,%d,%p) - stub!\n", pguidCmdGroup
, cCmds
, prgCmds
);
2185 return DRAGDROP_E_NOTREGISTERED
;
2188 /*************************************************************************
2191 * Determine if a window is not a child of another window.
2194 * hParent [I] Suspected parent window
2195 * hChild [I] Suspected child window
2198 * TRUE: If hChild is a child window of hParent
2199 * FALSE: If hChild is not a child window of hParent, or they are equal
2201 BOOL WINAPI
SHIsChildOrSelf(HWND hParent
, HWND hChild
)
2203 TRACE("(%p,%p)\n", hParent
, hChild
);
2205 if (!hParent
|| !hChild
)
2207 else if(hParent
== hChild
)
2209 return !IsChild(hParent
, hChild
);
2212 /*************************************************************************
2213 * FDSA functions. Manage a dynamic array of fixed size memory blocks.
2218 DWORD num_items
; /* Number of elements inserted */
2219 void *mem
; /* Ptr to array */
2220 DWORD blocks_alloced
; /* Number of elements allocated */
2221 BYTE inc
; /* Number of elements to grow by when we need to expand */
2222 BYTE block_size
; /* Size in bytes of an element */
2223 BYTE flags
; /* Flags */
2226 #define FDSA_FLAG_INTERNAL_ALLOC 0x01 /* When set we have allocated mem internally */
2228 /*************************************************************************
2231 * Initialize an FDSA array.
2233 BOOL WINAPI
FDSA_Initialize(DWORD block_size
, DWORD inc
, FDSA_info
*info
, void *mem
,
2236 TRACE("(0x%08x 0x%08x %p %p 0x%08x)\n", block_size
, inc
, info
, mem
, init_blocks
);
2242 memset(mem
, 0, block_size
* init_blocks
);
2244 info
->num_items
= 0;
2247 info
->blocks_alloced
= init_blocks
;
2248 info
->block_size
= block_size
;
2254 /*************************************************************************
2257 * Destroy an FDSA array
2259 BOOL WINAPI
FDSA_Destroy(FDSA_info
*info
)
2261 TRACE("(%p)\n", info
);
2263 if(info
->flags
& FDSA_FLAG_INTERNAL_ALLOC
)
2265 HeapFree(GetProcessHeap(), 0, info
->mem
);
2272 /*************************************************************************
2275 * Insert element into an FDSA array
2277 DWORD WINAPI
FDSA_InsertItem(FDSA_info
*info
, DWORD where
, const void *block
)
2279 TRACE("(%p 0x%08x %p)\n", info
, where
, block
);
2280 if(where
> info
->num_items
)
2281 where
= info
->num_items
;
2283 if(info
->num_items
>= info
->blocks_alloced
)
2285 DWORD size
= (info
->blocks_alloced
+ info
->inc
) * info
->block_size
;
2286 if(info
->flags
& 0x1)
2287 info
->mem
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, info
->mem
, size
);
2290 void *old_mem
= info
->mem
;
2291 info
->mem
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
2292 memcpy(info
->mem
, old_mem
, info
->blocks_alloced
* info
->block_size
);
2294 info
->blocks_alloced
+= info
->inc
;
2298 if(where
< info
->num_items
)
2300 memmove((char*)info
->mem
+ (where
+ 1) * info
->block_size
,
2301 (char*)info
->mem
+ where
* info
->block_size
,
2302 (info
->num_items
- where
) * info
->block_size
);
2304 memcpy((char*)info
->mem
+ where
* info
->block_size
, block
, info
->block_size
);
2310 /*************************************************************************
2313 * Delete an element from an FDSA array.
2315 BOOL WINAPI
FDSA_DeleteItem(FDSA_info
*info
, DWORD where
)
2317 TRACE("(%p 0x%08x)\n", info
, where
);
2319 if(where
>= info
->num_items
)
2322 if(where
< info
->num_items
- 1)
2324 memmove((char*)info
->mem
+ where
* info
->block_size
,
2325 (char*)info
->mem
+ (where
+ 1) * info
->block_size
,
2326 (info
->num_items
- where
- 1) * info
->block_size
);
2328 memset((char*)info
->mem
+ (info
->num_items
- 1) * info
->block_size
,
2329 0, info
->block_size
);
2334 /*************************************************************************
2337 * Call IUnknown_QueryInterface() on a table of objects.
2341 * Failure: E_POINTER or E_NOINTERFACE.
2343 HRESULT WINAPI
QISearch(
2344 void *base
, /* [in] Table of interfaces */
2345 const QITAB
*table
, /* [in] Array of REFIIDs and indexes into the table */
2346 REFIID riid
, /* [in] REFIID to get interface for */
2347 void **ppv
) /* [out] Destination for interface pointer */
2353 TRACE("(%p %p %s %p)\n", base
, table
, debugstr_guid(riid
), ppv
);
2356 while (xmove
->piid
) {
2357 TRACE("trying (offset %d) %s\n", xmove
->dwOffset
, debugstr_guid(xmove
->piid
));
2358 if (IsEqualIID(riid
, xmove
->piid
)) {
2359 a_vtbl
= (IUnknown
*)(xmove
->dwOffset
+ (LPBYTE
)base
);
2360 TRACE("matched, returning (%p)\n", a_vtbl
);
2362 IUnknown_AddRef(a_vtbl
);
2368 if (IsEqualIID(riid
, &IID_IUnknown
)) {
2369 a_vtbl
= (IUnknown
*)(table
->dwOffset
+ (LPBYTE
)base
);
2370 TRACE("returning first for IUnknown (%p)\n", a_vtbl
);
2372 IUnknown_AddRef(a_vtbl
);
2376 ret
= E_NOINTERFACE
;
2380 TRACE("-- 0x%08x\n", ret
);
2384 /*************************************************************************
2387 * Set the Font for a window and the "PropDlgFont" property of the parent window.
2390 * hWnd [I] Parent Window to set the property
2391 * id [I] Index of child Window to set the Font
2397 HRESULT WINAPI
SHSetDefaultDialogFont(HWND hWnd
, INT id
)
2399 FIXME("(%p, %d) stub\n", hWnd
, id
);
2403 /*************************************************************************
2406 * Remove the "PropDlgFont" property from a window.
2409 * hWnd [I] Window to remove the property from
2412 * A handle to the removed property, or NULL if it did not exist.
2414 HANDLE WINAPI
SHRemoveDefaultDialogFont(HWND hWnd
)
2418 TRACE("(%p)\n", hWnd
);
2420 hProp
= GetPropA(hWnd
, "PropDlgFont");
2424 DeleteObject(hProp
);
2425 hProp
= RemovePropA(hWnd
, "PropDlgFont");
2430 /*************************************************************************
2433 * Load the in-process server of a given GUID.
2436 * refiid [I] GUID of the server to load.
2439 * Success: A handle to the loaded server dll.
2440 * Failure: A NULL handle.
2442 HMODULE WINAPI
SHPinDllOfCLSID(REFIID refiid
)
2446 CHAR value
[MAX_PATH
], string
[MAX_PATH
];
2448 strcpy(string
, "CLSID\\");
2449 SHStringFromGUIDA(refiid
, string
+ 6, sizeof(string
)/sizeof(char) - 6);
2450 strcat(string
, "\\InProcServer32");
2453 RegOpenKeyExA(HKEY_CLASSES_ROOT
, string
, 0, 1, &newkey
);
2454 RegQueryValueExA(newkey
, 0, 0, &type
, (PBYTE
)value
, &count
);
2455 RegCloseKey(newkey
);
2456 return LoadLibraryExA(value
, 0, 0);
2459 /*************************************************************************
2462 * Unicode version of SHLWAPI_183.
2464 DWORD WINAPI
SHRegisterClassW(WNDCLASSW
* lpWndClass
)
2468 TRACE("(%p %s)\n",lpWndClass
->hInstance
, debugstr_w(lpWndClass
->lpszClassName
));
2470 if (GetClassInfoW(lpWndClass
->hInstance
, lpWndClass
->lpszClassName
, &WndClass
))
2472 return RegisterClassW(lpWndClass
);
2475 /*************************************************************************
2478 * Unregister a list of classes.
2481 * hInst [I] Application instance that registered the classes
2482 * lppClasses [I] List of class names
2483 * iCount [I] Number of names in lppClasses
2488 void WINAPI
SHUnregisterClassesA(HINSTANCE hInst
, LPCSTR
*lppClasses
, INT iCount
)
2492 TRACE("(%p,%p,%d)\n", hInst
, lppClasses
, iCount
);
2496 if (GetClassInfoA(hInst
, *lppClasses
, &WndClass
))
2497 UnregisterClassA(*lppClasses
, hInst
);
2503 /*************************************************************************
2506 * Unicode version of SHUnregisterClassesA.
2508 void WINAPI
SHUnregisterClassesW(HINSTANCE hInst
, LPCWSTR
*lppClasses
, INT iCount
)
2512 TRACE("(%p,%p,%d)\n", hInst
, lppClasses
, iCount
);
2516 if (GetClassInfoW(hInst
, *lppClasses
, &WndClass
))
2517 UnregisterClassW(*lppClasses
, hInst
);
2523 /*************************************************************************
2526 * Call The correct (Ascii/Unicode) default window procedure for a window.
2529 * hWnd [I] Window to call the default procedure for
2530 * uMessage [I] Message ID
2531 * wParam [I] WPARAM of message
2532 * lParam [I] LPARAM of message
2535 * The result of calling DefWindowProcA() or DefWindowProcW().
2537 LRESULT CALLBACK
SHDefWindowProc(HWND hWnd
, UINT uMessage
, WPARAM wParam
, LPARAM lParam
)
2539 if (IsWindowUnicode(hWnd
))
2540 return DefWindowProcW(hWnd
, uMessage
, wParam
, lParam
);
2541 return DefWindowProcA(hWnd
, uMessage
, wParam
, lParam
);
2544 /*************************************************************************
2547 HRESULT WINAPI
IUnknown_GetSite(LPUNKNOWN lpUnknown
, REFIID iid
, PVOID
*lppSite
)
2549 HRESULT hRet
= E_INVALIDARG
;
2550 LPOBJECTWITHSITE lpSite
= NULL
;
2552 TRACE("(%p,%s,%p)\n", lpUnknown
, debugstr_guid(iid
), lppSite
);
2554 if (lpUnknown
&& iid
&& lppSite
)
2556 hRet
= IUnknown_QueryInterface(lpUnknown
, &IID_IObjectWithSite
,
2558 if (SUCCEEDED(hRet
) && lpSite
)
2560 hRet
= IObjectWithSite_GetSite(lpSite
, iid
, lppSite
);
2561 IObjectWithSite_Release(lpSite
);
2567 /*************************************************************************
2570 * Create a worker window using CreateWindowExA().
2573 * wndProc [I] Window procedure
2574 * hWndParent [I] Parent window
2575 * dwExStyle [I] Extra style flags
2576 * dwStyle [I] Style flags
2577 * hMenu [I] Window menu
2578 * wnd_extra [I] Window extra bytes value
2581 * Success: The window handle of the newly created window.
2584 HWND WINAPI
SHCreateWorkerWindowA(WNDPROC wndProc
, HWND hWndParent
, DWORD dwExStyle
,
2585 DWORD dwStyle
, HMENU hMenu
, LONG_PTR wnd_extra
)
2587 static const char szClass
[] = "WorkerA";
2591 TRACE("(%p, %p, 0x%08x, 0x%08x, %p, 0x%08lx)\n",
2592 wndProc
, hWndParent
, dwExStyle
, dwStyle
, hMenu
, wnd_extra
);
2594 /* Create Window class */
2596 wc
.lpfnWndProc
= DefWindowProcA
;
2598 wc
.cbWndExtra
= sizeof(LONG_PTR
);
2599 wc
.hInstance
= shlwapi_hInstance
;
2601 wc
.hCursor
= LoadCursorA(NULL
, (LPSTR
)IDC_ARROW
);
2602 wc
.hbrBackground
= (HBRUSH
)(COLOR_BTNFACE
+ 1);
2603 wc
.lpszMenuName
= NULL
;
2604 wc
.lpszClassName
= szClass
;
2606 SHRegisterClassA(&wc
);
2608 hWnd
= CreateWindowExA(dwExStyle
, szClass
, 0, dwStyle
, 0, 0, 0, 0,
2609 hWndParent
, hMenu
, shlwapi_hInstance
, 0);
2612 SetWindowLongPtrW(hWnd
, 0, wnd_extra
);
2613 if (wndProc
) SetWindowLongPtrA(hWnd
, GWLP_WNDPROC
, (LONG_PTR
)wndProc
);
2619 typedef struct tagPOLICYDATA
2621 DWORD policy
; /* flags value passed to SHRestricted */
2622 LPCWSTR appstr
; /* application str such as "Explorer" */
2623 LPCWSTR keystr
; /* name of the actual registry key / policy */
2624 } POLICYDATA
, *LPPOLICYDATA
;
2626 #define SHELL_NO_POLICY 0xffffffff
2628 /* default shell policy registry key */
2629 static const WCHAR strRegistryPolicyW
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o',
2630 's','o','f','t','\\','W','i','n','d','o','w','s','\\',
2631 'C','u','r','r','e','n','t','V','e','r','s','i','o','n',
2632 '\\','P','o','l','i','c','i','e','s',0};
2634 /*************************************************************************
2637 * Retrieve a policy value from the registry.
2640 * lpSubKey [I] registry key name
2641 * lpSubName [I] subname of registry key
2642 * lpValue [I] value name of registry value
2645 * the value associated with the registry key or 0 if not found
2647 DWORD WINAPI
SHGetRestriction(LPCWSTR lpSubKey
, LPCWSTR lpSubName
, LPCWSTR lpValue
)
2649 DWORD retval
, datsize
= sizeof(retval
);
2653 lpSubKey
= strRegistryPolicyW
;
2655 retval
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, lpSubKey
, &hKey
);
2656 if (retval
!= ERROR_SUCCESS
)
2657 retval
= RegOpenKeyW(HKEY_CURRENT_USER
, lpSubKey
, &hKey
);
2658 if (retval
!= ERROR_SUCCESS
)
2661 SHGetValueW(hKey
, lpSubName
, lpValue
, NULL
, &retval
, &datsize
);
2666 /*************************************************************************
2669 * Helper function to retrieve the possibly cached value for a specific policy
2672 * policy [I] The policy to look for
2673 * initial [I] Main registry key to open, if NULL use default
2674 * polTable [I] Table of known policies, 0 terminated
2675 * polArr [I] Cache array of policy values
2678 * The retrieved policy value or 0 if not successful
2681 * This function is used by the native SHRestricted function to search for the
2682 * policy and cache it once retrieved. The current Wine implementation uses a
2683 * different POLICYDATA structure and implements a similar algorithm adapted to
2686 DWORD WINAPI
SHRestrictionLookup(
2689 LPPOLICYDATA polTable
,
2692 TRACE("(0x%08x %s %p %p)\n", policy
, debugstr_w(initial
), polTable
, polArr
);
2694 if (!polTable
|| !polArr
)
2697 for (;polTable
->policy
; polTable
++, polArr
++)
2699 if (policy
== polTable
->policy
)
2701 /* we have a known policy */
2703 /* check if this policy has been cached */
2704 if (*polArr
== SHELL_NO_POLICY
)
2705 *polArr
= SHGetRestriction(initial
, polTable
->appstr
, polTable
->keystr
);
2709 /* we don't know this policy, return 0 */
2710 TRACE("unknown policy: (%08x)\n", policy
);
2714 /*************************************************************************
2717 * Get an interface from an object.
2720 * Success: S_OK. ppv contains the requested interface.
2721 * Failure: An HRESULT error code.
2724 * This QueryInterface asks the inner object for an interface. In case
2725 * of aggregation this request would be forwarded by the inner to the
2726 * outer object. This function asks the inner object directly for the
2727 * interface circumventing the forwarding to the outer object.
2729 HRESULT WINAPI
SHWeakQueryInterface(
2730 IUnknown
* pUnk
, /* [in] Outer object */
2731 IUnknown
* pInner
, /* [in] Inner object */
2732 IID
* riid
, /* [in] Interface GUID to query for */
2733 LPVOID
* ppv
) /* [out] Destination for queried interface */
2735 HRESULT hret
= E_NOINTERFACE
;
2736 TRACE("(pUnk=%p pInner=%p\n\tIID: %s %p)\n",pUnk
,pInner
,debugstr_guid(riid
), ppv
);
2739 if(pUnk
&& pInner
) {
2740 hret
= IUnknown_QueryInterface(pInner
, riid
, ppv
);
2741 if (SUCCEEDED(hret
)) IUnknown_Release(pUnk
);
2743 TRACE("-- 0x%08x\n", hret
);
2747 /*************************************************************************
2750 * Move a reference from one interface to another.
2753 * lpDest [O] Destination to receive the reference
2754 * lppUnknown [O] Source to give up the reference to lpDest
2759 VOID WINAPI
SHWeakReleaseInterface(IUnknown
*lpDest
, IUnknown
**lppUnknown
)
2761 TRACE("(%p,%p)\n", lpDest
, lppUnknown
);
2766 IUnknown_AddRef(lpDest
);
2767 IUnknown_AtomicRelease(lppUnknown
); /* Release existing interface */
2771 /*************************************************************************
2774 * Convert an ASCII string of a CLSID into a CLSID.
2777 * idstr [I] String representing a CLSID in registry format
2778 * id [O] Destination for the converted CLSID
2781 * Success: TRUE. id contains the converted CLSID.
2784 BOOL WINAPI
GUIDFromStringA(LPCSTR idstr
, CLSID
*id
)
2787 MultiByteToWideChar(CP_ACP
, 0, idstr
, -1, wClsid
, sizeof(wClsid
)/sizeof(WCHAR
));
2788 return SUCCEEDED(CLSIDFromString(wClsid
, id
));
2791 /*************************************************************************
2794 * Unicode version of GUIDFromStringA.
2796 BOOL WINAPI
GUIDFromStringW(LPCWSTR idstr
, CLSID
*id
)
2798 return SUCCEEDED(CLSIDFromString((LPCOLESTR
)idstr
, id
));
2801 /*************************************************************************
2804 * Determine if the browser is integrated into the shell, and set a registry
2811 * 1, If the browser is not integrated.
2812 * 2, If the browser is integrated.
2815 * The key "HKLM\Software\Microsoft\Internet Explorer\IntegratedBrowser" is
2816 * either set to TRUE, or removed depending on whether the browser is deemed
2819 DWORD WINAPI
WhichPlatform(void)
2821 static const char szIntegratedBrowser
[] = "IntegratedBrowser";
2822 static DWORD dwState
= 0;
2824 DWORD dwRet
, dwData
, dwSize
;
2830 /* If shell32 exports DllGetVersion(), the browser is integrated */
2832 hshell32
= LoadLibraryA("shell32.dll");
2835 FARPROC pDllGetVersion
;
2836 pDllGetVersion
= GetProcAddress(hshell32
, "DllGetVersion");
2837 dwState
= pDllGetVersion
? 2 : 1;
2838 FreeLibrary(hshell32
);
2841 /* Set or delete the key accordingly */
2842 dwRet
= RegOpenKeyExA(HKEY_LOCAL_MACHINE
,
2843 "Software\\Microsoft\\Internet Explorer", 0,
2844 KEY_ALL_ACCESS
, &hKey
);
2847 dwRet
= RegQueryValueExA(hKey
, szIntegratedBrowser
, 0, 0,
2848 (LPBYTE
)&dwData
, &dwSize
);
2850 if (!dwRet
&& dwState
== 1)
2852 /* Value exists but browser is not integrated */
2853 RegDeleteValueA(hKey
, szIntegratedBrowser
);
2855 else if (dwRet
&& dwState
== 2)
2857 /* Browser is integrated but value does not exist */
2859 RegSetValueExA(hKey
, szIntegratedBrowser
, 0, REG_DWORD
,
2860 (LPBYTE
)&dwData
, sizeof(dwData
));
2867 /*************************************************************************
2870 * Unicode version of SHCreateWorkerWindowA.
2872 HWND WINAPI
SHCreateWorkerWindowW(WNDPROC wndProc
, HWND hWndParent
, DWORD dwExStyle
,
2873 DWORD dwStyle
, HMENU hMenu
, LONG_PTR wnd_extra
)
2875 static const WCHAR szClass
[] = { 'W', 'o', 'r', 'k', 'e', 'r', 'W', 0 };
2879 TRACE("(%p, %p, 0x%08x, 0x%08x, %p, 0x%08lx)\n",
2880 wndProc
, hWndParent
, dwExStyle
, dwStyle
, hMenu
, wnd_extra
);
2882 /* If our OS is natively ANSI, use the ANSI version */
2883 if (GetVersion() & 0x80000000) /* not NT */
2885 TRACE("fallback to ANSI, ver 0x%08x\n", GetVersion());
2886 return SHCreateWorkerWindowA(wndProc
, hWndParent
, dwExStyle
, dwStyle
, hMenu
, wnd_extra
);
2889 /* Create Window class */
2891 wc
.lpfnWndProc
= DefWindowProcW
;
2893 wc
.cbWndExtra
= sizeof(LONG_PTR
);
2894 wc
.hInstance
= shlwapi_hInstance
;
2896 wc
.hCursor
= LoadCursorW(NULL
, (LPWSTR
)IDC_ARROW
);
2897 wc
.hbrBackground
= (HBRUSH
)(COLOR_BTNFACE
+ 1);
2898 wc
.lpszMenuName
= NULL
;
2899 wc
.lpszClassName
= szClass
;
2901 SHRegisterClassW(&wc
);
2903 hWnd
= CreateWindowExW(dwExStyle
, szClass
, 0, dwStyle
, 0, 0, 0, 0,
2904 hWndParent
, hMenu
, shlwapi_hInstance
, 0);
2907 SetWindowLongPtrW(hWnd
, 0, wnd_extra
);
2908 if (wndProc
) SetWindowLongPtrW(hWnd
, GWLP_WNDPROC
, (LONG_PTR
)wndProc
);
2914 /*************************************************************************
2917 * Get and show a context menu from a shell folder.
2920 * hWnd [I] Window displaying the shell folder
2921 * lpFolder [I] IShellFolder interface
2922 * lpApidl [I] Id for the particular folder desired
2926 * Failure: An HRESULT error code indicating the error.
2928 HRESULT WINAPI
SHInvokeDefaultCommand(HWND hWnd
, IShellFolder
* lpFolder
, LPCITEMIDLIST lpApidl
)
2930 TRACE("%p %p %p\n", hWnd
, lpFolder
, lpApidl
);
2931 return SHInvokeCommand(hWnd
, lpFolder
, lpApidl
, 0);
2934 /*************************************************************************
2937 * _SHPackDispParamsV
2939 HRESULT WINAPI
SHPackDispParamsV(DISPPARAMS
*params
, VARIANTARG
*args
, UINT cnt
, __ms_va_list valist
)
2943 TRACE("(%p %p %u ...)\n", params
, args
, cnt
);
2945 params
->rgvarg
= args
;
2946 params
->rgdispidNamedArgs
= NULL
;
2947 params
->cArgs
= cnt
;
2948 params
->cNamedArgs
= 0;
2952 while(iter
-- > args
) {
2953 V_VT(iter
) = va_arg(valist
, enum VARENUM
);
2955 TRACE("vt=%d\n", V_VT(iter
));
2957 if(V_VT(iter
) & VT_BYREF
) {
2958 V_BYREF(iter
) = va_arg(valist
, LPVOID
);
2960 switch(V_VT(iter
)) {
2962 V_I4(iter
) = va_arg(valist
, LONG
);
2965 V_BSTR(iter
) = va_arg(valist
, BSTR
);
2968 V_DISPATCH(iter
) = va_arg(valist
, IDispatch
*);
2971 V_BOOL(iter
) = va_arg(valist
, int);
2974 V_UNKNOWN(iter
) = va_arg(valist
, IUnknown
*);
2978 V_I4(iter
) = va_arg(valist
, LONG
);
2986 /*************************************************************************
2991 HRESULT WINAPIV
SHPackDispParams(DISPPARAMS
*params
, VARIANTARG
*args
, UINT cnt
, ...)
2993 __ms_va_list valist
;
2996 __ms_va_start(valist
, cnt
);
2997 hres
= SHPackDispParamsV(params
, args
, cnt
, valist
);
2998 __ms_va_end(valist
);
3002 /*************************************************************************
3003 * SHLWAPI_InvokeByIID
3005 * This helper function calls IDispatch::Invoke for each sink
3006 * which implements given iid or IDispatch.
3009 static HRESULT
SHLWAPI_InvokeByIID(
3010 IConnectionPoint
* iCP
,
3013 DISPPARAMS
* dispParams
)
3015 IEnumConnections
*enumerator
;
3017 static DISPPARAMS empty
= {NULL
, NULL
, 0, 0};
3018 DISPPARAMS
* params
= dispParams
;
3020 HRESULT result
= IConnectionPoint_EnumConnections(iCP
, &enumerator
);
3024 /* Invoke is never happening with an NULL dispParams */
3028 while(IEnumConnections_Next(enumerator
, 1, &rgcd
, NULL
)==S_OK
)
3030 IDispatch
*dispIface
;
3031 if ((iid
&& SUCCEEDED(IUnknown_QueryInterface(rgcd
.pUnk
, iid
, (LPVOID
*)&dispIface
))) ||
3032 SUCCEEDED(IUnknown_QueryInterface(rgcd
.pUnk
, &IID_IDispatch
, (LPVOID
*)&dispIface
)))
3034 IDispatch_Invoke(dispIface
, dispId
, &IID_NULL
, 0, DISPATCH_METHOD
, params
, NULL
, NULL
, NULL
);
3035 IDispatch_Release(dispIface
);
3037 IUnknown_Release(rgcd
.pUnk
);
3040 IEnumConnections_Release(enumerator
);
3045 /*************************************************************************
3046 * IConnectionPoint_InvokeWithCancel [SHLWAPI.283]
3048 HRESULT WINAPI
IConnectionPoint_InvokeWithCancel( IConnectionPoint
* iCP
,
3049 DISPID dispId
, DISPPARAMS
* dispParams
,
3050 DWORD unknown1
, DWORD unknown2
)
3055 FIXME("(%p)->(0x%x %p %x %x) partial stub\n", iCP
, dispId
, dispParams
, unknown1
, unknown2
);
3057 result
= IConnectionPoint_GetConnectionInterface(iCP
, &iid
);
3058 if (SUCCEEDED(result
))
3059 result
= SHLWAPI_InvokeByIID(iCP
, &iid
, dispId
, dispParams
);
3061 result
= SHLWAPI_InvokeByIID(iCP
, NULL
, dispId
, dispParams
);
3067 /*************************************************************************
3070 * IConnectionPoint_SimpleInvoke
3072 HRESULT WINAPI
IConnectionPoint_SimpleInvoke(
3073 IConnectionPoint
* iCP
,
3075 DISPPARAMS
* dispParams
)
3080 TRACE("(%p)->(0x%x %p)\n",iCP
,dispId
,dispParams
);
3082 result
= IConnectionPoint_GetConnectionInterface(iCP
, &iid
);
3083 if (SUCCEEDED(result
))
3084 result
= SHLWAPI_InvokeByIID(iCP
, &iid
, dispId
, dispParams
);
3086 result
= SHLWAPI_InvokeByIID(iCP
, NULL
, dispId
, dispParams
);
3091 /*************************************************************************
3094 * Notify an IConnectionPoint object of changes.
3097 * lpCP [I] Object to notify
3102 * Failure: E_NOINTERFACE, if lpCP is NULL or does not support the
3103 * IConnectionPoint interface.
3105 HRESULT WINAPI
IConnectionPoint_OnChanged(IConnectionPoint
* lpCP
, DISPID dispID
)
3107 IEnumConnections
*lpEnum
;
3108 HRESULT hRet
= E_NOINTERFACE
;
3110 TRACE("(%p,0x%8X)\n", lpCP
, dispID
);
3112 /* Get an enumerator for the connections */
3114 hRet
= IConnectionPoint_EnumConnections(lpCP
, &lpEnum
);
3116 if (SUCCEEDED(hRet
))
3118 IPropertyNotifySink
*lpSink
;
3119 CONNECTDATA connData
;
3122 /* Call OnChanged() for every notify sink in the connection point */
3123 while (IEnumConnections_Next(lpEnum
, 1, &connData
, &ulFetched
) == S_OK
)
3125 if (SUCCEEDED(IUnknown_QueryInterface(connData
.pUnk
, &IID_IPropertyNotifySink
, (void**)&lpSink
)) &&
3128 IPropertyNotifySink_OnChanged(lpSink
, dispID
);
3129 IPropertyNotifySink_Release(lpSink
);
3131 IUnknown_Release(connData
.pUnk
);
3134 IEnumConnections_Release(lpEnum
);
3139 /*************************************************************************
3142 * IUnknown_CPContainerInvokeParam
3144 HRESULT WINAPIV
IUnknown_CPContainerInvokeParam(
3145 IUnknown
*container
,
3152 IConnectionPoint
*iCP
;
3153 IConnectionPointContainer
*iCPC
;
3154 DISPPARAMS dispParams
= {buffer
, NULL
, cParams
, 0};
3155 __ms_va_list valist
;
3158 return E_NOINTERFACE
;
3160 result
= IUnknown_QueryInterface(container
, &IID_IConnectionPointContainer
,(LPVOID
*) &iCPC
);
3164 result
= IConnectionPointContainer_FindConnectionPoint(iCPC
, riid
, &iCP
);
3165 IConnectionPointContainer_Release(iCPC
);
3169 __ms_va_start(valist
, cParams
);
3170 SHPackDispParamsV(&dispParams
, buffer
, cParams
, valist
);
3171 __ms_va_end(valist
);
3173 result
= SHLWAPI_InvokeByIID(iCP
, riid
, dispId
, &dispParams
);
3174 IConnectionPoint_Release(iCP
);
3179 /*************************************************************************
3182 * Notify an IConnectionPointContainer object of changes.
3185 * lpUnknown [I] Object to notify
3190 * Failure: E_NOINTERFACE, if lpUnknown is NULL or does not support the
3191 * IConnectionPointContainer interface.
3193 HRESULT WINAPI
IUnknown_CPContainerOnChanged(IUnknown
*lpUnknown
, DISPID dispID
)
3195 IConnectionPointContainer
* lpCPC
= NULL
;
3196 HRESULT hRet
= E_NOINTERFACE
;
3198 TRACE("(%p,0x%8X)\n", lpUnknown
, dispID
);
3201 hRet
= IUnknown_QueryInterface(lpUnknown
, &IID_IConnectionPointContainer
, (void**)&lpCPC
);
3203 if (SUCCEEDED(hRet
))
3205 IConnectionPoint
* lpCP
;
3207 hRet
= IConnectionPointContainer_FindConnectionPoint(lpCPC
, &IID_IPropertyNotifySink
, &lpCP
);
3208 IConnectionPointContainer_Release(lpCPC
);
3210 hRet
= IConnectionPoint_OnChanged(lpCP
, dispID
);
3211 IConnectionPoint_Release(lpCP
);
3216 /*************************************************************************
3221 BOOL WINAPI
PlaySoundWrapW(LPCWSTR pszSound
, HMODULE hmod
, DWORD fdwSound
)
3223 return PlaySoundW(pszSound
, hmod
, fdwSound
);
3226 /*************************************************************************
3229 * Retrieve a key value from an INI file. See GetPrivateProfileString for
3233 * appName [I] The section in the INI file that contains the key
3234 * keyName [I] The key to be retrieved
3235 * out [O] The buffer into which the key's value will be copied
3236 * outLen [I] The length of the `out' buffer
3237 * filename [I] The location of the INI file
3240 * Length of string copied into `out'.
3242 DWORD WINAPI
SHGetIniStringW(LPCWSTR appName
, LPCWSTR keyName
, LPWSTR out
,
3243 DWORD outLen
, LPCWSTR filename
)
3248 TRACE("(%s,%s,%p,%08x,%s)\n", debugstr_w(appName
), debugstr_w(keyName
),
3249 out
, outLen
, debugstr_w(filename
));
3254 buf
= HeapAlloc(GetProcessHeap(), 0, outLen
* sizeof(WCHAR
));
3260 ret
= GetPrivateProfileStringW(appName
, keyName
, NULL
, buf
, outLen
, filename
);
3266 HeapFree(GetProcessHeap(), 0, buf
);
3268 return strlenW(out
);
3271 /*************************************************************************
3274 * Set a key value in an INI file. See WritePrivateProfileString for
3278 * appName [I] The section in the INI file that contains the key
3279 * keyName [I] The key to be set
3280 * str [O] The value of the key
3281 * filename [I] The location of the INI file
3287 BOOL WINAPI
SHSetIniStringW(LPCWSTR appName
, LPCWSTR keyName
, LPCWSTR str
,
3290 TRACE("(%s, %p, %s, %s)\n", debugstr_w(appName
), keyName
, debugstr_w(str
),
3291 debugstr_w(filename
));
3293 return WritePrivateProfileStringW(appName
, keyName
, str
, filename
);
3296 /*************************************************************************
3299 * See SHGetFileInfoW.
3301 DWORD WINAPI
SHGetFileInfoWrapW(LPCWSTR path
, DWORD dwFileAttributes
,
3302 SHFILEINFOW
*psfi
, UINT sizeofpsfi
, UINT flags
)
3304 return SHGetFileInfoW(path
, dwFileAttributes
, psfi
, sizeofpsfi
, flags
);
3307 /*************************************************************************
3310 * See DragQueryFileW.
3312 UINT WINAPI
DragQueryFileWrapW(HDROP hDrop
, UINT lFile
, LPWSTR lpszFile
, UINT lLength
)
3314 return DragQueryFileW(hDrop
, lFile
, lpszFile
, lLength
);
3317 /*************************************************************************
3320 * See SHBrowseForFolderW.
3322 LPITEMIDLIST WINAPI
SHBrowseForFolderWrapW(LPBROWSEINFOW lpBi
)
3324 return SHBrowseForFolderW(lpBi
);