xref: /reactos/dll/win32/shlwapi/ordinal.c (revision b99f0b49)
1 /*
2  * SHLWAPI ordinal functions
3  *
4  * Copyright 1997 Marcus Meissner
5  *           1998 Jürgen Schmied
6  *           2001-2003 Jon Griffiths
7  *
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.
12  *
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.
17  *
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
21  */
22 
23 #include "precomp.h"
24 
25 #include <stdio.h>
26 
27 #include <winver.h>
28 #include <winnetwk.h>
29 #include <mmsystem.h>
30 #include <shdeprecated.h>
31 #include <shellapi.h>
32 #include <commdlg.h>
33 #include <mlang.h>
34 #include <mshtmhst.h>
35 
36 /* DLL handles for late bound calls */
37 extern HINSTANCE shlwapi_hInstance;
38 extern DWORD SHLWAPI_ThreadRef_index;
39 
40 HRESULT WINAPI IUnknown_QueryService(IUnknown*,REFGUID,REFIID,LPVOID*);
41 HRESULT WINAPI SHInvokeCommand(HWND,IShellFolder*,LPCITEMIDLIST,DWORD);
42 BOOL    WINAPI SHAboutInfoW(LPWSTR,DWORD);
43 
44 /*
45  NOTES: Most functions exported by ordinal seem to be superfluous.
46  The reason for these functions to be there is to provide a wrapper
47  for unicode functions to provide these functions on systems without
48  unicode functions eg. win95/win98. Since we have such functions we just
49  call these. If running Wine with native DLLs, some late bound calls may
50  fail. However, it is better to implement the functions in the forward DLL
51  and recommend the builtin rather than reimplementing the calls here!
52 */
53 
54 /*************************************************************************
55  * @   [SHLWAPI.11]
56  *
57  * Copy a sharable memory handle from one process to another.
58  *
59  * PARAMS
60  * hShared     [I] Shared memory handle to duplicate
61  * dwSrcProcId [I] ID of the process owning hShared
62  * dwDstProcId [I] ID of the process wanting the duplicated handle
63  * dwAccess    [I] Desired DuplicateHandle() access
64  * dwOptions   [I] Desired DuplicateHandle() options
65  *
66  * RETURNS
67  * Success: A handle suitable for use by the dwDstProcId process.
68  * Failure: A NULL handle.
69  *
70  */
71 HANDLE WINAPI SHMapHandle(HANDLE hShared, DWORD dwSrcProcId, DWORD dwDstProcId,
72                           DWORD dwAccess, DWORD dwOptions)
73 {
74   HANDLE hDst, hSrc;
75   DWORD dwMyProcId = GetCurrentProcessId();
76   HANDLE hRet = NULL;
77 
78   TRACE("(%p,%d,%d,%08x,%08x)\n", hShared, dwDstProcId, dwSrcProcId,
79         dwAccess, dwOptions);
80 
81   /* Get dest process handle */
82   if (dwDstProcId == dwMyProcId)
83     hDst = GetCurrentProcess();
84   else
85     hDst = OpenProcess(PROCESS_DUP_HANDLE, 0, dwDstProcId);
86 
87   if (hDst)
88   {
89     /* Get src process handle */
90     if (dwSrcProcId == dwMyProcId)
91       hSrc = GetCurrentProcess();
92     else
93       hSrc = OpenProcess(PROCESS_DUP_HANDLE, 0, dwSrcProcId);
94 
95     if (hSrc)
96     {
97       /* Make handle available to dest process */
98       if (!DuplicateHandle(hSrc, hShared, hDst, &hRet,
99                            dwAccess, 0, dwOptions | DUPLICATE_SAME_ACCESS))
100         hRet = NULL;
101 
102       if (dwSrcProcId != dwMyProcId)
103         CloseHandle(hSrc);
104     }
105 
106     if (dwDstProcId != dwMyProcId)
107       CloseHandle(hDst);
108   }
109 
110   TRACE("Returning handle %p\n", hRet);
111   return hRet;
112 }
113 
114 /*************************************************************************
115  * @  [SHLWAPI.7]
116  *
117  * Create a block of sharable memory and initialise it with data.
118  *
119  * PARAMS
120  * lpvData  [I] Pointer to data to write
121  * dwSize   [I] Size of data
122  * dwProcId [I] ID of process owning data
123  *
124  * RETURNS
125  * Success: A shared memory handle
126  * Failure: NULL
127  *
128  * NOTES
129  * Ordinals 7-11 provide a set of calls to create shared memory between a
130  * group of processes. The shared memory is treated opaquely in that its size
131  * is not exposed to clients who map it. This is accomplished by storing
132  * the size of the map as the first DWORD of mapped data, and then offsetting
133  * the view pointer returned by this size.
134  *
135  */
136 HANDLE WINAPI SHAllocShared(LPCVOID lpvData, DWORD dwSize, DWORD dwProcId)
137 {
138   HANDLE hMap;
139   LPVOID pMapped;
140   HANDLE hRet = NULL;
141 
142   TRACE("(%p,%d,%d)\n", lpvData, dwSize, dwProcId);
143 
144   /* Create file mapping of the correct length */
145   hMap = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, FILE_MAP_READ, 0,
146                             dwSize + sizeof(dwSize), NULL);
147   if (!hMap)
148     return hRet;
149 
150   /* Get a view in our process address space */
151   pMapped = MapViewOfFile(hMap, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
152 
153   if (pMapped)
154   {
155     /* Write size of data, followed by the data, to the view */
156     *((DWORD*)pMapped) = dwSize;
157     if (lpvData)
158       memcpy((char *) pMapped + sizeof(dwSize), lpvData, dwSize);
159 
160     /* Release view. All further views mapped will be opaque */
161     UnmapViewOfFile(pMapped);
162     hRet = SHMapHandle(hMap, GetCurrentProcessId(), dwProcId,
163                        FILE_MAP_ALL_ACCESS, DUPLICATE_SAME_ACCESS);
164   }
165 
166   CloseHandle(hMap);
167   return hRet;
168 }
169 
170 /*************************************************************************
171  * @ [SHLWAPI.8]
172  *
173  * Get a pointer to a block of shared memory from a shared memory handle.
174  *
175  * PARAMS
176  * hShared  [I] Shared memory handle
177  * dwProcId [I] ID of process owning hShared
178  *
179  * RETURNS
180  * Success: A pointer to the shared memory
181  * Failure: NULL
182  *
183  */
184 PVOID WINAPI SHLockShared(HANDLE hShared, DWORD dwProcId)
185 {
186   HANDLE hDup;
187   LPVOID pMapped;
188 
189   TRACE("(%p %d)\n", hShared, dwProcId);
190 
191   /* Get handle to shared memory for current process */
192   hDup = SHMapHandle(hShared, dwProcId, GetCurrentProcessId(), FILE_MAP_ALL_ACCESS, 0);
193 
194   /* Get View */
195   pMapped = MapViewOfFile(hDup, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
196   CloseHandle(hDup);
197 
198   if (pMapped)
199     return (char *) pMapped + sizeof(DWORD); /* Hide size */
200   return NULL;
201 }
202 
203 /*************************************************************************
204  * @ [SHLWAPI.9]
205  *
206  * Release a pointer to a block of shared memory.
207  *
208  * PARAMS
209  * lpView [I] Shared memory pointer
210  *
211  * RETURNS
212  * Success: TRUE
213  * Failure: FALSE
214  *
215  */
216 BOOL WINAPI SHUnlockShared(LPVOID lpView)
217 {
218   TRACE("(%p)\n", lpView);
219   return UnmapViewOfFile((char *) lpView - sizeof(DWORD)); /* Include size */
220 }
221 
222 /*************************************************************************
223  * @ [SHLWAPI.10]
224  *
225  * Destroy a block of sharable memory.
226  *
227  * PARAMS
228  * hShared  [I] Shared memory handle
229  * dwProcId [I] ID of process owning hShared
230  *
231  * RETURNS
232  * Success: TRUE
233  * Failure: FALSE
234  *
235  */
236 BOOL WINAPI SHFreeShared(HANDLE hShared, DWORD dwProcId)
237 {
238   HANDLE hClose;
239 
240   TRACE("(%p %d)\n", hShared, dwProcId);
241 
242   if (!hShared)
243     return TRUE;
244 
245   /* Get a copy of the handle for our process, closing the source handle */
246   hClose = SHMapHandle(hShared, dwProcId, GetCurrentProcessId(),
247                        FILE_MAP_ALL_ACCESS,DUPLICATE_CLOSE_SOURCE);
248   /* Close local copy */
249   return CloseHandle(hClose);
250 }
251 
252 /*************************************************************************
253  *      @	[SHLWAPI.13]
254  *
255  * Create and register a clipboard enumerator for a web browser.
256  *
257  * PARAMS
258  *  lpBC      [I] Binding context
259  *  lpUnknown [I] An object exposing the IWebBrowserApp interface
260  *
261  * RETURNS
262  *  Success: S_OK.
263  *  Failure: An HRESULT error code.
264  *
265  * NOTES
266  *  The enumerator is stored as a property of the web browser. If it does not
267  *  yet exist, it is created and set before being registered.
268  */
269 HRESULT WINAPI RegisterDefaultAcceptHeaders(LPBC lpBC, IUnknown *lpUnknown)
270 {
271   static const WCHAR szProperty[] = { '{','D','0','F','C','A','4','2','0',
272       '-','D','3','F','5','-','1','1','C','F', '-','B','2','1','1','-','0',
273       '0','A','A','0','0','4','A','E','8','3','7','}','\0' };
274   BSTR property;
275   IEnumFORMATETC* pIEnumFormatEtc = NULL;
276   VARIANTARG var;
277   HRESULT hr;
278   IWebBrowserApp* pBrowser;
279 
280   TRACE("(%p, %p)\n", lpBC, lpUnknown);
281 
282   hr = IUnknown_QueryService(lpUnknown, &IID_IWebBrowserApp, &IID_IWebBrowserApp, (void**)&pBrowser);
283   if (FAILED(hr))
284     return hr;
285 
286   V_VT(&var) = VT_EMPTY;
287 
288   /* The property we get is the browsers clipboard enumerator */
289   property = SysAllocString(szProperty);
290   hr = IWebBrowserApp_GetProperty(pBrowser, property, &var);
291   SysFreeString(property);
292   if (FAILED(hr)) goto exit;
293 
294   if (V_VT(&var) == VT_EMPTY)
295   {
296     /* Iterate through accepted documents and RegisterClipBoardFormatA() them */
297     char szKeyBuff[128], szValueBuff[128];
298     DWORD dwKeySize, dwValueSize, dwRet = 0, dwCount = 0, dwNumValues, dwType;
299     FORMATETC* formatList, *format;
300     HKEY hDocs;
301 
302     TRACE("Registering formats and creating IEnumFORMATETC instance\n");
303 
304     if (!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\Current"
305                      "Version\\Internet Settings\\Accepted Documents", &hDocs))
306     {
307       hr = E_FAIL;
308       goto exit;
309     }
310 
311     /* Get count of values in key */
312     while (!dwRet)
313     {
314       dwKeySize = sizeof(szKeyBuff);
315       dwRet = RegEnumValueA(hDocs,dwCount,szKeyBuff,&dwKeySize,0,&dwType,0,0);
316       dwCount++;
317     }
318 
319     dwNumValues = dwCount;
320 
321     /* Note: dwCount = number of items + 1; The extra item is the end node */
322     format = formatList = HeapAlloc(GetProcessHeap(), 0, dwCount * sizeof(FORMATETC));
323     if (!formatList)
324     {
325       RegCloseKey(hDocs);
326       hr = E_OUTOFMEMORY;
327       goto exit;
328     }
329 
330     if (dwNumValues > 1)
331     {
332       dwRet = 0;
333       dwCount = 0;
334 
335       dwNumValues--;
336 
337       /* Register clipboard formats for the values and populate format list */
338       while(!dwRet && dwCount < dwNumValues)
339       {
340         dwKeySize = sizeof(szKeyBuff);
341         dwValueSize = sizeof(szValueBuff);
342         dwRet = RegEnumValueA(hDocs, dwCount, szKeyBuff, &dwKeySize, 0, &dwType,
343                               (PBYTE)szValueBuff, &dwValueSize);
344         if (!dwRet)
345         {
346           HeapFree(GetProcessHeap(), 0, formatList);
347           RegCloseKey(hDocs);
348           hr = E_FAIL;
349           goto exit;
350         }
351 
352         format->cfFormat = RegisterClipboardFormatA(szValueBuff);
353         format->ptd = NULL;
354         format->dwAspect = 1;
355         format->lindex = 4;
356         format->tymed = -1;
357 
358         format++;
359         dwCount++;
360       }
361     }
362 
363     RegCloseKey(hDocs);
364 
365     /* Terminate the (maybe empty) list, last entry has a cfFormat of 0 */
366     format->cfFormat = 0;
367     format->ptd = NULL;
368     format->dwAspect = 1;
369     format->lindex = 4;
370     format->tymed = -1;
371 
372     /* Create a clipboard enumerator */
373     hr = CreateFormatEnumerator(dwNumValues, formatList, &pIEnumFormatEtc);
374     HeapFree(GetProcessHeap(), 0, formatList);
375     if (FAILED(hr)) goto exit;
376 
377     /* Set our enumerator as the browsers property */
378     V_VT(&var) = VT_UNKNOWN;
379     V_UNKNOWN(&var) = (IUnknown*)pIEnumFormatEtc;
380 
381     property = SysAllocString(szProperty);
382     hr = IWebBrowserApp_PutProperty(pBrowser, property, var);
383     SysFreeString(property);
384     if (FAILED(hr))
385     {
386        IEnumFORMATETC_Release(pIEnumFormatEtc);
387        goto exit;
388     }
389   }
390 
391   if (V_VT(&var) == VT_UNKNOWN)
392   {
393     /* Our variant is holding the clipboard enumerator */
394     IUnknown* pIUnknown = V_UNKNOWN(&var);
395     IEnumFORMATETC* pClone = NULL;
396 
397     TRACE("Retrieved IEnumFORMATETC property\n");
398 
399     /* Get an IEnumFormatEtc interface from the variants value */
400     pIEnumFormatEtc = NULL;
401     hr = IUnknown_QueryInterface(pIUnknown, &IID_IEnumFORMATETC, (void**)&pIEnumFormatEtc);
402     if (hr == S_OK && pIEnumFormatEtc)
403     {
404       /* Clone and register the enumerator */
405       hr = IEnumFORMATETC_Clone(pIEnumFormatEtc, &pClone);
406       if (hr == S_OK && pClone)
407       {
408         RegisterFormatEnumerator(lpBC, pClone, 0);
409 
410         IEnumFORMATETC_Release(pClone);
411       }
412 
413       IUnknown_Release(pIUnknown);
414     }
415     IUnknown_Release(V_UNKNOWN(&var));
416   }
417 
418 exit:
419   IWebBrowserApp_Release(pBrowser);
420   return hr;
421 }
422 
423 /*************************************************************************
424  *      @	[SHLWAPI.15]
425  *
426  * Get Explorers "AcceptLanguage" setting.
427  *
428  * PARAMS
429  *  langbuf [O] Destination for language string
430  *  buflen  [I] Length of langbuf in characters
431  *          [0] Success: used length of langbuf
432  *
433  * RETURNS
434  *  Success: S_OK.   langbuf is set to the language string found.
435  *  Failure: E_FAIL, If any arguments are invalid, error occurred, or Explorer
436  *           does not contain the setting.
437  *           E_NOT_SUFFICIENT_BUFFER, If the buffer is not big enough
438  */
439 HRESULT WINAPI GetAcceptLanguagesW( LPWSTR langbuf, LPDWORD buflen)
440 {
441     static const WCHAR szkeyW[] = {
442 	'S','o','f','t','w','a','r','e','\\',
443 	'M','i','c','r','o','s','o','f','t','\\',
444 	'I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r','\\',
445 	'I','n','t','e','r','n','a','t','i','o','n','a','l',0};
446     static const WCHAR valueW[] = {
447 	'A','c','c','e','p','t','L','a','n','g','u','a','g','e',0};
448     DWORD mystrlen, mytype;
449     DWORD len;
450     HKEY mykey;
451     LCID mylcid;
452     WCHAR *mystr;
453     LONG lres;
454 
455     TRACE("(%p, %p) *%p: %d\n", langbuf, buflen, buflen, buflen ? *buflen : -1);
456 
457     if(!langbuf || !buflen || !*buflen)
458 	return E_FAIL;
459 
460     mystrlen = (*buflen > 20) ? *buflen : 20 ;
461     len = mystrlen * sizeof(WCHAR);
462     mystr = HeapAlloc(GetProcessHeap(), 0, len);
463     mystr[0] = 0;
464     RegOpenKeyW(HKEY_CURRENT_USER, szkeyW, &mykey);
465     lres = RegQueryValueExW(mykey, valueW, 0, &mytype, (PBYTE)mystr, &len);
466     RegCloseKey(mykey);
467     len = lstrlenW(mystr);
468 
469     if (!lres && (*buflen > len)) {
470         lstrcpyW(langbuf, mystr);
471         *buflen = len;
472         HeapFree(GetProcessHeap(), 0, mystr);
473         return S_OK;
474     }
475 
476     /* Did not find a value in the registry or the user buffer is too small */
477     mylcid = GetUserDefaultLCID();
478     LcidToRfc1766W(mylcid, mystr, mystrlen);
479     len = lstrlenW(mystr);
480 
481     memcpy( langbuf, mystr, min(*buflen, len+1)*sizeof(WCHAR) );
482     HeapFree(GetProcessHeap(), 0, mystr);
483 
484     if (*buflen > len) {
485         *buflen = len;
486         return S_OK;
487     }
488 
489     *buflen = 0;
490     return E_NOT_SUFFICIENT_BUFFER;
491 }
492 
493 /*************************************************************************
494  *      @	[SHLWAPI.14]
495  *
496  * Ascii version of GetAcceptLanguagesW.
497  */
498 HRESULT WINAPI GetAcceptLanguagesA( LPSTR langbuf, LPDWORD buflen)
499 {
500     WCHAR *langbufW;
501     DWORD buflenW, convlen;
502     HRESULT retval;
503 
504     TRACE("(%p, %p) *%p: %d\n", langbuf, buflen, buflen, buflen ? *buflen : -1);
505 
506     if(!langbuf || !buflen || !*buflen) return E_FAIL;
507 
508     buflenW = *buflen;
509     langbufW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * buflenW);
510     retval = GetAcceptLanguagesW(langbufW, &buflenW);
511 
512     if (retval == S_OK)
513     {
514         convlen = WideCharToMultiByte(CP_ACP, 0, langbufW, -1, langbuf, *buflen, NULL, NULL);
515         convlen--;  /* do not count the terminating 0 */
516     }
517     else  /* copy partial string anyway */
518     {
519         convlen = WideCharToMultiByte(CP_ACP, 0, langbufW, *buflen, langbuf, *buflen, NULL, NULL);
520         if (convlen < *buflen)
521         {
522             langbuf[convlen] = 0;
523             convlen--;  /* do not count the terminating 0 */
524         }
525         else
526         {
527             convlen = *buflen;
528         }
529     }
530     *buflen = buflenW ? convlen : 0;
531 
532     HeapFree(GetProcessHeap(), 0, langbufW);
533     return retval;
534 }
535 
536 /*************************************************************************
537  *      @	[SHLWAPI.23]
538  *
539  * Convert a GUID to a string.
540  *
541  * PARAMS
542  *  guid     [I] GUID to convert
543  *  lpszDest [O] Destination for string
544  *  cchMax   [I] Length of output buffer
545  *
546  * RETURNS
547  *  The length of the string created.
548  */
549 INT WINAPI SHStringFromGUIDA(REFGUID guid, LPSTR lpszDest, INT cchMax)
550 {
551   char xguid[40];
552   INT iLen;
553 
554   TRACE("(%s,%p,%d)\n", debugstr_guid(guid), lpszDest, cchMax);
555 
556   sprintf(xguid, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
557           guid->Data1, guid->Data2, guid->Data3,
558           guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
559           guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
560 
561   iLen = strlen(xguid) + 1;
562 
563   if (iLen > cchMax)
564     return 0;
565   memcpy(lpszDest, xguid, iLen);
566   return iLen;
567 }
568 
569 /*************************************************************************
570  *      @	[SHLWAPI.24]
571  *
572  * Convert a GUID to a string.
573  *
574  * PARAMS
575  *  guid [I] GUID to convert
576  *  str  [O] Destination for string
577  *  cmax [I] Length of output buffer
578  *
579  * RETURNS
580  *  The length of the string created.
581  */
582 INT WINAPI SHStringFromGUIDW(REFGUID guid, LPWSTR lpszDest, INT cchMax)
583 {
584   WCHAR xguid[40];
585   INT iLen;
586   static const WCHAR wszFormat[] = {'{','%','0','8','l','X','-','%','0','4','X','-','%','0','4','X','-',
587       '%','0','2','X','%','0','2','X','-','%','0','2','X','%','0','2','X','%','0','2','X','%','0','2',
588       'X','%','0','2','X','%','0','2','X','}',0};
589 
590   TRACE("(%s,%p,%d)\n", debugstr_guid(guid), lpszDest, cchMax);
591 
592   sprintfW(xguid, wszFormat, guid->Data1, guid->Data2, guid->Data3,
593           guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
594           guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
595 
596   iLen = strlenW(xguid) + 1;
597 
598   if (iLen > cchMax)
599     return 0;
600   memcpy(lpszDest, xguid, iLen*sizeof(WCHAR));
601   return iLen;
602 }
603 
604 /*************************************************************************
605  *      @	[SHLWAPI.30]
606  *
607  * Determine if a Unicode character is a blank.
608  *
609  * PARAMS
610  *  wc [I] Character to check.
611  *
612  * RETURNS
613  *  TRUE, if wc is a blank,
614  *  FALSE otherwise.
615  *
616  */
617 BOOL WINAPI IsCharBlankW(WCHAR wc)
618 {
619     WORD CharType;
620 
621     return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_BLANK);
622 }
623 
624 /*************************************************************************
625  *      @	[SHLWAPI.31]
626  *
627  * Determine if a Unicode character is punctuation.
628  *
629  * PARAMS
630  *  wc [I] Character to check.
631  *
632  * RETURNS
633  *  TRUE, if wc is punctuation,
634  *  FALSE otherwise.
635  */
636 BOOL WINAPI IsCharPunctW(WCHAR wc)
637 {
638     WORD CharType;
639 
640     return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_PUNCT);
641 }
642 
643 /*************************************************************************
644  *      @	[SHLWAPI.32]
645  *
646  * Determine if a Unicode character is a control character.
647  *
648  * PARAMS
649  *  wc [I] Character to check.
650  *
651  * RETURNS
652  *  TRUE, if wc is a control character,
653  *  FALSE otherwise.
654  */
655 BOOL WINAPI IsCharCntrlW(WCHAR wc)
656 {
657     WORD CharType;
658 
659     return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_CNTRL);
660 }
661 
662 /*************************************************************************
663  *      @	[SHLWAPI.33]
664  *
665  * Determine if a Unicode character is a digit.
666  *
667  * PARAMS
668  *  wc [I] Character to check.
669  *
670  * RETURNS
671  *  TRUE, if wc is a digit,
672  *  FALSE otherwise.
673  */
674 BOOL WINAPI IsCharDigitW(WCHAR wc)
675 {
676     WORD CharType;
677 
678     return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_DIGIT);
679 }
680 
681 /*************************************************************************
682  *      @	[SHLWAPI.34]
683  *
684  * Determine if a Unicode character is a hex digit.
685  *
686  * PARAMS
687  *  wc [I] Character to check.
688  *
689  * RETURNS
690  *  TRUE, if wc is a hex digit,
691  *  FALSE otherwise.
692  */
693 BOOL WINAPI IsCharXDigitW(WCHAR wc)
694 {
695     WORD CharType;
696 
697     return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_XDIGIT);
698 }
699 
700 /*************************************************************************
701  *      @	[SHLWAPI.35]
702  *
703  */
704 BOOL WINAPI GetStringType3ExW(LPWSTR src, INT count, LPWORD type)
705 {
706     return GetStringTypeW(CT_CTYPE3, src, count, type);
707 }
708 
709 /*************************************************************************
710  *      @	[SHLWAPI.151]
711  *
712  * Compare two Ascii strings up to a given length.
713  *
714  * PARAMS
715  *  lpszSrc [I] Source string
716  *  lpszCmp [I] String to compare to lpszSrc
717  *  len     [I] Maximum length
718  *
719  * RETURNS
720  *  A number greater than, less than or equal to 0 depending on whether
721  *  lpszSrc is greater than, less than or equal to lpszCmp.
722  */
723 DWORD WINAPI StrCmpNCA(LPCSTR lpszSrc, LPCSTR lpszCmp, INT len)
724 {
725     return StrCmpNA(lpszSrc, lpszCmp, len);
726 }
727 
728 /*************************************************************************
729  *      @	[SHLWAPI.152]
730  *
731  * Unicode version of StrCmpNCA.
732  */
733 DWORD WINAPI StrCmpNCW(LPCWSTR lpszSrc, LPCWSTR lpszCmp, INT len)
734 {
735     return StrCmpNW(lpszSrc, lpszCmp, len);
736 }
737 
738 /*************************************************************************
739  *      @	[SHLWAPI.153]
740  *
741  * Compare two Ascii strings up to a given length, ignoring case.
742  *
743  * PARAMS
744  *  lpszSrc [I] Source string
745  *  lpszCmp [I] String to compare to lpszSrc
746  *  len     [I] Maximum length
747  *
748  * RETURNS
749  *  A number greater than, less than or equal to 0 depending on whether
750  *  lpszSrc is greater than, less than or equal to lpszCmp.
751  */
752 DWORD WINAPI StrCmpNICA(LPCSTR lpszSrc, LPCSTR lpszCmp, DWORD len)
753 {
754     return StrCmpNIA(lpszSrc, lpszCmp, len);
755 }
756 
757 /*************************************************************************
758  *      @	[SHLWAPI.154]
759  *
760  * Unicode version of StrCmpNICA.
761  */
762 DWORD WINAPI StrCmpNICW(LPCWSTR lpszSrc, LPCWSTR lpszCmp, DWORD len)
763 {
764     return StrCmpNIW(lpszSrc, lpszCmp, len);
765 }
766 
767 /*************************************************************************
768  *      @	[SHLWAPI.155]
769  *
770  * Compare two Ascii strings.
771  *
772  * PARAMS
773  *  lpszSrc [I] Source string
774  *  lpszCmp [I] String to compare to lpszSrc
775  *
776  * RETURNS
777  *  A number greater than, less than or equal to 0 depending on whether
778  *  lpszSrc is greater than, less than or equal to lpszCmp.
779  */
780 DWORD WINAPI StrCmpCA(LPCSTR lpszSrc, LPCSTR lpszCmp)
781 {
782     return lstrcmpA(lpszSrc, lpszCmp);
783 }
784 
785 /*************************************************************************
786  *      @	[SHLWAPI.156]
787  *
788  * Unicode version of StrCmpCA.
789  */
790 DWORD WINAPI StrCmpCW(LPCWSTR lpszSrc, LPCWSTR lpszCmp)
791 {
792     return lstrcmpW(lpszSrc, lpszCmp);
793 }
794 
795 /*************************************************************************
796  *      @	[SHLWAPI.157]
797  *
798  * Compare two Ascii strings, ignoring case.
799  *
800  * PARAMS
801  *  lpszSrc [I] Source string
802  *  lpszCmp [I] String to compare to lpszSrc
803  *
804  * RETURNS
805  *  A number greater than, less than or equal to 0 depending on whether
806  *  lpszSrc is greater than, less than or equal to lpszCmp.
807  */
808 DWORD WINAPI StrCmpICA(LPCSTR lpszSrc, LPCSTR lpszCmp)
809 {
810     return lstrcmpiA(lpszSrc, lpszCmp);
811 }
812 
813 /*************************************************************************
814  *      @	[SHLWAPI.158]
815  *
816  * Unicode version of StrCmpICA.
817  */
818 DWORD WINAPI StrCmpICW(LPCWSTR lpszSrc, LPCWSTR lpszCmp)
819 {
820     return lstrcmpiW(lpszSrc, lpszCmp);
821 }
822 
823 /*************************************************************************
824  *      @	[SHLWAPI.160]
825  *
826  * Get an identification string for the OS and explorer.
827  *
828  * PARAMS
829  *  lpszDest  [O] Destination for Id string
830  *  dwDestLen [I] Length of lpszDest
831  *
832  * RETURNS
833  *  TRUE,  If the string was created successfully
834  *  FALSE, Otherwise
835  */
836 BOOL WINAPI SHAboutInfoA(LPSTR lpszDest, DWORD dwDestLen)
837 {
838   WCHAR buff[2084];
839 
840   TRACE("(%p,%d)\n", lpszDest, dwDestLen);
841 
842   if (lpszDest && SHAboutInfoW(buff, dwDestLen))
843   {
844     WideCharToMultiByte(CP_ACP, 0, buff, -1, lpszDest, dwDestLen, NULL, NULL);
845     return TRUE;
846   }
847   return FALSE;
848 }
849 
850 /*************************************************************************
851  *      @	[SHLWAPI.161]
852  *
853  * Unicode version of SHAboutInfoA.
854  */
855 BOOL WINAPI SHAboutInfoW(LPWSTR lpszDest, DWORD dwDestLen)
856 {
857   static const WCHAR szIEKey[] = { 'S','O','F','T','W','A','R','E','\\',
858     'M','i','c','r','o','s','o','f','t','\\','I','n','t','e','r','n','e','t',
859     ' ','E','x','p','l','o','r','e','r','\0' };
860   static const WCHAR szWinNtKey[] = { 'S','O','F','T','W','A','R','E','\\',
861     'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s',' ',
862     'N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\0' };
863   static const WCHAR szWinKey[] = { 'S','O','F','T','W','A','R','E','\\',
864     'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
865     'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\0' };
866   static const WCHAR szRegKey[] = { 'S','O','F','T','W','A','R','E','\\',
867     'M','i','c','r','o','s','o','f','t','\\','I','n','t','e','r','n','e','t',
868     ' ','E','x','p','l','o','r','e','r','\\',
869     'R','e','g','i','s','t','r','a','t','i','o','n','\0' };
870   static const WCHAR szVersion[] = { 'V','e','r','s','i','o','n','\0' };
871   static const WCHAR szCustomized[] = { 'C','u','s','t','o','m','i','z','e','d',
872     'V','e','r','s','i','o','n','\0' };
873   static const WCHAR szOwner[] = { 'R','e','g','i','s','t','e','r','e','d',
874     'O','w','n','e','r','\0' };
875   static const WCHAR szOrg[] = { 'R','e','g','i','s','t','e','r','e','d',
876     'O','r','g','a','n','i','z','a','t','i','o','n','\0' };
877   static const WCHAR szProduct[] = { 'P','r','o','d','u','c','t','I','d','\0' };
878   static const WCHAR szUpdate[] = { 'I','E','A','K',
879     'U','p','d','a','t','e','U','r','l','\0' };
880   static const WCHAR szHelp[] = { 'I','E','A','K',
881     'H','e','l','p','S','t','r','i','n','g','\0' };
882   WCHAR buff[2084];
883   HKEY hReg;
884   DWORD dwType, dwLen;
885 
886   TRACE("(%p,%d)\n", lpszDest, dwDestLen);
887 
888   if (!lpszDest)
889     return FALSE;
890 
891   *lpszDest = '\0';
892 
893   /* Try the NT key first, followed by 95/98 key */
894   if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szWinNtKey, 0, KEY_READ, &hReg) &&
895       RegOpenKeyExW(HKEY_LOCAL_MACHINE, szWinKey, 0, KEY_READ, &hReg))
896     return FALSE;
897 
898   /* OS Version */
899   buff[0] = '\0';
900   dwLen = 30;
901   if (!SHGetValueW(HKEY_LOCAL_MACHINE, szIEKey, szVersion, &dwType, buff, &dwLen))
902   {
903     DWORD dwStrLen = strlenW(buff);
904     dwLen = 30 - dwStrLen;
905     SHGetValueW(HKEY_LOCAL_MACHINE, szIEKey,
906                 szCustomized, &dwType, buff+dwStrLen, &dwLen);
907   }
908   StrCatBuffW(lpszDest, buff, dwDestLen);
909 
910   /* ~Registered Owner */
911   buff[0] = '~';
912   dwLen = 256;
913   if (SHGetValueW(hReg, szOwner, 0, &dwType, buff+1, &dwLen))
914     buff[1] = '\0';
915   StrCatBuffW(lpszDest, buff, dwDestLen);
916 
917   /* ~Registered Organization */
918   dwLen = 256;
919   if (SHGetValueW(hReg, szOrg, 0, &dwType, buff+1, &dwLen))
920     buff[1] = '\0';
921   StrCatBuffW(lpszDest, buff, dwDestLen);
922 
923   /* FIXME: Not sure where this number comes from  */
924   buff[0] = '~';
925   buff[1] = '0';
926   buff[2] = '\0';
927   StrCatBuffW(lpszDest, buff, dwDestLen);
928 
929   /* ~Product Id */
930   dwLen = 256;
931   if (SHGetValueW(HKEY_LOCAL_MACHINE, szRegKey, szProduct, &dwType, buff+1, &dwLen))
932     buff[1] = '\0';
933   StrCatBuffW(lpszDest, buff, dwDestLen);
934 
935   /* ~IE Update Url */
936   dwLen = 2048;
937   if(SHGetValueW(HKEY_LOCAL_MACHINE, szWinKey, szUpdate, &dwType, buff+1, &dwLen))
938     buff[1] = '\0';
939   StrCatBuffW(lpszDest, buff, dwDestLen);
940 
941   /* ~IE Help String */
942   dwLen = 256;
943   if(SHGetValueW(hReg, szHelp, 0, &dwType, buff+1, &dwLen))
944     buff[1] = '\0';
945   StrCatBuffW(lpszDest, buff, dwDestLen);
946 
947   RegCloseKey(hReg);
948   return TRUE;
949 }
950 
951 /*************************************************************************
952  *      @	[SHLWAPI.163]
953  *
954  * Call IOleCommandTarget_QueryStatus() on an object.
955  *
956  * PARAMS
957  *  lpUnknown     [I] Object supporting the IOleCommandTarget interface
958  *  pguidCmdGroup [I] GUID for the command group
959  *  cCmds         [I]
960  *  prgCmds       [O] Commands
961  *  pCmdText      [O] Command text
962  *
963  * RETURNS
964  *  Success: S_OK.
965  *  Failure: E_FAIL, if lpUnknown is NULL.
966  *           E_NOINTERFACE, if lpUnknown does not support IOleCommandTarget.
967  *           Otherwise, an error code from IOleCommandTarget_QueryStatus().
968  */
969 HRESULT WINAPI IUnknown_QueryStatus(IUnknown* lpUnknown, REFGUID pguidCmdGroup,
970                            ULONG cCmds, OLECMD *prgCmds, OLECMDTEXT* pCmdText)
971 {
972   HRESULT hRet = E_FAIL;
973 
974   TRACE("(%p,%p,%d,%p,%p)\n",lpUnknown, pguidCmdGroup, cCmds, prgCmds, pCmdText);
975 
976   if (lpUnknown)
977   {
978     IOleCommandTarget* lpOle;
979 
980     hRet = IUnknown_QueryInterface(lpUnknown, &IID_IOleCommandTarget,
981                                    (void**)&lpOle);
982 
983     if (SUCCEEDED(hRet) && lpOle)
984     {
985       hRet = IOleCommandTarget_QueryStatus(lpOle, pguidCmdGroup, cCmds,
986                                            prgCmds, pCmdText);
987       IOleCommandTarget_Release(lpOle);
988     }
989   }
990   return hRet;
991 }
992 
993 /*************************************************************************
994  *      @		[SHLWAPI.164]
995  *
996  * Call IOleCommandTarget_Exec() on an object.
997  *
998  * PARAMS
999  *  lpUnknown     [I] Object supporting the IOleCommandTarget interface
1000  *  pguidCmdGroup [I] GUID for the command group
1001  *
1002  * RETURNS
1003  *  Success: S_OK.
1004  *  Failure: E_FAIL, if lpUnknown is NULL.
1005  *           E_NOINTERFACE, if lpUnknown does not support IOleCommandTarget.
1006  *           Otherwise, an error code from IOleCommandTarget_Exec().
1007  */
1008 HRESULT WINAPI IUnknown_Exec(IUnknown* lpUnknown, REFGUID pguidCmdGroup,
1009                            DWORD nCmdID, DWORD nCmdexecopt, VARIANT* pvaIn,
1010                            VARIANT* pvaOut)
1011 {
1012   HRESULT hRet = E_FAIL;
1013 
1014   TRACE("(%p,%p,%d,%d,%p,%p)\n",lpUnknown, pguidCmdGroup, nCmdID,
1015         nCmdexecopt, pvaIn, pvaOut);
1016 
1017   if (lpUnknown)
1018   {
1019     IOleCommandTarget* lpOle;
1020 
1021     hRet = IUnknown_QueryInterface(lpUnknown, &IID_IOleCommandTarget,
1022                                    (void**)&lpOle);
1023     if (SUCCEEDED(hRet) && lpOle)
1024     {
1025       hRet = IOleCommandTarget_Exec(lpOle, pguidCmdGroup, nCmdID,
1026                                     nCmdexecopt, pvaIn, pvaOut);
1027       IOleCommandTarget_Release(lpOle);
1028     }
1029   }
1030   return hRet;
1031 }
1032 
1033 /*************************************************************************
1034  *      @	[SHLWAPI.165]
1035  *
1036  * Retrieve, modify, and re-set a value from a window.
1037  *
1038  * PARAMS
1039  *  hWnd   [I] Window to get value from
1040  *  offset [I] Offset of value
1041  *  mask   [I] Mask for flags
1042  *  flags  [I] Bits to set in window value
1043  *
1044  * RETURNS
1045  *  The new value as it was set, or 0 if any parameter is invalid.
1046  *
1047  * NOTES
1048  *  Only bits specified in mask are affected - set if present in flags and
1049  *  reset otherwise.
1050  */
1051 LONG WINAPI SHSetWindowBits(HWND hwnd, INT offset, UINT mask, UINT flags)
1052 {
1053   LONG ret = GetWindowLongW(hwnd, offset);
1054   LONG new_flags = (flags & mask) | (ret & ~mask);
1055 
1056   TRACE("%p %d %x %x\n", hwnd, offset, mask, flags);
1057 
1058   if (new_flags != ret)
1059     ret = SetWindowLongW(hwnd, offset, new_flags);
1060   return ret;
1061 }
1062 
1063 /*************************************************************************
1064  *      @	[SHLWAPI.167]
1065  *
1066  * Change a window's parent.
1067  *
1068  * PARAMS
1069  *  hWnd       [I] Window to change parent of
1070  *  hWndParent [I] New parent window
1071  *
1072  * RETURNS
1073  *  The old parent of hWnd.
1074  *
1075  * NOTES
1076  *  If hWndParent is NULL (desktop), the window style is changed to WS_POPUP.
1077  *  If hWndParent is NOT NULL then we set the WS_CHILD style.
1078  */
1079 HWND WINAPI SHSetParentHwnd(HWND hWnd, HWND hWndParent)
1080 {
1081   TRACE("%p, %p\n", hWnd, hWndParent);
1082 
1083   if(GetParent(hWnd) == hWndParent)
1084     return NULL;
1085 
1086   if(hWndParent)
1087     SHSetWindowBits(hWnd, GWL_STYLE, WS_CHILD | WS_POPUP, WS_CHILD);
1088   else
1089     SHSetWindowBits(hWnd, GWL_STYLE, WS_CHILD | WS_POPUP, WS_POPUP);
1090 
1091   return hWndParent ? SetParent(hWnd, hWndParent) : NULL;
1092 }
1093 
1094 /*************************************************************************
1095  *      @       [SHLWAPI.168]
1096  *
1097  * Locate and advise a connection point in an IConnectionPointContainer object.
1098  *
1099  * PARAMS
1100  *  lpUnkSink   [I] Sink for the connection point advise call
1101  *  riid        [I] REFIID of connection point to advise
1102  *  fConnect    [I] TRUE = Connection being establisted, FALSE = broken
1103  *  lpUnknown   [I] Object supporting the IConnectionPointContainer interface
1104  *  lpCookie    [O] Pointer to connection point cookie
1105  *  lppCP       [O] Destination for the IConnectionPoint found
1106  *
1107  * RETURNS
1108  *  Success: S_OK. If lppCP is non-NULL, it is filled with the IConnectionPoint
1109  *           that was advised. The caller is responsible for releasing it.
1110  *  Failure: E_FAIL, if any arguments are invalid.
1111  *           E_NOINTERFACE, if lpUnknown isn't an IConnectionPointContainer,
1112  *           Or an HRESULT error code if any call fails.
1113  */
1114 HRESULT WINAPI ConnectToConnectionPoint(IUnknown* lpUnkSink, REFIID riid, BOOL fConnect,
1115                            IUnknown* lpUnknown, LPDWORD lpCookie,
1116                            IConnectionPoint **lppCP)
1117 {
1118   HRESULT hRet;
1119   IConnectionPointContainer* lpContainer;
1120   IConnectionPoint *lpCP;
1121 
1122   if(!lpUnknown || (fConnect && !lpUnkSink))
1123     return E_FAIL;
1124 
1125   if(lppCP)
1126     *lppCP = NULL;
1127 
1128   hRet = IUnknown_QueryInterface(lpUnknown, &IID_IConnectionPointContainer,
1129                                  (void**)&lpContainer);
1130   if (SUCCEEDED(hRet))
1131   {
1132     hRet = IConnectionPointContainer_FindConnectionPoint(lpContainer, riid, &lpCP);
1133 
1134     if (SUCCEEDED(hRet))
1135     {
1136       if(!fConnect)
1137         hRet = IConnectionPoint_Unadvise(lpCP, *lpCookie);
1138       else
1139         hRet = IConnectionPoint_Advise(lpCP, lpUnkSink, lpCookie);
1140 
1141       if (FAILED(hRet))
1142         *lpCookie = 0;
1143 
1144       if (lppCP && SUCCEEDED(hRet))
1145         *lppCP = lpCP; /* Caller keeps the interface */
1146       else
1147         IConnectionPoint_Release(lpCP); /* Release it */
1148     }
1149 
1150     IConnectionPointContainer_Release(lpContainer);
1151   }
1152   return hRet;
1153 }
1154 
1155 /*************************************************************************
1156  *	@	[SHLWAPI.169]
1157  *
1158  * Release an interface and zero a supplied pointer.
1159  *
1160  * PARAMS
1161  *  lpUnknown [I] Object to release
1162  *
1163  * RETURNS
1164  *  Nothing.
1165  */
1166 void WINAPI IUnknown_AtomicRelease(IUnknown ** lpUnknown)
1167 {
1168     TRACE("(%p)\n", lpUnknown);
1169 
1170     if(!lpUnknown || !*lpUnknown) return;
1171 
1172     TRACE("doing Release\n");
1173 
1174     IUnknown_Release(*lpUnknown);
1175     *lpUnknown = NULL;
1176 }
1177 
1178 /*************************************************************************
1179  *      @	[SHLWAPI.170]
1180  *
1181  * Skip '//' if present in a string.
1182  *
1183  * PARAMS
1184  *  lpszSrc [I] String to check for '//'
1185  *
1186  * RETURNS
1187  *  Success: The next character after the '//' or the string if not present
1188  *  Failure: NULL, if lpszStr is NULL.
1189  */
1190 LPCSTR WINAPI PathSkipLeadingSlashesA(LPCSTR lpszSrc)
1191 {
1192   if (lpszSrc && lpszSrc[0] == '/' && lpszSrc[1] == '/')
1193     lpszSrc += 2;
1194   return lpszSrc;
1195 }
1196 
1197 /*************************************************************************
1198  *      @		[SHLWAPI.171]
1199  *
1200  * Check if two interfaces come from the same object.
1201  *
1202  * PARAMS
1203  *   lpInt1 [I] Interface to check against lpInt2.
1204  *   lpInt2 [I] Interface to check against lpInt1.
1205  *
1206  * RETURNS
1207  *   TRUE, If the interfaces come from the same object.
1208  *   FALSE Otherwise.
1209  */
1210 BOOL WINAPI SHIsSameObject(IUnknown* lpInt1, IUnknown* lpInt2)
1211 {
1212   IUnknown *lpUnknown1, *lpUnknown2;
1213   BOOL ret;
1214 
1215   TRACE("(%p %p)\n", lpInt1, lpInt2);
1216 
1217   if (!lpInt1 || !lpInt2)
1218     return FALSE;
1219 
1220   if (lpInt1 == lpInt2)
1221     return TRUE;
1222 
1223   if (IUnknown_QueryInterface(lpInt1, &IID_IUnknown, (void**)&lpUnknown1) != S_OK)
1224     return FALSE;
1225 
1226   if (IUnknown_QueryInterface(lpInt2, &IID_IUnknown, (void**)&lpUnknown2) != S_OK)
1227   {
1228     IUnknown_Release(lpUnknown1);
1229     return FALSE;
1230   }
1231 
1232   ret = lpUnknown1 == lpUnknown2;
1233 
1234   IUnknown_Release(lpUnknown1);
1235   IUnknown_Release(lpUnknown2);
1236 
1237   return ret;
1238 }
1239 
1240 /*************************************************************************
1241  *      @	[SHLWAPI.172]
1242  *
1243  * Get the window handle of an object.
1244  *
1245  * PARAMS
1246  *  lpUnknown [I] Object to get the window handle of
1247  *  lphWnd    [O] Destination for window handle
1248  *
1249  * RETURNS
1250  *  Success: S_OK. lphWnd contains the objects window handle.
1251  *  Failure: An HRESULT error code.
1252  *
1253  * NOTES
1254  *  lpUnknown is expected to support one of the following interfaces:
1255  *  IOleWindow(), IInternetSecurityMgrSite(), or IShellView().
1256  */
1257 HRESULT WINAPI IUnknown_GetWindow(IUnknown *lpUnknown, HWND *lphWnd)
1258 {
1259   IUnknown *lpOle;
1260   HRESULT hRet = E_FAIL;
1261 
1262   TRACE("(%p,%p)\n", lpUnknown, lphWnd);
1263 
1264   if (!lpUnknown)
1265     return hRet;
1266 
1267   hRet = IUnknown_QueryInterface(lpUnknown, &IID_IOleWindow, (void**)&lpOle);
1268 
1269   if (FAILED(hRet))
1270   {
1271     hRet = IUnknown_QueryInterface(lpUnknown,&IID_IShellView, (void**)&lpOle);
1272 
1273     if (FAILED(hRet))
1274     {
1275       hRet = IUnknown_QueryInterface(lpUnknown, &IID_IInternetSecurityMgrSite,
1276                                       (void**)&lpOle);
1277     }
1278   }
1279 
1280   if (SUCCEEDED(hRet))
1281   {
1282     /* Laziness here - Since GetWindow() is the first method for the above 3
1283      * interfaces, we use the same call for them all.
1284      */
1285     hRet = IOleWindow_GetWindow((IOleWindow*)lpOle, lphWnd);
1286     IUnknown_Release(lpOle);
1287     if (lphWnd)
1288       TRACE("Returning HWND=%p\n", *lphWnd);
1289   }
1290 
1291   return hRet;
1292 }
1293 
1294 /*************************************************************************
1295  *      @	[SHLWAPI.173]
1296  *
1297  * Call a SetOwner method of IShellService from specified object.
1298  *
1299  * PARAMS
1300  *  iface [I] Object that supports IShellService
1301  *  pUnk  [I] Argument for the SetOwner call
1302  *
1303  * RETURNS
1304  *  Corresponding return value from last call or E_FAIL for null input
1305  */
1306 HRESULT WINAPI IUnknown_SetOwner(IUnknown *iface, IUnknown *pUnk)
1307 {
1308   IShellService *service;
1309   HRESULT hr;
1310 
1311   TRACE("(%p, %p)\n", iface, pUnk);
1312 
1313   if (!iface) return E_FAIL;
1314 
1315   hr = IUnknown_QueryInterface(iface, &IID_IShellService, (void**)&service);
1316   if (hr == S_OK)
1317   {
1318     hr = IShellService_SetOwner(service, pUnk);
1319     IShellService_Release(service);
1320   }
1321 
1322   return hr;
1323 }
1324 
1325 /*************************************************************************
1326  *      @	[SHLWAPI.174]
1327  *
1328  * Call either IObjectWithSite_SetSite() or IInternetSecurityManager_SetSecuritySite() on
1329  * an object.
1330  *
1331  */
1332 HRESULT WINAPI IUnknown_SetSite(
1333         IUnknown *obj,        /* [in]   OLE object     */
1334         IUnknown *site)       /* [in]   Site interface */
1335 {
1336     HRESULT hr;
1337     IObjectWithSite *iobjwithsite;
1338     IInternetSecurityManager *isecmgr;
1339 
1340     if (!obj) return E_FAIL;
1341 
1342     hr = IUnknown_QueryInterface(obj, &IID_IObjectWithSite, (LPVOID *)&iobjwithsite);
1343     TRACE("IID_IObjectWithSite QI ret=%08x, %p\n", hr, iobjwithsite);
1344     if (SUCCEEDED(hr))
1345     {
1346 	hr = IObjectWithSite_SetSite(iobjwithsite, site);
1347 	TRACE("done IObjectWithSite_SetSite ret=%08x\n", hr);
1348 	IObjectWithSite_Release(iobjwithsite);
1349     }
1350     else
1351     {
1352 	hr = IUnknown_QueryInterface(obj, &IID_IInternetSecurityManager, (LPVOID *)&isecmgr);
1353 	TRACE("IID_IInternetSecurityManager QI ret=%08x, %p\n", hr, isecmgr);
1354 	if (FAILED(hr)) return hr;
1355 
1356 	hr = IInternetSecurityManager_SetSecuritySite(isecmgr, (IInternetSecurityMgrSite *)site);
1357 	TRACE("done IInternetSecurityManager_SetSecuritySite ret=%08x\n", hr);
1358 	IInternetSecurityManager_Release(isecmgr);
1359     }
1360     return hr;
1361 }
1362 
1363 /*************************************************************************
1364  *      @	[SHLWAPI.175]
1365  *
1366  * Call IPersist_GetClassID() on an object.
1367  *
1368  * PARAMS
1369  *  lpUnknown [I] Object supporting the IPersist interface
1370  *  clsid     [O] Destination for Class Id
1371  *
1372  * RETURNS
1373  *  Success: S_OK. lpClassId contains the Class Id requested.
1374  *  Failure: E_FAIL, If lpUnknown is NULL,
1375  *           E_NOINTERFACE If lpUnknown does not support IPersist,
1376  *           Or an HRESULT error code.
1377  */
1378 HRESULT WINAPI IUnknown_GetClassID(IUnknown *lpUnknown, CLSID *clsid)
1379 {
1380     IPersist *persist;
1381     HRESULT hr;
1382 
1383     TRACE("(%p, %p)\n", lpUnknown, clsid);
1384 
1385     if (!lpUnknown)
1386     {
1387         memset(clsid, 0, sizeof(*clsid));
1388         return E_FAIL;
1389     }
1390 
1391     hr = IUnknown_QueryInterface(lpUnknown, &IID_IPersist, (void**)&persist);
1392     if (hr != S_OK)
1393     {
1394         hr = IUnknown_QueryInterface(lpUnknown, &IID_IPersistFolder, (void**)&persist);
1395         if (hr != S_OK)
1396             return hr;
1397     }
1398 
1399     hr = IPersist_GetClassID(persist, clsid);
1400     IPersist_Release(persist);
1401     return hr;
1402 }
1403 
1404 /*************************************************************************
1405  *      @	[SHLWAPI.176]
1406  *
1407  * Retrieve a Service Interface from an object.
1408  *
1409  * PARAMS
1410  *  lpUnknown [I] Object to get an IServiceProvider interface from
1411  *  sid       [I] Service ID for IServiceProvider_QueryService() call
1412  *  riid      [I] Function requested for QueryService call
1413  *  lppOut    [O] Destination for the service interface pointer
1414  *
1415  * RETURNS
1416  *  Success: S_OK. lppOut contains an object providing the requested service
1417  *  Failure: An HRESULT error code
1418  *
1419  * NOTES
1420  *  lpUnknown is expected to support the IServiceProvider interface.
1421  */
1422 HRESULT WINAPI IUnknown_QueryService(IUnknown* lpUnknown, REFGUID sid, REFIID riid,
1423                            LPVOID *lppOut)
1424 {
1425   IServiceProvider* pService = NULL;
1426   HRESULT hRet;
1427 
1428   if (!lppOut)
1429     return E_FAIL;
1430 
1431   *lppOut = NULL;
1432 
1433   if (!lpUnknown)
1434     return E_FAIL;
1435 
1436   hRet = IUnknown_QueryInterface(lpUnknown, &IID_IServiceProvider,
1437                                  (LPVOID*)&pService);
1438 
1439   if (hRet == S_OK && pService)
1440   {
1441     TRACE("QueryInterface returned (IServiceProvider*)%p\n", pService);
1442 
1443     /* Get a Service interface from the object */
1444     hRet = IServiceProvider_QueryService(pService, sid, riid, lppOut);
1445 
1446     TRACE("(IServiceProvider*)%p returned (IUnknown*)%p\n", pService, *lppOut);
1447 
1448     IServiceProvider_Release(pService);
1449   }
1450   return hRet;
1451 }
1452 
1453 /*************************************************************************
1454  *      @	[SHLWAPI.484]
1455  *
1456  * Calls IOleCommandTarget::Exec() for specified service object.
1457  *
1458  * PARAMS
1459  *  lpUnknown [I] Object to get an IServiceProvider interface from
1460  *  service   [I] Service ID for IServiceProvider_QueryService() call
1461  *  group     [I] Group ID for IOleCommandTarget::Exec() call
1462  *  cmdId     [I] Command ID for IOleCommandTarget::Exec() call
1463  *  cmdOpt    [I] Options flags for command
1464  *  pIn       [I] Input arguments for command
1465  *  pOut      [O] Output arguments for command
1466  *
1467  * RETURNS
1468  *  Success: S_OK. lppOut contains an object providing the requested service
1469  *  Failure: An HRESULT error code
1470  *
1471  * NOTES
1472  *  lpUnknown is expected to support the IServiceProvider interface.
1473  */
1474 HRESULT WINAPI IUnknown_QueryServiceExec(IUnknown *lpUnknown, REFIID service,
1475     const GUID *group, DWORD cmdId, DWORD cmdOpt, VARIANT *pIn, VARIANT *pOut)
1476 {
1477     IOleCommandTarget *target;
1478     HRESULT hr;
1479 
1480     TRACE("%p %s %s %d %08x %p %p\n", lpUnknown, debugstr_guid(service),
1481         debugstr_guid(group), cmdId, cmdOpt, pIn, pOut);
1482 
1483     hr = IUnknown_QueryService(lpUnknown, service, &IID_IOleCommandTarget, (void**)&target);
1484     if (hr == S_OK)
1485     {
1486         hr = IOleCommandTarget_Exec(target, group, cmdId, cmdOpt, pIn, pOut);
1487         IOleCommandTarget_Release(target);
1488     }
1489 
1490     TRACE("<-- hr=0x%08x\n", hr);
1491 
1492     return hr;
1493 }
1494 
1495 /*************************************************************************
1496  *      @	[SHLWAPI.514]
1497  *
1498  * Calls IProfferService methods to proffer/revoke specified service.
1499  *
1500  * PARAMS
1501  *  lpUnknown [I]  Object to get an IServiceProvider interface from
1502  *  service   [I]  Service ID for IProfferService::Proffer/Revoke calls
1503  *  pService  [I]  Service to proffer. If NULL ::Revoke is called
1504  *  pCookie   [IO] Group ID for IOleCommandTarget::Exec() call
1505  *
1506  * RETURNS
1507  *  Success: S_OK. IProffer method returns S_OK
1508  *  Failure: An HRESULT error code
1509  *
1510  * NOTES
1511  *  lpUnknown is expected to support the IServiceProvider interface.
1512  */
1513 HRESULT WINAPI IUnknown_ProfferService(IUnknown *lpUnknown, REFGUID service, IServiceProvider *pService, DWORD *pCookie)
1514 {
1515     IProfferService *proffer;
1516     HRESULT hr;
1517 
1518     TRACE("%p %s %p %p\n", lpUnknown, debugstr_guid(service), pService, pCookie);
1519 
1520     hr = IUnknown_QueryService(lpUnknown, &IID_IProfferService, &IID_IProfferService, (void**)&proffer);
1521     if (hr == S_OK)
1522     {
1523         if (pService)
1524             hr = IProfferService_ProfferService(proffer, service, pService, pCookie);
1525         else
1526         {
1527             hr = IProfferService_RevokeService(proffer, *pCookie);
1528             *pCookie = 0;
1529         }
1530 
1531         IProfferService_Release(proffer);
1532     }
1533 
1534     return hr;
1535 }
1536 
1537 /*************************************************************************
1538  *      @	[SHLWAPI.479]
1539  *
1540  * Call an object's UIActivateIO method.
1541  *
1542  * PARAMS
1543  *  unknown  [I] Object to call the UIActivateIO method on
1544  *  activate [I] Parameter for UIActivateIO call
1545  *  msg      [I] Parameter for UIActivateIO call
1546  *
1547  * RETURNS
1548  *  Success: Value of UI_ActivateIO call
1549  *  Failure: An HRESULT error code
1550  *
1551  * NOTES
1552  *  unknown is expected to support the IInputObject interface.
1553  */
1554 HRESULT WINAPI IUnknown_UIActivateIO(IUnknown *unknown, BOOL activate, LPMSG msg)
1555 {
1556     IInputObject* object = NULL;
1557     HRESULT ret;
1558 
1559     if (!unknown)
1560         return E_FAIL;
1561 
1562     /* Get an IInputObject interface from the object */
1563     ret = IUnknown_QueryInterface(unknown, &IID_IInputObject, (LPVOID*) &object);
1564 
1565     if (ret == S_OK)
1566     {
1567         ret = IInputObject_UIActivateIO(object, activate, msg);
1568         IInputObject_Release(object);
1569     }
1570 
1571     return ret;
1572 }
1573 
1574 /*************************************************************************
1575  *      @	[SHLWAPI.177]
1576  *
1577  * Loads a popup menu.
1578  *
1579  * PARAMS
1580  *  hInst  [I] Instance handle
1581  *  szName [I] Menu name
1582  *
1583  * RETURNS
1584  *  Success: TRUE.
1585  *  Failure: FALSE.
1586  */
1587 BOOL WINAPI SHLoadMenuPopup(HINSTANCE hInst, LPCWSTR szName)
1588 {
1589   HMENU hMenu;
1590 
1591   TRACE("%p %s\n", hInst, debugstr_w(szName));
1592 
1593   if ((hMenu = LoadMenuW(hInst, szName)))
1594   {
1595     if (GetSubMenu(hMenu, 0))
1596       RemoveMenu(hMenu, 0, MF_BYPOSITION);
1597 
1598     DestroyMenu(hMenu);
1599     return TRUE;
1600   }
1601   return FALSE;
1602 }
1603 
1604 typedef struct _enumWndData
1605 {
1606   UINT   uiMsgId;
1607   WPARAM wParam;
1608   LPARAM lParam;
1609   LRESULT (WINAPI *pfnPost)(HWND,UINT,WPARAM,LPARAM);
1610 } enumWndData;
1611 
1612 /* Callback for SHLWAPI_178 */
1613 static BOOL CALLBACK SHLWAPI_EnumChildProc(HWND hWnd, LPARAM lParam)
1614 {
1615   enumWndData *data = (enumWndData *)lParam;
1616 
1617   TRACE("(%p,%p)\n", hWnd, data);
1618   data->pfnPost(hWnd, data->uiMsgId, data->wParam, data->lParam);
1619   return TRUE;
1620 }
1621 
1622 /*************************************************************************
1623  * @  [SHLWAPI.178]
1624  *
1625  * Send or post a message to every child of a window.
1626  *
1627  * PARAMS
1628  *  hWnd    [I] Window whose children will get the messages
1629  *  uiMsgId [I] Message Id
1630  *  wParam  [I] WPARAM of message
1631  *  lParam  [I] LPARAM of message
1632  *  bSend   [I] TRUE = Use SendMessageA(), FALSE = Use PostMessageA()
1633  *
1634  * RETURNS
1635  *  Nothing.
1636  *
1637  * NOTES
1638  *  The appropriate ASCII or Unicode function is called for the window.
1639  */
1640 void WINAPI SHPropagateMessage(HWND hWnd, UINT uiMsgId, WPARAM wParam, LPARAM lParam, BOOL bSend)
1641 {
1642   enumWndData data;
1643 
1644   TRACE("(%p,%u,%ld,%ld,%d)\n", hWnd, uiMsgId, wParam, lParam, bSend);
1645 
1646   if(hWnd)
1647   {
1648     data.uiMsgId = uiMsgId;
1649     data.wParam  = wParam;
1650     data.lParam  = lParam;
1651 
1652     if (bSend)
1653       data.pfnPost = IsWindowUnicode(hWnd) ? (void*)SendMessageW : (void*)SendMessageA;
1654     else
1655       data.pfnPost = IsWindowUnicode(hWnd) ? (void*)PostMessageW : (void*)PostMessageA;
1656 
1657     EnumChildWindows(hWnd, SHLWAPI_EnumChildProc, (LPARAM)&data);
1658   }
1659 }
1660 
1661 /*************************************************************************
1662  *      @	[SHLWAPI.180]
1663  *
1664  * Remove all sub-menus from a menu.
1665  *
1666  * PARAMS
1667  *  hMenu [I] Menu to remove sub-menus from
1668  *
1669  * RETURNS
1670  *  Success: 0.  All sub-menus under hMenu are removed
1671  *  Failure: -1, if any parameter is invalid
1672  */
1673 DWORD WINAPI SHRemoveAllSubMenus(HMENU hMenu)
1674 {
1675   int iItemCount = GetMenuItemCount(hMenu) - 1;
1676 
1677   TRACE("%p\n", hMenu);
1678 
1679   while (iItemCount >= 0)
1680   {
1681     HMENU hSubMenu = GetSubMenu(hMenu, iItemCount);
1682     if (hSubMenu)
1683       RemoveMenu(hMenu, iItemCount, MF_BYPOSITION);
1684     iItemCount--;
1685   }
1686   return iItemCount;
1687 }
1688 
1689 /*************************************************************************
1690  *      @	[SHLWAPI.181]
1691  *
1692  * Enable or disable a menu item.
1693  *
1694  * PARAMS
1695  *  hMenu   [I] Menu holding menu item
1696  *  uID     [I] ID of menu item to enable/disable
1697  *  bEnable [I] Whether to enable (TRUE) or disable (FALSE) the item.
1698  *
1699  * RETURNS
1700  *  The return code from EnableMenuItem.
1701  */
1702 UINT WINAPI SHEnableMenuItem(HMENU hMenu, UINT wItemID, BOOL bEnable)
1703 {
1704   TRACE("%p, %u, %d\n", hMenu, wItemID, bEnable);
1705   return EnableMenuItem(hMenu, wItemID, bEnable ? MF_ENABLED : MF_GRAYED);
1706 }
1707 
1708 /*************************************************************************
1709  * @	[SHLWAPI.182]
1710  *
1711  * Check or uncheck a menu item.
1712  *
1713  * PARAMS
1714  *  hMenu  [I] Menu holding menu item
1715  *  uID    [I] ID of menu item to check/uncheck
1716  *  bCheck [I] Whether to check (TRUE) or uncheck (FALSE) the item.
1717  *
1718  * RETURNS
1719  *  The return code from CheckMenuItem.
1720  */
1721 DWORD WINAPI SHCheckMenuItem(HMENU hMenu, UINT uID, BOOL bCheck)
1722 {
1723   TRACE("%p, %u, %d\n", hMenu, uID, bCheck);
1724   return CheckMenuItem(hMenu, uID, bCheck ? MF_CHECKED : MF_UNCHECKED);
1725 }
1726 
1727 /*************************************************************************
1728  *      @	[SHLWAPI.183]
1729  *
1730  * Register a window class if it isn't already.
1731  *
1732  * PARAMS
1733  *  lpWndClass [I] Window class to register
1734  *
1735  * RETURNS
1736  *  The result of the RegisterClassA call.
1737  */
1738 DWORD WINAPI SHRegisterClassA(WNDCLASSA *wndclass)
1739 {
1740   WNDCLASSA wca;
1741   if (GetClassInfoA(wndclass->hInstance, wndclass->lpszClassName, &wca))
1742     return TRUE;
1743   return (DWORD)RegisterClassA(wndclass);
1744 }
1745 
1746 /*************************************************************************
1747  *      @	[SHLWAPI.186]
1748  */
1749 BOOL WINAPI SHSimulateDrop(IDropTarget *pDrop, IDataObject *pDataObj,
1750                            DWORD grfKeyState, PPOINTL lpPt, DWORD* pdwEffect)
1751 {
1752   DWORD dwEffect = DROPEFFECT_LINK | DROPEFFECT_MOVE | DROPEFFECT_COPY;
1753   POINTL pt = { 0, 0 };
1754 
1755   TRACE("%p %p 0x%08x %p %p\n", pDrop, pDataObj, grfKeyState, lpPt, pdwEffect);
1756 
1757   if (!lpPt)
1758     lpPt = &pt;
1759 
1760   if (!pdwEffect)
1761     pdwEffect = &dwEffect;
1762 
1763   IDropTarget_DragEnter(pDrop, pDataObj, grfKeyState, *lpPt, pdwEffect);
1764 
1765   if (*pdwEffect != DROPEFFECT_NONE)
1766     return IDropTarget_Drop(pDrop, pDataObj, grfKeyState, *lpPt, pdwEffect);
1767 
1768   IDropTarget_DragLeave(pDrop);
1769   return TRUE;
1770 }
1771 
1772 /*************************************************************************
1773  *      @	[SHLWAPI.187]
1774  *
1775  * Call IPersistPropertyBag_Load() on an object.
1776  *
1777  * PARAMS
1778  *  lpUnknown [I] Object supporting the IPersistPropertyBag interface
1779  *  lpPropBag [O] Destination for loaded IPropertyBag
1780  *
1781  * RETURNS
1782  *  Success: S_OK.
1783  *  Failure: An HRESULT error code, or E_FAIL if lpUnknown is NULL.
1784  */
1785 DWORD WINAPI SHLoadFromPropertyBag(IUnknown *lpUnknown, IPropertyBag* lpPropBag)
1786 {
1787   IPersistPropertyBag* lpPPBag;
1788   HRESULT hRet = E_FAIL;
1789 
1790   TRACE("(%p,%p)\n", lpUnknown, lpPropBag);
1791 
1792   if (lpUnknown)
1793   {
1794     hRet = IUnknown_QueryInterface(lpUnknown, &IID_IPersistPropertyBag,
1795                                    (void**)&lpPPBag);
1796     if (SUCCEEDED(hRet) && lpPPBag)
1797     {
1798       hRet = IPersistPropertyBag_Load(lpPPBag, lpPropBag, NULL);
1799       IPersistPropertyBag_Release(lpPPBag);
1800     }
1801   }
1802   return hRet;
1803 }
1804 
1805 /*************************************************************************
1806  * @  [SHLWAPI.188]
1807  *
1808  * Call IOleControlSite_TranslateAccelerator()  on an object.
1809  *
1810  * PARAMS
1811  *  lpUnknown   [I] Object supporting the IOleControlSite interface.
1812  *  lpMsg       [I] Key message to be processed.
1813  *  dwModifiers [I] Flags containing the state of the modifier keys.
1814  *
1815  * RETURNS
1816  *  Success: S_OK.
1817  *  Failure: An HRESULT error code, or E_INVALIDARG if lpUnknown is NULL.
1818  */
1819 HRESULT WINAPI IUnknown_TranslateAcceleratorOCS(IUnknown *lpUnknown, LPMSG lpMsg, DWORD dwModifiers)
1820 {
1821   IOleControlSite* lpCSite = NULL;
1822   HRESULT hRet = E_INVALIDARG;
1823 
1824   TRACE("(%p,%p,0x%08x)\n", lpUnknown, lpMsg, dwModifiers);
1825   if (lpUnknown)
1826   {
1827     hRet = IUnknown_QueryInterface(lpUnknown, &IID_IOleControlSite,
1828                                    (void**)&lpCSite);
1829     if (SUCCEEDED(hRet) && lpCSite)
1830     {
1831       hRet = IOleControlSite_TranslateAccelerator(lpCSite, lpMsg, dwModifiers);
1832       IOleControlSite_Release(lpCSite);
1833     }
1834   }
1835   return hRet;
1836 }
1837 
1838 
1839 /*************************************************************************
1840  * @  [SHLWAPI.189]
1841  *
1842  * Call IOleControlSite_OnFocus() on an object.
1843  *
1844  * PARAMS
1845  *  lpUnknown [I] Object supporting the IOleControlSite interface.
1846  *  fGotFocus [I] Whether focus was gained (TRUE) or lost (FALSE).
1847  *
1848  * RETURNS
1849  *  Success: S_OK.
1850  *  Failure: An HRESULT error code, or E_FAIL if lpUnknown is NULL.
1851  */
1852 HRESULT WINAPI IUnknown_OnFocusOCS(IUnknown *lpUnknown, BOOL fGotFocus)
1853 {
1854   IOleControlSite* lpCSite = NULL;
1855   HRESULT hRet = E_FAIL;
1856 
1857   TRACE("(%p, %d)\n", lpUnknown, fGotFocus);
1858   if (lpUnknown)
1859   {
1860     hRet = IUnknown_QueryInterface(lpUnknown, &IID_IOleControlSite,
1861                                    (void**)&lpCSite);
1862     if (SUCCEEDED(hRet) && lpCSite)
1863     {
1864       hRet = IOleControlSite_OnFocus(lpCSite, fGotFocus);
1865       IOleControlSite_Release(lpCSite);
1866     }
1867   }
1868   return hRet;
1869 }
1870 
1871 /*************************************************************************
1872  * @    [SHLWAPI.190]
1873  */
1874 HRESULT WINAPI IUnknown_HandleIRestrict(LPUNKNOWN lpUnknown, PVOID lpArg1,
1875                                         PVOID lpArg2, PVOID lpArg3, PVOID lpArg4)
1876 {
1877   /* FIXME: {D12F26B2-D90A-11D0-830D-00AA005B4383} - What object does this represent? */
1878   static const DWORD service_id[] = { 0xd12f26b2, 0x11d0d90a, 0xaa000d83, 0x83435b00 };
1879   /* FIXME: {D12F26B1-D90A-11D0-830D-00AA005B4383} - Also Unknown/undocumented */
1880   static const DWORD function_id[] = { 0xd12f26b1, 0x11d0d90a, 0xaa000d83, 0x83435b00 };
1881   HRESULT hRet = E_INVALIDARG;
1882   LPUNKNOWN lpUnkInner = NULL; /* FIXME: Real type is unknown */
1883 
1884   TRACE("(%p,%p,%p,%p,%p)\n", lpUnknown, lpArg1, lpArg2, lpArg3, lpArg4);
1885 
1886   if (lpUnknown && lpArg4)
1887   {
1888      hRet = IUnknown_QueryService(lpUnknown, (REFGUID)service_id,
1889                                   (REFGUID)function_id, (void**)&lpUnkInner);
1890 
1891      if (SUCCEEDED(hRet) && lpUnkInner)
1892      {
1893        /* FIXME: The type of service object requested is unknown, however
1894 	* testing shows that its first method is called with 4 parameters.
1895 	* Fake this by using IParseDisplayName_ParseDisplayName since the
1896 	* signature and position in the vtable matches our unknown object type.
1897 	*/
1898        hRet = IParseDisplayName_ParseDisplayName((LPPARSEDISPLAYNAME)lpUnkInner,
1899                                                  lpArg1, lpArg2, lpArg3, lpArg4);
1900        IUnknown_Release(lpUnkInner);
1901      }
1902   }
1903   return hRet;
1904 }
1905 
1906 /*************************************************************************
1907  * @    [SHLWAPI.192]
1908  *
1909  * Get a sub-menu from a menu item.
1910  *
1911  * PARAMS
1912  *  hMenu [I] Menu to get sub-menu from
1913  *  uID   [I] ID of menu item containing sub-menu
1914  *
1915  * RETURNS
1916  *  The sub-menu of the item, or a NULL handle if any parameters are invalid.
1917  */
1918 HMENU WINAPI SHGetMenuFromID(HMENU hMenu, UINT uID)
1919 {
1920   MENUITEMINFOW mi;
1921 
1922   TRACE("(%p,%u)\n", hMenu, uID);
1923 
1924   mi.cbSize = sizeof(mi);
1925   mi.fMask = MIIM_SUBMENU;
1926 
1927   if (!GetMenuItemInfoW(hMenu, uID, FALSE, &mi))
1928     return NULL;
1929 
1930   return mi.hSubMenu;
1931 }
1932 
1933 /*************************************************************************
1934  *      @	[SHLWAPI.193]
1935  *
1936  * Get the color depth of the primary display.
1937  *
1938  * PARAMS
1939  *  None.
1940  *
1941  * RETURNS
1942  *  The color depth of the primary display.
1943  */
1944 DWORD WINAPI SHGetCurColorRes(void)
1945 {
1946     HDC hdc;
1947     DWORD ret;
1948 
1949     TRACE("()\n");
1950 
1951     hdc = GetDC(0);
1952     ret = GetDeviceCaps(hdc, BITSPIXEL) * GetDeviceCaps(hdc, PLANES);
1953     ReleaseDC(0, hdc);
1954     return ret;
1955 }
1956 
1957 /*************************************************************************
1958  *      @	[SHLWAPI.194]
1959  *
1960  * Wait for a message to arrive, with a timeout.
1961  *
1962  * PARAMS
1963  *  hand      [I] Handle to query
1964  *  dwTimeout [I] Timeout in ticks or INFINITE to never timeout
1965  *
1966  * RETURNS
1967  *  STATUS_TIMEOUT if no message is received before dwTimeout ticks passes.
1968  *  Otherwise returns the value from MsgWaitForMultipleObjectsEx when a
1969  *  message is available.
1970  */
1971 DWORD WINAPI SHWaitForSendMessageThread(HANDLE hand, DWORD dwTimeout)
1972 {
1973   DWORD dwEndTicks = GetTickCount() + dwTimeout;
1974   DWORD dwRet;
1975 
1976   while ((dwRet = MsgWaitForMultipleObjectsEx(1, &hand, dwTimeout, QS_SENDMESSAGE, 0)) == 1)
1977   {
1978     MSG msg;
1979 
1980     PeekMessageW(&msg, NULL, 0, 0, PM_NOREMOVE);
1981 
1982     if (dwTimeout != INFINITE)
1983     {
1984         if ((int)(dwTimeout = dwEndTicks - GetTickCount()) <= 0)
1985             return WAIT_TIMEOUT;
1986     }
1987   }
1988 
1989   return dwRet;
1990 }
1991 
1992 /*************************************************************************
1993  *      @       [SHLWAPI.195]
1994  *
1995  * Determine if a shell folder can be expanded.
1996  *
1997  * PARAMS
1998  *  lpFolder [I] Parent folder containing the object to test.
1999  *  pidl     [I] Id of the object to test.
2000  *
2001  * RETURNS
2002  *  Success: S_OK, if the object is expandable, S_FALSE otherwise.
2003  *  Failure: E_INVALIDARG, if any argument is invalid.
2004  *
2005  * NOTES
2006  *  If the object to be tested does not expose the IQueryInfo() interface it
2007  *  will not be identified as an expandable folder.
2008  */
2009 HRESULT WINAPI SHIsExpandableFolder(LPSHELLFOLDER lpFolder, LPCITEMIDLIST pidl)
2010 {
2011   HRESULT hRet = E_INVALIDARG;
2012   IQueryInfo *lpInfo;
2013 
2014   if (lpFolder && pidl)
2015   {
2016     hRet = IShellFolder_GetUIObjectOf(lpFolder, NULL, 1, &pidl, &IID_IQueryInfo,
2017                                       NULL, (void**)&lpInfo);
2018     if (FAILED(hRet))
2019       hRet = S_FALSE; /* Doesn't expose IQueryInfo */
2020     else
2021     {
2022       DWORD dwFlags = 0;
2023 
2024       /* MSDN states of IQueryInfo_GetInfoFlags() that "This method is not
2025        * currently used". Really? You wouldn't be holding out on me would you?
2026        */
2027       hRet = IQueryInfo_GetInfoFlags(lpInfo, &dwFlags);
2028 
2029       if (SUCCEEDED(hRet))
2030       {
2031         /* 0x2 is an undocumented flag apparently indicating expandability */
2032         hRet = dwFlags & 0x2 ? S_OK : S_FALSE;
2033       }
2034 
2035       IQueryInfo_Release(lpInfo);
2036     }
2037   }
2038   return hRet;
2039 }
2040 
2041 /*************************************************************************
2042  *      @       [SHLWAPI.197]
2043  *
2044  * Blank out a region of text by drawing the background only.
2045  *
2046  * PARAMS
2047  *  hDC   [I] Device context to draw in
2048  *  pRect [I] Area to draw in
2049  *  cRef  [I] Color to draw in
2050  *
2051  * RETURNS
2052  *  Nothing.
2053  */
2054 DWORD WINAPI SHFillRectClr(HDC hDC, LPCRECT pRect, COLORREF cRef)
2055 {
2056     COLORREF cOldColor = SetBkColor(hDC, cRef);
2057     ExtTextOutA(hDC, 0, 0, ETO_OPAQUE, pRect, 0, 0, 0);
2058     SetBkColor(hDC, cOldColor);
2059     return 0;
2060 }
2061 
2062 /*************************************************************************
2063  *      @	[SHLWAPI.198]
2064  *
2065  * Return the value associated with a key in a map.
2066  *
2067  * PARAMS
2068  *  lpKeys   [I] A list of keys of length iLen
2069  *  lpValues [I] A list of values associated with lpKeys, of length iLen
2070  *  iLen     [I] Length of both lpKeys and lpValues
2071  *  iKey     [I] The key value to look up in lpKeys
2072  *
2073  * RETURNS
2074  *  The value in lpValues associated with iKey, or -1 if iKey is not
2075  *  found in lpKeys.
2076  *
2077  * NOTES
2078  *  - If two elements in the map share the same key, this function returns
2079  *    the value closest to the start of the map
2080  *  - The native version of this function crashes if lpKeys or lpValues is NULL.
2081  */
2082 int WINAPI SHSearchMapInt(const int *lpKeys, const int *lpValues, int iLen, int iKey)
2083 {
2084   if (lpKeys && lpValues)
2085   {
2086     int i = 0;
2087 
2088     while (i < iLen)
2089     {
2090       if (lpKeys[i] == iKey)
2091         return lpValues[i]; /* Found */
2092       i++;
2093     }
2094   }
2095   return -1; /* Not found */
2096 }
2097 
2098 
2099 /*************************************************************************
2100  *      @	[SHLWAPI.199]
2101  *
2102  * Copy an interface pointer
2103  *
2104  * PARAMS
2105  *   lppDest   [O] Destination for copy
2106  *   lpUnknown [I] Source for copy
2107  *
2108  * RETURNS
2109  *  Nothing.
2110  */
2111 VOID WINAPI IUnknown_Set(IUnknown **lppDest, IUnknown *lpUnknown)
2112 {
2113   TRACE("(%p,%p)\n", lppDest, lpUnknown);
2114 
2115   IUnknown_AtomicRelease(lppDest);
2116 
2117   if (lpUnknown)
2118   {
2119     IUnknown_AddRef(lpUnknown);
2120     *lppDest = lpUnknown;
2121   }
2122 }
2123 
2124 /*************************************************************************
2125  *      @	[SHLWAPI.200]
2126  *
2127  */
2128 HRESULT WINAPI MayQSForward(IUnknown* lpUnknown, PVOID lpReserved,
2129                             REFGUID riidCmdGrp, ULONG cCmds,
2130                             OLECMD *prgCmds, OLECMDTEXT* pCmdText)
2131 {
2132   FIXME("(%p,%p,%p,%d,%p,%p) - stub\n",
2133         lpUnknown, lpReserved, riidCmdGrp, cCmds, prgCmds, pCmdText);
2134 
2135   /* FIXME: Calls IsQSForward & IUnknown_QueryStatus */
2136   return DRAGDROP_E_NOTREGISTERED;
2137 }
2138 
2139 /*************************************************************************
2140  *      @	[SHLWAPI.201]
2141  *
2142  */
2143 HRESULT WINAPI MayExecForward(IUnknown* lpUnknown, INT iUnk, REFGUID pguidCmdGroup,
2144                            DWORD nCmdID, DWORD nCmdexecopt, VARIANT* pvaIn,
2145                            VARIANT* pvaOut)
2146 {
2147   FIXME("(%p,%d,%p,%d,%d,%p,%p) - stub!\n", lpUnknown, iUnk, pguidCmdGroup,
2148         nCmdID, nCmdexecopt, pvaIn, pvaOut);
2149   return DRAGDROP_E_NOTREGISTERED;
2150 }
2151 
2152 /*************************************************************************
2153  *      @	[SHLWAPI.202]
2154  *
2155  */
2156 HRESULT WINAPI IsQSForward(REFGUID pguidCmdGroup,ULONG cCmds, OLECMD *prgCmds)
2157 {
2158   FIXME("(%p,%d,%p) - stub!\n", pguidCmdGroup, cCmds, prgCmds);
2159   return DRAGDROP_E_NOTREGISTERED;
2160 }
2161 
2162 /*************************************************************************
2163  * @	[SHLWAPI.204]
2164  *
2165  * Determine if a window is not a child of another window.
2166  *
2167  * PARAMS
2168  * hParent [I] Suspected parent window
2169  * hChild  [I] Suspected child window
2170  *
2171  * RETURNS
2172  * TRUE:  If hChild is a child window of hParent
2173  * FALSE: If hChild is not a child window of hParent, or they are equal
2174  */
2175 BOOL WINAPI SHIsChildOrSelf(HWND hParent, HWND hChild)
2176 {
2177   TRACE("(%p,%p)\n", hParent, hChild);
2178 
2179   if (!hParent || !hChild)
2180     return TRUE;
2181   else if(hParent == hChild)
2182     return FALSE;
2183   return !IsChild(hParent, hChild);
2184 }
2185 
2186 /*************************************************************************
2187  *    FDSA functions.  Manage a dynamic array of fixed size memory blocks.
2188  */
2189 
2190 typedef struct
2191 {
2192     DWORD num_items;       /* Number of elements inserted */
2193     void *mem;             /* Ptr to array */
2194     DWORD blocks_alloced;  /* Number of elements allocated */
2195     BYTE inc;              /* Number of elements to grow by when we need to expand */
2196     BYTE block_size;       /* Size in bytes of an element */
2197     BYTE flags;            /* Flags */
2198 } FDSA_info;
2199 
2200 #define FDSA_FLAG_INTERNAL_ALLOC 0x01 /* When set we have allocated mem internally */
2201 
2202 /*************************************************************************
2203  *      @	[SHLWAPI.208]
2204  *
2205  * Initialize an FDSA array.
2206  */
2207 BOOL WINAPI FDSA_Initialize(DWORD block_size, DWORD inc, FDSA_info *info, void *mem,
2208                             DWORD init_blocks)
2209 {
2210     TRACE("(0x%08x 0x%08x %p %p 0x%08x)\n", block_size, inc, info, mem, init_blocks);
2211 
2212     if(inc == 0)
2213         inc = 1;
2214 
2215     if(mem)
2216         memset(mem, 0, block_size * init_blocks);
2217 
2218     info->num_items = 0;
2219     info->inc = inc;
2220     info->mem = mem;
2221     info->blocks_alloced = init_blocks;
2222     info->block_size = block_size;
2223     info->flags = 0;
2224 
2225     return TRUE;
2226 }
2227 
2228 /*************************************************************************
2229  *      @	[SHLWAPI.209]
2230  *
2231  * Destroy an FDSA array
2232  */
2233 BOOL WINAPI FDSA_Destroy(FDSA_info *info)
2234 {
2235     TRACE("(%p)\n", info);
2236 
2237     if(info->flags & FDSA_FLAG_INTERNAL_ALLOC)
2238     {
2239         HeapFree(GetProcessHeap(), 0, info->mem);
2240         return FALSE;
2241     }
2242 
2243     return TRUE;
2244 }
2245 
2246 /*************************************************************************
2247  *      @	[SHLWAPI.210]
2248  *
2249  * Insert element into an FDSA array
2250  */
2251 DWORD WINAPI FDSA_InsertItem(FDSA_info *info, DWORD where, const void *block)
2252 {
2253     TRACE("(%p 0x%08x %p)\n", info, where, block);
2254     if(where > info->num_items)
2255         where = info->num_items;
2256 
2257     if(info->num_items >= info->blocks_alloced)
2258     {
2259         DWORD size = (info->blocks_alloced + info->inc) * info->block_size;
2260         if(info->flags & 0x1)
2261             info->mem = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, info->mem, size);
2262         else
2263         {
2264             void *old_mem = info->mem;
2265             info->mem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2266             memcpy(info->mem, old_mem, info->blocks_alloced * info->block_size);
2267         }
2268         info->blocks_alloced += info->inc;
2269         info->flags |= 0x1;
2270     }
2271 
2272     if(where < info->num_items)
2273     {
2274         memmove((char*)info->mem + (where + 1) * info->block_size,
2275                 (char*)info->mem + where * info->block_size,
2276                 (info->num_items - where) * info->block_size);
2277     }
2278     memcpy((char*)info->mem + where * info->block_size, block, info->block_size);
2279 
2280     info->num_items++;
2281     return where;
2282 }
2283 
2284 /*************************************************************************
2285  *      @	[SHLWAPI.211]
2286  *
2287  * Delete an element from an FDSA array.
2288  */
2289 BOOL WINAPI FDSA_DeleteItem(FDSA_info *info, DWORD where)
2290 {
2291     TRACE("(%p 0x%08x)\n", info, where);
2292 
2293     if(where >= info->num_items)
2294         return FALSE;
2295 
2296     if(where < info->num_items - 1)
2297     {
2298         memmove((char*)info->mem + where * info->block_size,
2299                 (char*)info->mem + (where + 1) * info->block_size,
2300                 (info->num_items - where - 1) * info->block_size);
2301     }
2302     memset((char*)info->mem + (info->num_items - 1) * info->block_size,
2303            0, info->block_size);
2304     info->num_items--;
2305     return TRUE;
2306 }
2307 
2308 /*************************************************************************
2309  *      @	[SHLWAPI.219]
2310  *
2311  * Call IUnknown_QueryInterface() on a table of objects.
2312  *
2313  * RETURNS
2314  *  Success: S_OK.
2315  *  Failure: E_POINTER or E_NOINTERFACE.
2316  */
2317 HRESULT WINAPI QISearch(
2318 	void *base,         /* [in]   Table of interfaces */
2319 	const QITAB *table, /* [in]   Array of REFIIDs and indexes into the table */
2320 	REFIID riid,        /* [in]   REFIID to get interface for */
2321 	void **ppv)         /* [out]  Destination for interface pointer */
2322 {
2323 	HRESULT ret;
2324 	IUnknown *a_vtbl;
2325 	const QITAB *xmove;
2326 
2327 	TRACE("(%p %p %s %p)\n", base, table, debugstr_guid(riid), ppv);
2328 	if (ppv) {
2329 	    xmove = table;
2330 	    while (xmove->piid) {
2331 		TRACE("trying (offset %d) %s\n", xmove->dwOffset, debugstr_guid(xmove->piid));
2332 		if (IsEqualIID(riid, xmove->piid)) {
2333 		    a_vtbl = (IUnknown*)(xmove->dwOffset + (LPBYTE)base);
2334 		    TRACE("matched, returning (%p)\n", a_vtbl);
2335                     *ppv = a_vtbl;
2336 		    IUnknown_AddRef(a_vtbl);
2337 		    return S_OK;
2338 		}
2339 		xmove++;
2340 	    }
2341 
2342 	    if (IsEqualIID(riid, &IID_IUnknown)) {
2343 		a_vtbl = (IUnknown*)(table->dwOffset + (LPBYTE)base);
2344 		TRACE("returning first for IUnknown (%p)\n", a_vtbl);
2345                 *ppv = a_vtbl;
2346 		IUnknown_AddRef(a_vtbl);
2347 		return S_OK;
2348 	    }
2349 	    *ppv = 0;
2350 	    ret = E_NOINTERFACE;
2351 	} else
2352 	    ret = E_POINTER;
2353 
2354 	TRACE("-- 0x%08x\n", ret);
2355 	return ret;
2356 }
2357 
2358 /*************************************************************************
2359  * @ [SHLWAPI.220]
2360  *
2361  * Set the Font for a window and the "PropDlgFont" property of the parent window.
2362  *
2363  * PARAMS
2364  *  hWnd [I] Parent Window to set the property
2365  *  id   [I] Index of child Window to set the Font
2366  *
2367  * RETURNS
2368  *  Success: S_OK
2369  *
2370  */
2371 HRESULT WINAPI SHSetDefaultDialogFont(HWND hWnd, INT id)
2372 {
2373     FIXME("(%p, %d) stub\n", hWnd, id);
2374     return S_OK;
2375 }
2376 
2377 /*************************************************************************
2378  *      @	[SHLWAPI.221]
2379  *
2380  * Remove the "PropDlgFont" property from a window.
2381  *
2382  * PARAMS
2383  *  hWnd [I] Window to remove the property from
2384  *
2385  * RETURNS
2386  *  A handle to the removed property, or NULL if it did not exist.
2387  */
2388 HANDLE WINAPI SHRemoveDefaultDialogFont(HWND hWnd)
2389 {
2390   HANDLE hProp;
2391 
2392   TRACE("(%p)\n", hWnd);
2393 
2394   hProp = GetPropA(hWnd, "PropDlgFont");
2395 
2396   if(hProp)
2397   {
2398     DeleteObject(hProp);
2399     hProp = RemovePropA(hWnd, "PropDlgFont");
2400   }
2401   return hProp;
2402 }
2403 
2404 /*************************************************************************
2405  *      @	[SHLWAPI.236]
2406  *
2407  * Load the in-process server of a given GUID.
2408  *
2409  * PARAMS
2410  *  refiid [I] GUID of the server to load.
2411  *
2412  * RETURNS
2413  *  Success: A handle to the loaded server dll.
2414  *  Failure: A NULL handle.
2415  */
2416 HMODULE WINAPI SHPinDllOfCLSID(REFIID refiid)
2417 {
2418     HKEY newkey;
2419     DWORD type, count;
2420     CHAR value[MAX_PATH], string[MAX_PATH];
2421 
2422     strcpy(string, "CLSID\\");
2423     SHStringFromGUIDA(refiid, string + 6, sizeof(string)/sizeof(char) - 6);
2424     strcat(string, "\\InProcServer32");
2425 
2426     count = MAX_PATH;
2427     RegOpenKeyExA(HKEY_CLASSES_ROOT, string, 0, 1, &newkey);
2428     RegQueryValueExA(newkey, 0, 0, &type, (PBYTE)value, &count);
2429     RegCloseKey(newkey);
2430     return LoadLibraryExA(value, 0, 0);
2431 }
2432 
2433 /*************************************************************************
2434  *      @	[SHLWAPI.237]
2435  *
2436  * Unicode version of SHLWAPI_183.
2437  */
2438 DWORD WINAPI SHRegisterClassW(WNDCLASSW * lpWndClass)
2439 {
2440 	WNDCLASSW WndClass;
2441 
2442 	TRACE("(%p %s)\n",lpWndClass->hInstance, debugstr_w(lpWndClass->lpszClassName));
2443 
2444 	if (GetClassInfoW(lpWndClass->hInstance, lpWndClass->lpszClassName, &WndClass))
2445 		return TRUE;
2446 	return RegisterClassW(lpWndClass);
2447 }
2448 
2449 /*************************************************************************
2450  *      @	[SHLWAPI.238]
2451  *
2452  * Unregister a list of classes.
2453  *
2454  * PARAMS
2455  *  hInst      [I] Application instance that registered the classes
2456  *  lppClasses [I] List of class names
2457  *  iCount     [I] Number of names in lppClasses
2458  *
2459  * RETURNS
2460  *  Nothing.
2461  */
2462 void WINAPI SHUnregisterClassesA(HINSTANCE hInst, LPCSTR *lppClasses, INT iCount)
2463 {
2464   WNDCLASSA WndClass;
2465 
2466   TRACE("(%p,%p,%d)\n", hInst, lppClasses, iCount);
2467 
2468   while (iCount > 0)
2469   {
2470     if (GetClassInfoA(hInst, *lppClasses, &WndClass))
2471       UnregisterClassA(*lppClasses, hInst);
2472     lppClasses++;
2473     iCount--;
2474   }
2475 }
2476 
2477 /*************************************************************************
2478  *      @	[SHLWAPI.239]
2479  *
2480  * Unicode version of SHUnregisterClassesA.
2481  */
2482 void WINAPI SHUnregisterClassesW(HINSTANCE hInst, LPCWSTR *lppClasses, INT iCount)
2483 {
2484   WNDCLASSW WndClass;
2485 
2486   TRACE("(%p,%p,%d)\n", hInst, lppClasses, iCount);
2487 
2488   while (iCount > 0)
2489   {
2490     if (GetClassInfoW(hInst, *lppClasses, &WndClass))
2491       UnregisterClassW(*lppClasses, hInst);
2492     lppClasses++;
2493     iCount--;
2494   }
2495 }
2496 
2497 /*************************************************************************
2498  *      @	[SHLWAPI.240]
2499  *
2500  * Call The correct (Ascii/Unicode) default window procedure for a window.
2501  *
2502  * PARAMS
2503  *  hWnd     [I] Window to call the default procedure for
2504  *  uMessage [I] Message ID
2505  *  wParam   [I] WPARAM of message
2506  *  lParam   [I] LPARAM of message
2507  *
2508  * RETURNS
2509  *  The result of calling DefWindowProcA() or DefWindowProcW().
2510  */
2511 LRESULT CALLBACK SHDefWindowProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
2512 {
2513 	if (IsWindowUnicode(hWnd))
2514 		return DefWindowProcW(hWnd, uMessage, wParam, lParam);
2515 	return DefWindowProcA(hWnd, uMessage, wParam, lParam);
2516 }
2517 
2518 /*************************************************************************
2519  *      @       [SHLWAPI.256]
2520  */
2521 HRESULT WINAPI IUnknown_GetSite(LPUNKNOWN lpUnknown, REFIID iid, PVOID *lppSite)
2522 {
2523   HRESULT hRet = E_INVALIDARG;
2524   LPOBJECTWITHSITE lpSite = NULL;
2525 
2526   TRACE("(%p,%s,%p)\n", lpUnknown, debugstr_guid(iid), lppSite);
2527 
2528   if (lpUnknown && iid && lppSite)
2529   {
2530     hRet = IUnknown_QueryInterface(lpUnknown, &IID_IObjectWithSite,
2531                                    (void**)&lpSite);
2532     if (SUCCEEDED(hRet) && lpSite)
2533     {
2534       hRet = IObjectWithSite_GetSite(lpSite, iid, lppSite);
2535       IObjectWithSite_Release(lpSite);
2536     }
2537   }
2538   return hRet;
2539 }
2540 
2541 /*************************************************************************
2542  *      @	[SHLWAPI.257]
2543  *
2544  * Create a worker window using CreateWindowExA().
2545  *
2546  * PARAMS
2547  *  wndProc    [I] Window procedure
2548  *  hWndParent [I] Parent window
2549  *  dwExStyle  [I] Extra style flags
2550  *  dwStyle    [I] Style flags
2551  *  hMenu      [I] Window menu
2552  *  wnd_extra  [I] Window extra bytes value
2553  *
2554  * RETURNS
2555  *  Success: The window handle of the newly created window.
2556  *  Failure: 0.
2557  */
2558 HWND WINAPI SHCreateWorkerWindowA(LONG wndProc, HWND hWndParent, DWORD dwExStyle,
2559                                   DWORD dwStyle, HMENU hMenu, LONG_PTR wnd_extra)
2560 {
2561   static const char szClass[] = "WorkerA";
2562   WNDCLASSA wc;
2563   HWND hWnd;
2564 
2565   TRACE("(0x%08x, %p, 0x%08x, 0x%08x, %p, 0x%08lx)\n",
2566          wndProc, hWndParent, dwExStyle, dwStyle, hMenu, wnd_extra);
2567 
2568   /* Create Window class */
2569   wc.style         = 0;
2570   wc.lpfnWndProc   = DefWindowProcA;
2571   wc.cbClsExtra    = 0;
2572   wc.cbWndExtra    = sizeof(LONG_PTR);
2573   wc.hInstance     = shlwapi_hInstance;
2574   wc.hIcon         = NULL;
2575   wc.hCursor       = LoadCursorA(NULL, (LPSTR)IDC_ARROW);
2576   wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
2577   wc.lpszMenuName  = NULL;
2578   wc.lpszClassName = szClass;
2579 
2580   SHRegisterClassA(&wc);
2581 
2582   hWnd = CreateWindowExA(dwExStyle, szClass, 0, dwStyle, 0, 0, 0, 0,
2583                          hWndParent, hMenu, shlwapi_hInstance, 0);
2584   if (hWnd)
2585   {
2586     SetWindowLongPtrW(hWnd, 0, wnd_extra);
2587 
2588     if (wndProc) SetWindowLongPtrA(hWnd, GWLP_WNDPROC, wndProc);
2589   }
2590 
2591   return hWnd;
2592 }
2593 
2594 typedef struct tagPOLICYDATA
2595 {
2596   DWORD policy;        /* flags value passed to SHRestricted */
2597   LPCWSTR appstr;      /* application str such as "Explorer" */
2598   LPCWSTR keystr;      /* name of the actual registry key / policy */
2599 } POLICYDATA, *LPPOLICYDATA;
2600 
2601 #define SHELL_NO_POLICY 0xffffffff
2602 
2603 /* default shell policy registry key */
2604 static const WCHAR strRegistryPolicyW[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o',
2605                                       's','o','f','t','\\','W','i','n','d','o','w','s','\\',
2606                                       'C','u','r','r','e','n','t','V','e','r','s','i','o','n',
2607                                       '\\','P','o','l','i','c','i','e','s',0};
2608 
2609 /*************************************************************************
2610  * @                          [SHLWAPI.271]
2611  *
2612  * Retrieve a policy value from the registry.
2613  *
2614  * PARAMS
2615  *  lpSubKey   [I]   registry key name
2616  *  lpSubName  [I]   subname of registry key
2617  *  lpValue    [I]   value name of registry value
2618  *
2619  * RETURNS
2620  *  the value associated with the registry key or 0 if not found
2621  */
2622 DWORD WINAPI SHGetRestriction(LPCWSTR lpSubKey, LPCWSTR lpSubName, LPCWSTR lpValue)
2623 {
2624 	DWORD retval, datsize = sizeof(retval);
2625 	HKEY hKey;
2626 
2627 	if (!lpSubKey)
2628 	  lpSubKey = strRegistryPolicyW;
2629 
2630 	retval = RegOpenKeyW(HKEY_LOCAL_MACHINE, lpSubKey, &hKey);
2631         if (retval != ERROR_SUCCESS)
2632 	  retval = RegOpenKeyW(HKEY_CURRENT_USER, lpSubKey, &hKey);
2633 	if (retval != ERROR_SUCCESS)
2634 	  return 0;
2635 
2636         SHGetValueW(hKey, lpSubName, lpValue, NULL, &retval, &datsize);
2637 	RegCloseKey(hKey);
2638 	return retval;
2639 }
2640 
2641 /*************************************************************************
2642  * @                         [SHLWAPI.266]
2643  *
2644  * Helper function to retrieve the possibly cached value for a specific policy
2645  *
2646  * PARAMS
2647  *  policy     [I]   The policy to look for
2648  *  initial    [I]   Main registry key to open, if NULL use default
2649  *  polTable   [I]   Table of known policies, 0 terminated
2650  *  polArr     [I]   Cache array of policy values
2651  *
2652  * RETURNS
2653  *  The retrieved policy value or 0 if not successful
2654  *
2655  * NOTES
2656  *  This function is used by the native SHRestricted function to search for the
2657  *  policy and cache it once retrieved. The current Wine implementation uses a
2658  *  different POLICYDATA structure and implements a similar algorithm adapted to
2659  *  that structure.
2660  */
2661 DWORD WINAPI SHRestrictionLookup(
2662 	DWORD policy,
2663 	LPCWSTR initial,
2664 	LPPOLICYDATA polTable,
2665 	LPDWORD polArr)
2666 {
2667 	TRACE("(0x%08x %s %p %p)\n", policy, debugstr_w(initial), polTable, polArr);
2668 
2669 	if (!polTable || !polArr)
2670 	  return 0;
2671 
2672 	for (;polTable->policy; polTable++, polArr++)
2673 	{
2674 	  if (policy == polTable->policy)
2675 	  {
2676 	    /* we have a known policy */
2677 
2678 	    /* check if this policy has been cached */
2679             if (*polArr == SHELL_NO_POLICY)
2680 	      *polArr = SHGetRestriction(initial, polTable->appstr, polTable->keystr);
2681 	    return *polArr;
2682 	  }
2683 	}
2684 	/* we don't know this policy, return 0 */
2685 	TRACE("unknown policy: (%08x)\n", policy);
2686 	return 0;
2687 }
2688 
2689 /*************************************************************************
2690  *      @	[SHLWAPI.267]
2691  *
2692  * Get an interface from an object.
2693  *
2694  * RETURNS
2695  *  Success: S_OK. ppv contains the requested interface.
2696  *  Failure: An HRESULT error code.
2697  *
2698  * NOTES
2699  *   This QueryInterface asks the inner object for an interface. In case
2700  *   of aggregation this request would be forwarded by the inner to the
2701  *   outer object. This function asks the inner object directly for the
2702  *   interface circumventing the forwarding to the outer object.
2703  */
2704 HRESULT WINAPI SHWeakQueryInterface(
2705 	IUnknown * pUnk,   /* [in] Outer object */
2706 	IUnknown * pInner, /* [in] Inner object */
2707 	IID * riid, /* [in] Interface GUID to query for */
2708 	LPVOID* ppv) /* [out] Destination for queried interface */
2709 {
2710 	HRESULT hret = E_NOINTERFACE;
2711 	TRACE("(pUnk=%p pInner=%p\n\tIID:  %s %p)\n",pUnk,pInner,debugstr_guid(riid), ppv);
2712 
2713 	*ppv = NULL;
2714 	if(pUnk && pInner) {
2715             hret = IUnknown_QueryInterface(pInner, riid, ppv);
2716 	    if (SUCCEEDED(hret)) IUnknown_Release(pUnk);
2717 	}
2718 	TRACE("-- 0x%08x\n", hret);
2719 	return hret;
2720 }
2721 
2722 /*************************************************************************
2723  *      @	[SHLWAPI.268]
2724  *
2725  * Move a reference from one interface to another.
2726  *
2727  * PARAMS
2728  *   lpDest     [O] Destination to receive the reference
2729  *   lppUnknown [O] Source to give up the reference to lpDest
2730  *
2731  * RETURNS
2732  *  Nothing.
2733  */
2734 VOID WINAPI SHWeakReleaseInterface(IUnknown *lpDest, IUnknown **lppUnknown)
2735 {
2736   TRACE("(%p,%p)\n", lpDest, lppUnknown);
2737 
2738   if (*lppUnknown)
2739   {
2740     /* Copy Reference*/
2741     IUnknown_AddRef(lpDest);
2742     IUnknown_AtomicRelease(lppUnknown); /* Release existing interface */
2743   }
2744 }
2745 
2746 /*************************************************************************
2747  *      @	[SHLWAPI.269]
2748  *
2749  * Convert an ASCII string of a CLSID into a CLSID.
2750  *
2751  * PARAMS
2752  *  idstr [I] String representing a CLSID in registry format
2753  *  id    [O] Destination for the converted CLSID
2754  *
2755  * RETURNS
2756  *  Success: TRUE. id contains the converted CLSID.
2757  *  Failure: FALSE.
2758  */
2759 BOOL WINAPI GUIDFromStringA(LPCSTR idstr, CLSID *id)
2760 {
2761   WCHAR wClsid[40];
2762   MultiByteToWideChar(CP_ACP, 0, idstr, -1, wClsid, sizeof(wClsid)/sizeof(WCHAR));
2763   return SUCCEEDED(CLSIDFromString(wClsid, id));
2764 }
2765 
2766 /*************************************************************************
2767  *      @	[SHLWAPI.270]
2768  *
2769  * Unicode version of GUIDFromStringA.
2770  */
2771 BOOL WINAPI GUIDFromStringW(LPCWSTR idstr, CLSID *id)
2772 {
2773     return SUCCEEDED(CLSIDFromString((LPCOLESTR)idstr, id));
2774 }
2775 
2776 /*************************************************************************
2777  *      @	[SHLWAPI.276]
2778  *
2779  * Determine if the browser is integrated into the shell, and set a registry
2780  * key accordingly.
2781  *
2782  * PARAMS
2783  *  None.
2784  *
2785  * RETURNS
2786  *  1, If the browser is not integrated.
2787  *  2, If the browser is integrated.
2788  *
2789  * NOTES
2790  *  The key "HKLM\Software\Microsoft\Internet Explorer\IntegratedBrowser" is
2791  *  either set to TRUE, or removed depending on whether the browser is deemed
2792  *  to be integrated.
2793  */
2794 DWORD WINAPI WhichPlatform(void)
2795 {
2796   static const char szIntegratedBrowser[] = "IntegratedBrowser";
2797   static DWORD dwState = 0;
2798   HKEY hKey;
2799   DWORD dwRet, dwData, dwSize;
2800   HMODULE hshell32;
2801 
2802   if (dwState)
2803     return dwState;
2804 
2805   /* If shell32 exports DllGetVersion(), the browser is integrated */
2806   dwState = 1;
2807   hshell32 = LoadLibraryA("shell32.dll");
2808   if (hshell32)
2809   {
2810     FARPROC pDllGetVersion;
2811     pDllGetVersion = GetProcAddress(hshell32, "DllGetVersion");
2812     dwState = pDllGetVersion ? 2 : 1;
2813     FreeLibrary(hshell32);
2814   }
2815 
2816   /* Set or delete the key accordingly */
2817   dwRet = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
2818                         "Software\\Microsoft\\Internet Explorer", 0,
2819                          KEY_ALL_ACCESS, &hKey);
2820   if (!dwRet)
2821   {
2822     dwRet = RegQueryValueExA(hKey, szIntegratedBrowser, 0, 0,
2823                              (LPBYTE)&dwData, &dwSize);
2824 
2825     if (!dwRet && dwState == 1)
2826     {
2827       /* Value exists but browser is not integrated */
2828       RegDeleteValueA(hKey, szIntegratedBrowser);
2829     }
2830     else if (dwRet && dwState == 2)
2831     {
2832       /* Browser is integrated but value does not exist */
2833       dwData = TRUE;
2834       RegSetValueExA(hKey, szIntegratedBrowser, 0, REG_DWORD,
2835                      (LPBYTE)&dwData, sizeof(dwData));
2836     }
2837     RegCloseKey(hKey);
2838   }
2839   return dwState;
2840 }
2841 
2842 /*************************************************************************
2843  *      @	[SHLWAPI.278]
2844  *
2845  * Unicode version of SHCreateWorkerWindowA.
2846  */
2847 HWND WINAPI SHCreateWorkerWindowW(LONG wndProc, HWND hWndParent, DWORD dwExStyle,
2848                         DWORD dwStyle, HMENU hMenu, LONG msg_result)
2849 {
2850   static const WCHAR szClass[] = { 'W', 'o', 'r', 'k', 'e', 'r', 'W', 0 };
2851   WNDCLASSW wc;
2852   HWND hWnd;
2853 
2854   TRACE("(0x%08x, %p, 0x%08x, 0x%08x, %p, 0x%08x)\n",
2855          wndProc, hWndParent, dwExStyle, dwStyle, hMenu, msg_result);
2856 
2857   /* If our OS is natively ANSI, use the ANSI version */
2858   if (GetVersion() & 0x80000000)  /* not NT */
2859   {
2860     TRACE("fallback to ANSI, ver 0x%08x\n", GetVersion());
2861     return SHCreateWorkerWindowA(wndProc, hWndParent, dwExStyle, dwStyle, hMenu, msg_result);
2862   }
2863 
2864   /* Create Window class */
2865   wc.style         = 0;
2866   wc.lpfnWndProc   = DefWindowProcW;
2867   wc.cbClsExtra    = 0;
2868   wc.cbWndExtra    = 4;
2869   wc.hInstance     = shlwapi_hInstance;
2870   wc.hIcon         = NULL;
2871   wc.hCursor       = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
2872   wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
2873   wc.lpszMenuName  = NULL;
2874   wc.lpszClassName = szClass;
2875 
2876   SHRegisterClassW(&wc);
2877 
2878   hWnd = CreateWindowExW(dwExStyle, szClass, 0, dwStyle, 0, 0, 0, 0,
2879                          hWndParent, hMenu, shlwapi_hInstance, 0);
2880   if (hWnd)
2881   {
2882     SetWindowLongPtrW(hWnd, DWLP_MSGRESULT, msg_result);
2883 
2884     if (wndProc) SetWindowLongPtrW(hWnd, GWLP_WNDPROC, wndProc);
2885   }
2886 
2887   return hWnd;
2888 }
2889 
2890 /*************************************************************************
2891  *      @	[SHLWAPI.279]
2892  *
2893  * Get and show a context menu from a shell folder.
2894  *
2895  * PARAMS
2896  *  hWnd           [I] Window displaying the shell folder
2897  *  lpFolder       [I] IShellFolder interface
2898  *  lpApidl        [I] Id for the particular folder desired
2899  *
2900  * RETURNS
2901  *  Success: S_OK.
2902  *  Failure: An HRESULT error code indicating the error.
2903  */
2904 HRESULT WINAPI SHInvokeDefaultCommand(HWND hWnd, IShellFolder* lpFolder, LPCITEMIDLIST lpApidl)
2905 {
2906     TRACE("%p %p %p\n", hWnd, lpFolder, lpApidl);
2907     return SHInvokeCommand(hWnd, lpFolder, lpApidl, 0);
2908 }
2909 
2910 /*************************************************************************
2911  *      @	[SHLWAPI.281]
2912  *
2913  * _SHPackDispParamsV
2914  */
2915 HRESULT WINAPI SHPackDispParamsV(DISPPARAMS *params, VARIANTARG *args, UINT cnt, __ms_va_list valist)
2916 {
2917   VARIANTARG *iter;
2918 
2919   TRACE("(%p %p %u ...)\n", params, args, cnt);
2920 
2921   params->rgvarg = args;
2922   params->rgdispidNamedArgs = NULL;
2923   params->cArgs = cnt;
2924   params->cNamedArgs = 0;
2925 
2926   iter = args+cnt;
2927 
2928   while(iter-- > args) {
2929     V_VT(iter) = va_arg(valist, enum VARENUM);
2930 
2931     TRACE("vt=%d\n", V_VT(iter));
2932 
2933     if(V_VT(iter) & VT_BYREF) {
2934       V_BYREF(iter) = va_arg(valist, LPVOID);
2935     } else {
2936       switch(V_VT(iter)) {
2937       case VT_I4:
2938         V_I4(iter) = va_arg(valist, LONG);
2939         break;
2940       case VT_BSTR:
2941         V_BSTR(iter) = va_arg(valist, BSTR);
2942         break;
2943       case VT_DISPATCH:
2944         V_DISPATCH(iter) = va_arg(valist, IDispatch*);
2945         break;
2946       case VT_BOOL:
2947         V_BOOL(iter) = va_arg(valist, int);
2948         break;
2949       case VT_UNKNOWN:
2950         V_UNKNOWN(iter) = va_arg(valist, IUnknown*);
2951         break;
2952       default:
2953         V_VT(iter) = VT_I4;
2954         V_I4(iter) = va_arg(valist, LONG);
2955       }
2956     }
2957   }
2958 
2959   return S_OK;
2960 }
2961 
2962 /*************************************************************************
2963  *      @       [SHLWAPI.282]
2964  *
2965  * SHPackDispParams
2966  */
2967 HRESULT WINAPIV SHPackDispParams(DISPPARAMS *params, VARIANTARG *args, UINT cnt, ...)
2968 {
2969   __ms_va_list valist;
2970   HRESULT hres;
2971 
2972   __ms_va_start(valist, cnt);
2973   hres = SHPackDispParamsV(params, args, cnt, valist);
2974   __ms_va_end(valist);
2975   return hres;
2976 }
2977 
2978 /*************************************************************************
2979  *      SHLWAPI_InvokeByIID
2980  *
2981  *   This helper function calls IDispatch::Invoke for each sink
2982  * which implements given iid or IDispatch.
2983  *
2984  */
2985 static HRESULT SHLWAPI_InvokeByIID(
2986         IConnectionPoint* iCP,
2987         REFIID iid,
2988         DISPID dispId,
2989         DISPPARAMS* dispParams)
2990 {
2991   IEnumConnections *enumerator;
2992   CONNECTDATA rgcd;
2993   static DISPPARAMS empty = {NULL, NULL, 0, 0};
2994   DISPPARAMS* params = dispParams;
2995 
2996   HRESULT result = IConnectionPoint_EnumConnections(iCP, &enumerator);
2997   if (FAILED(result))
2998     return result;
2999 
3000   /* Invoke is never happening with an NULL dispParams */
3001   if (!params)
3002     params = &empty;
3003 
3004   while(IEnumConnections_Next(enumerator, 1, &rgcd, NULL)==S_OK)
3005   {
3006     IDispatch *dispIface;
3007     if ((iid && SUCCEEDED(IUnknown_QueryInterface(rgcd.pUnk, iid, (LPVOID*)&dispIface))) ||
3008         SUCCEEDED(IUnknown_QueryInterface(rgcd.pUnk, &IID_IDispatch, (LPVOID*)&dispIface)))
3009     {
3010       IDispatch_Invoke(dispIface, dispId, &IID_NULL, 0, DISPATCH_METHOD, params, NULL, NULL, NULL);
3011       IDispatch_Release(dispIface);
3012     }
3013     IUnknown_Release(rgcd.pUnk);
3014   }
3015 
3016   IEnumConnections_Release(enumerator);
3017 
3018   return S_OK;
3019 }
3020 
3021 /*************************************************************************
3022  *  IConnectionPoint_InvokeWithCancel   [SHLWAPI.283]
3023  */
3024 HRESULT WINAPI IConnectionPoint_InvokeWithCancel( IConnectionPoint* iCP,
3025                                                   DISPID dispId, DISPPARAMS* dispParams,
3026                                                   DWORD unknown1, DWORD unknown2 )
3027 {
3028     IID iid;
3029     HRESULT result;
3030 
3031     FIXME("(%p)->(0x%x %p %x %x) partial stub\n", iCP, dispId, dispParams, unknown1, unknown2);
3032 
3033     result = IConnectionPoint_GetConnectionInterface(iCP, &iid);
3034     if (SUCCEEDED(result))
3035         result = SHLWAPI_InvokeByIID(iCP, &iid, dispId, dispParams);
3036     else
3037         result = SHLWAPI_InvokeByIID(iCP, NULL, dispId, dispParams);
3038 
3039     return result;
3040 }
3041 
3042 
3043 /*************************************************************************
3044  *      @	[SHLWAPI.284]
3045  *
3046  *  IConnectionPoint_SimpleInvoke
3047  */
3048 HRESULT WINAPI IConnectionPoint_SimpleInvoke(
3049         IConnectionPoint* iCP,
3050         DISPID dispId,
3051         DISPPARAMS* dispParams)
3052 {
3053   IID iid;
3054   HRESULT result;
3055 
3056   TRACE("(%p)->(0x%x %p)\n",iCP,dispId,dispParams);
3057 
3058   result = IConnectionPoint_GetConnectionInterface(iCP, &iid);
3059   if (SUCCEEDED(result))
3060     result = SHLWAPI_InvokeByIID(iCP, &iid, dispId, dispParams);
3061   else
3062     result = SHLWAPI_InvokeByIID(iCP, NULL, dispId, dispParams);
3063 
3064   return result;
3065 }
3066 
3067 /*************************************************************************
3068  *      @	[SHLWAPI.285]
3069  *
3070  * Notify an IConnectionPoint object of changes.
3071  *
3072  * PARAMS
3073  *  lpCP   [I] Object to notify
3074  *  dispID [I]
3075  *
3076  * RETURNS
3077  *  Success: S_OK.
3078  *  Failure: E_NOINTERFACE, if lpCP is NULL or does not support the
3079  *           IConnectionPoint interface.
3080  */
3081 HRESULT WINAPI IConnectionPoint_OnChanged(IConnectionPoint* lpCP, DISPID dispID)
3082 {
3083   IEnumConnections *lpEnum;
3084   HRESULT hRet = E_NOINTERFACE;
3085 
3086   TRACE("(%p,0x%8X)\n", lpCP, dispID);
3087 
3088   /* Get an enumerator for the connections */
3089   if (lpCP)
3090     hRet = IConnectionPoint_EnumConnections(lpCP, &lpEnum);
3091 
3092   if (SUCCEEDED(hRet))
3093   {
3094     IPropertyNotifySink *lpSink;
3095     CONNECTDATA connData;
3096     ULONG ulFetched;
3097 
3098     /* Call OnChanged() for every notify sink in the connection point */
3099     while (IEnumConnections_Next(lpEnum, 1, &connData, &ulFetched) == S_OK)
3100     {
3101       if (SUCCEEDED(IUnknown_QueryInterface(connData.pUnk, &IID_IPropertyNotifySink, (void**)&lpSink)) &&
3102           lpSink)
3103       {
3104         IPropertyNotifySink_OnChanged(lpSink, dispID);
3105         IPropertyNotifySink_Release(lpSink);
3106       }
3107       IUnknown_Release(connData.pUnk);
3108     }
3109 
3110     IEnumConnections_Release(lpEnum);
3111   }
3112   return hRet;
3113 }
3114 
3115 /*************************************************************************
3116  *      @	[SHLWAPI.286]
3117  *
3118  *  IUnknown_CPContainerInvokeParam
3119  */
3120 HRESULT WINAPIV IUnknown_CPContainerInvokeParam(
3121         IUnknown *container,
3122         REFIID riid,
3123         DISPID dispId,
3124         VARIANTARG* buffer,
3125         DWORD cParams, ...)
3126 {
3127   HRESULT result;
3128   IConnectionPoint *iCP;
3129   IConnectionPointContainer *iCPC;
3130   DISPPARAMS dispParams = {buffer, NULL, cParams, 0};
3131   __ms_va_list valist;
3132 
3133   if (!container)
3134     return E_NOINTERFACE;
3135 
3136   result = IUnknown_QueryInterface(container, &IID_IConnectionPointContainer,(LPVOID*) &iCPC);
3137   if (FAILED(result))
3138       return result;
3139 
3140   result = IConnectionPointContainer_FindConnectionPoint(iCPC, riid, &iCP);
3141   IConnectionPointContainer_Release(iCPC);
3142   if(FAILED(result))
3143       return result;
3144 
3145   __ms_va_start(valist, cParams);
3146   SHPackDispParamsV(&dispParams, buffer, cParams, valist);
3147   __ms_va_end(valist);
3148 
3149   result = SHLWAPI_InvokeByIID(iCP, riid, dispId, &dispParams);
3150   IConnectionPoint_Release(iCP);
3151 
3152   return result;
3153 }
3154 
3155 /*************************************************************************
3156  *      @	[SHLWAPI.287]
3157  *
3158  * Notify an IConnectionPointContainer object of changes.
3159  *
3160  * PARAMS
3161  *  lpUnknown [I] Object to notify
3162  *  dispID    [I]
3163  *
3164  * RETURNS
3165  *  Success: S_OK.
3166  *  Failure: E_NOINTERFACE, if lpUnknown is NULL or does not support the
3167  *           IConnectionPointContainer interface.
3168  */
3169 HRESULT WINAPI IUnknown_CPContainerOnChanged(IUnknown *lpUnknown, DISPID dispID)
3170 {
3171   IConnectionPointContainer* lpCPC = NULL;
3172   HRESULT hRet = E_NOINTERFACE;
3173 
3174   TRACE("(%p,0x%8X)\n", lpUnknown, dispID);
3175 
3176   if (lpUnknown)
3177     hRet = IUnknown_QueryInterface(lpUnknown, &IID_IConnectionPointContainer, (void**)&lpCPC);
3178 
3179   if (SUCCEEDED(hRet))
3180   {
3181     IConnectionPoint* lpCP;
3182 
3183     hRet = IConnectionPointContainer_FindConnectionPoint(lpCPC, &IID_IPropertyNotifySink, &lpCP);
3184     IConnectionPointContainer_Release(lpCPC);
3185 
3186     hRet = IConnectionPoint_OnChanged(lpCP, dispID);
3187     IConnectionPoint_Release(lpCP);
3188   }
3189   return hRet;
3190 }
3191 
3192 /*************************************************************************
3193  *      @	[SHLWAPI.289]
3194  *
3195  * See PlaySoundW.
3196  */
3197 BOOL WINAPI PlaySoundWrapW(LPCWSTR pszSound, HMODULE hmod, DWORD fdwSound)
3198 {
3199     return PlaySoundW(pszSound, hmod, fdwSound);
3200 }
3201 
3202 /*************************************************************************
3203  *      @	[SHLWAPI.294]
3204  *
3205  * Retrieve a key value from an INI file.  See GetPrivateProfileString for
3206  * more information.
3207  *
3208  * PARAMS
3209  *  appName   [I] The section in the INI file that contains the key
3210  *  keyName   [I] The key to be retrieved
3211  *  out       [O] The buffer into which the key's value will be copied
3212  *  outLen    [I] The length of the `out' buffer
3213  *  filename  [I] The location of the INI file
3214  *
3215  * RETURNS
3216  *  Length of string copied into `out'.
3217  */
3218 DWORD WINAPI SHGetIniStringW(LPCWSTR appName, LPCWSTR keyName, LPWSTR out,
3219         DWORD outLen, LPCWSTR filename)
3220 {
3221     INT ret;
3222     WCHAR *buf;
3223 
3224     TRACE("(%s,%s,%p,%08x,%s)\n", debugstr_w(appName), debugstr_w(keyName),
3225         out, outLen, debugstr_w(filename));
3226 
3227     if(outLen == 0)
3228         return 0;
3229 
3230     buf = HeapAlloc(GetProcessHeap(), 0, outLen * sizeof(WCHAR));
3231     if(!buf){
3232         *out = 0;
3233         return 0;
3234     }
3235 
3236     ret = GetPrivateProfileStringW(appName, keyName, NULL, buf, outLen, filename);
3237     if(ret)
3238         strcpyW(out, buf);
3239     else
3240         *out = 0;
3241 
3242     HeapFree(GetProcessHeap(), 0, buf);
3243 
3244     return strlenW(out);
3245 }
3246 
3247 /*************************************************************************
3248  *      @	[SHLWAPI.295]
3249  *
3250  * Set a key value in an INI file.  See WritePrivateProfileString for
3251  * more information.
3252  *
3253  * PARAMS
3254  *  appName   [I] The section in the INI file that contains the key
3255  *  keyName   [I] The key to be set
3256  *  str       [O] The value of the key
3257  *  filename  [I] The location of the INI file
3258  *
3259  * RETURNS
3260  *   Success: TRUE
3261  *   Failure: FALSE
3262  */
3263 BOOL WINAPI SHSetIniStringW(LPCWSTR appName, LPCWSTR keyName, LPCWSTR str,
3264         LPCWSTR filename)
3265 {
3266     TRACE("(%s, %p, %s, %s)\n", debugstr_w(appName), keyName, debugstr_w(str),
3267             debugstr_w(filename));
3268 
3269     return WritePrivateProfileStringW(appName, keyName, str, filename);
3270 }
3271 
3272 /*************************************************************************
3273  *      @	[SHLWAPI.313]
3274  *
3275  * See SHGetFileInfoW.
3276  */
3277 DWORD WINAPI SHGetFileInfoWrapW(LPCWSTR path, DWORD dwFileAttributes,
3278                          SHFILEINFOW *psfi, UINT sizeofpsfi, UINT flags)
3279 {
3280     return SHGetFileInfoW(path, dwFileAttributes, psfi, sizeofpsfi, flags);
3281 }
3282 
3283 /*************************************************************************
3284  *      @	[SHLWAPI.318]
3285  *
3286  * See DragQueryFileW.
3287  */
3288 UINT WINAPI DragQueryFileWrapW(HDROP hDrop, UINT lFile, LPWSTR lpszFile, UINT lLength)
3289 {
3290     return DragQueryFileW(hDrop, lFile, lpszFile, lLength);
3291 }
3292 
3293 /*************************************************************************
3294  *      @	[SHLWAPI.333]
3295  *
3296  * See SHBrowseForFolderW.
3297  */
3298 LPITEMIDLIST WINAPI SHBrowseForFolderWrapW(LPBROWSEINFOW lpBi)
3299 {
3300     return SHBrowseForFolderW(lpBi);
3301 }
3302 
3303 /*************************************************************************
3304  *      @	[SHLWAPI.334]
3305  *
3306  * See SHGetPathFromIDListW.
3307  */
3308 BOOL WINAPI SHGetPathFromIDListWrapW(LPCITEMIDLIST pidl,LPWSTR pszPath)
3309 {
3310     return SHGetPathFromIDListW(pidl, pszPath);
3311 }
3312 
3313 /*************************************************************************
3314  *      @	[SHLWAPI.335]
3315  *
3316  * See ShellExecuteExW.
3317  */
3318 BOOL WINAPI ShellExecuteExWrapW(LPSHELLEXECUTEINFOW lpExecInfo)
3319 {
3320     return ShellExecuteExW(lpExecInfo);
3321 }
3322 
3323 /*************************************************************************
3324  *      @	[SHLWAPI.336]
3325  *
3326  * See SHFileOperationW.
3327  */
3328 INT WINAPI SHFileOperationWrapW(LPSHFILEOPSTRUCTW lpFileOp)
3329 {
3330     return SHFileOperationW(lpFileOp);
3331 }
3332 
3333 /*************************************************************************
3334  *      @	[SHLWAPI.342]
3335  *
3336  */
3337 PVOID WINAPI SHInterlockedCompareExchange( PVOID *dest, PVOID xchg, PVOID compare )
3338 {
3339     return InterlockedCompareExchangePointer( dest, xchg, compare );
3340 }
3341 
3342 /*************************************************************************
3343  *      @	[SHLWAPI.350]
3344  *
3345  * See GetFileVersionInfoSizeW.
3346  */
3347 DWORD WINAPI GetFileVersionInfoSizeWrapW( LPCWSTR filename, LPDWORD handle )
3348 {
3349     return GetFileVersionInfoSizeW( filename, handle );
3350 }
3351 
3352 /*************************************************************************
3353  *      @	[SHLWAPI.351]
3354  *
3355  * See GetFileVersionInfoW.
3356  */
3357 BOOL  WINAPI GetFileVersionInfoWrapW( LPCWSTR filename, DWORD handle,
3358                                       DWORD datasize, LPVOID data )
3359 {
3360     return GetFileVersionInfoW( filename, handle, datasize, data );
3361 }
3362 
3363 /*************************************************************************
3364  *      @	[SHLWAPI.352]
3365  *
3366  * See VerQueryValueW.
3367  */
3368 WORD WINAPI VerQueryValueWrapW( LPVOID pBlock, LPCWSTR lpSubBlock,
3369                                 LPVOID *lplpBuffer, UINT *puLen )
3370 {
3371     return VerQueryValueW( pBlock, lpSubBlock, lplpBuffer, puLen );
3372 }
3373 
3374 #define IsIface(type) SUCCEEDED((hRet = IUnknown_QueryInterface(lpUnknown, &IID_##type, (void**)&lpObj)))
3375 #define IShellBrowser_EnableModeless IShellBrowser_EnableModelessSB
3376 #define EnableModeless(type) type##_EnableModeless((type*)lpObj, bModeless)
3377 
3378 /*************************************************************************
3379  *      @	[SHLWAPI.355]
3380  *
3381  * Change the modality of a shell object.
3382  *
3383  * PARAMS
3384  *  lpUnknown [I] Object to make modeless
3385  *  bModeless [I] TRUE=Make modeless, FALSE=Make modal
3386  *
3387  * RETURNS
3388  *  Success: S_OK. The modality lpUnknown is changed.
3389  *  Failure: An HRESULT error code indicating the error.
3390  *
3391  * NOTES
3392  *  lpUnknown must support the IOleInPlaceFrame interface, the
3393  *  IInternetSecurityMgrSite interface, the IShellBrowser interface
3394  *  the IDocHostUIHandler interface, or the IOleInPlaceActiveObject interface,
3395  *  or this call will fail.
3396  */
3397 HRESULT WINAPI IUnknown_EnableModeless(IUnknown *lpUnknown, BOOL bModeless)
3398 {
3399   IUnknown *lpObj;
3400   HRESULT hRet;
3401 
3402   TRACE("(%p,%d)\n", lpUnknown, bModeless);
3403 
3404   if (!lpUnknown)
3405     return E_FAIL;
3406 
3407   if (IsIface(IOleInPlaceActiveObject))
3408     EnableModeless(IOleInPlaceActiveObject);
3409   else if (IsIface(IOleInPlaceFrame))
3410     EnableModeless(IOleInPlaceFrame);
3411   else if (IsIface(IShellBrowser))
3412     EnableModeless(IShellBrowser);
3413   else if (IsIface(IInternetSecurityMgrSite))
3414     EnableModeless(IInternetSecurityMgrSite);
3415   else if (IsIface(IDocHostUIHandler))
3416     EnableModeless(IDocHostUIHandler);
3417   else
3418     return hRet;
3419 
3420   IUnknown_Release(lpObj);
3421   return S_OK;
3422 }
3423 
3424 /*************************************************************************
3425  *      @	[SHLWAPI.357]
3426  *
3427  * See SHGetNewLinkInfoW.
3428  */
3429 BOOL WINAPI SHGetNewLinkInfoWrapW(LPCWSTR pszLinkTo, LPCWSTR pszDir, LPWSTR pszName,
3430                         BOOL *pfMustCopy, UINT uFlags)
3431 {
3432     return SHGetNewLinkInfoW(pszLinkTo, pszDir, pszName, pfMustCopy, uFlags);
3433 }
3434 
3435 /*************************************************************************
3436  *      @	[SHLWAPI.358]
3437  *
3438  * See SHDefExtractIconW.
3439  */
3440 UINT WINAPI SHDefExtractIconWrapW(LPCWSTR pszIconFile, int iIndex, UINT uFlags, HICON* phiconLarge,
3441                          HICON* phiconSmall, UINT nIconSize)
3442 {
3443     return SHDefExtractIconW(pszIconFile, iIndex, uFlags, phiconLarge, phiconSmall, nIconSize);
3444 }
3445 
3446 /*************************************************************************
3447  *      @	[SHLWAPI.363]
3448  *
3449  * Get and show a context menu from a shell folder.
3450  *
3451  * PARAMS
3452  *  hWnd           [I] Window displaying the shell folder
3453  *  lpFolder       [I] IShellFolder interface
3454  *  lpApidl        [I] Id for the particular folder desired
3455  *  dwCommandId    [I] The command ID to invoke (0=invoke default)
3456  *
3457  * RETURNS
3458  *  Success: S_OK. If bInvokeDefault is TRUE, the default menu action was
3459  *           executed.
3460  *  Failure: An HRESULT error code indicating the error.
3461  */
3462 HRESULT WINAPI SHInvokeCommand(HWND hWnd, IShellFolder* lpFolder, LPCITEMIDLIST lpApidl, DWORD dwCommandId)
3463 {
3464   IContextMenu *iContext;
3465   HRESULT hRet;
3466 
3467   TRACE("(%p, %p, %p, %u)\n", hWnd, lpFolder, lpApidl, dwCommandId);
3468 
3469   if (!lpFolder)
3470     return E_FAIL;
3471 
3472   /* Get the context menu from the shell folder */
3473   hRet = IShellFolder_GetUIObjectOf(lpFolder, hWnd, 1, &lpApidl,
3474                                     &IID_IContextMenu, 0, (void**)&iContext);
3475   if (SUCCEEDED(hRet))
3476   {
3477     HMENU hMenu;
3478     if ((hMenu = CreatePopupMenu()))
3479     {
3480       HRESULT hQuery;
3481 
3482       /* Add the context menu entries to the popup */
3483       hQuery = IContextMenu_QueryContextMenu(iContext, hMenu, 0, 1, 0x7FFF,
3484                                              dwCommandId ? CMF_NORMAL : CMF_DEFAULTONLY);
3485 
3486       if (SUCCEEDED(hQuery))
3487       {
3488         if (!dwCommandId)
3489           dwCommandId = GetMenuDefaultItem(hMenu, 0, 0);
3490         if (dwCommandId != (UINT)-1)
3491         {
3492           CMINVOKECOMMANDINFO cmIci;
3493           /* Invoke the default item */
3494           memset(&cmIci,0,sizeof(cmIci));
3495           cmIci.cbSize = sizeof(cmIci);
3496           cmIci.fMask = CMIC_MASK_ASYNCOK;
3497           cmIci.hwnd = hWnd;
3498 #ifdef __REACTOS__ /* r75561 */
3499           cmIci.lpVerb = MAKEINTRESOURCEA(dwCommandId - 1);
3500 #else
3501           cmIci.lpVerb = MAKEINTRESOURCEA(dwCommandId);
3502 #endif
3503           cmIci.nShow = SW_SHOWNORMAL;
3504 
3505           hRet = IContextMenu_InvokeCommand(iContext, &cmIci);
3506         }
3507       }
3508       DestroyMenu(hMenu);
3509     }
3510     IContextMenu_Release(iContext);
3511   }
3512   return hRet;
3513 }
3514 
3515 /*************************************************************************
3516  *      @	[SHLWAPI.370]
3517  *
3518  * See ExtractIconW.
3519  */
3520 HICON WINAPI ExtractIconWrapW(HINSTANCE hInstance, LPCWSTR lpszExeFileName,
3521                          UINT nIconIndex)
3522 {
3523     return ExtractIconW(hInstance, lpszExeFileName, nIconIndex);
3524 }
3525 
3526 /*************************************************************************
3527  *      @	[SHLWAPI.377]
3528  *
3529  * Load a library from the directory of a particular process.
3530  *
3531  * PARAMS
3532  *  new_mod        [I] Library name
3533  *  inst_hwnd      [I] Module whose directory is to be used
3534  *  dwCrossCodePage [I] Should be FALSE (currently ignored)
3535  *
3536  * RETURNS
3537  *  Success: A handle to the loaded module
3538  *  Failure: A NULL handle.
3539  */
3540 HMODULE WINAPI MLLoadLibraryA(LPCSTR new_mod, HMODULE inst_hwnd, DWORD dwCrossCodePage)
3541 {
3542   /* FIXME: Native appears to do DPA_Create and a DPA_InsertPtr for
3543    *        each call here.
3544    * FIXME: Native shows calls to:
3545    *  SHRegGetUSValue for "Software\Microsoft\Internet Explorer\International"
3546    *                      CheckVersion
3547    *  RegOpenKeyExA for "HKLM\Software\Microsoft\Internet Explorer"
3548    *  RegQueryValueExA for "LPKInstalled"
3549    *  RegCloseKey
3550    *  RegOpenKeyExA for "HKCU\Software\Microsoft\Internet Explorer\International"
3551    *  RegQueryValueExA for "ResourceLocale"
3552    *  RegCloseKey
3553    *  RegOpenKeyExA for "HKLM\Software\Microsoft\Active Setup\Installed Components\{guid}"
3554    *  RegQueryValueExA for "Locale"
3555    *  RegCloseKey
3556    *  and then tests the Locale ("en" for me).
3557    *     code below
3558    *  after the code then a DPA_Create (first time) and DPA_InsertPtr are done.
3559    */
3560     CHAR mod_path[2*MAX_PATH];
3561     LPSTR ptr;
3562     DWORD len;
3563 
3564     FIXME("(%s,%p,%d) semi-stub!\n", debugstr_a(new_mod), inst_hwnd, dwCrossCodePage);
3565     len = GetModuleFileNameA(inst_hwnd, mod_path, sizeof(mod_path));
3566     if (!len || len >= sizeof(mod_path)) return NULL;
3567 
3568     ptr = strrchr(mod_path, '\\');
3569     if (ptr) {
3570 	strcpy(ptr+1, new_mod);
3571 	TRACE("loading %s\n", debugstr_a(mod_path));
3572 	return LoadLibraryA(mod_path);
3573     }
3574     return NULL;
3575 }
3576 
3577 /*************************************************************************
3578  *      @	[SHLWAPI.378]
3579  *
3580  * Unicode version of MLLoadLibraryA.
3581  */
3582 HMODULE WINAPI MLLoadLibraryW(LPCWSTR new_mod, HMODULE inst_hwnd, DWORD dwCrossCodePage)
3583 {
3584     WCHAR mod_path[2*MAX_PATH];
3585     LPWSTR ptr;
3586     DWORD len;
3587 
3588     FIXME("(%s,%p,%d) semi-stub!\n", debugstr_w(new_mod), inst_hwnd, dwCrossCodePage);
3589     len = GetModuleFileNameW(inst_hwnd, mod_path, sizeof(mod_path) / sizeof(WCHAR));
3590     if (!len || len >= sizeof(mod_path) / sizeof(WCHAR)) return NULL;
3591 
3592     ptr = strrchrW(mod_path, '\\');
3593     if (ptr) {
3594 	strcpyW(ptr+1, new_mod);
3595 	TRACE("loading %s\n", debugstr_w(mod_path));
3596 	return LoadLibraryW(mod_path);
3597     }
3598     return NULL;
3599 }
3600 
3601 /*************************************************************************
3602  * ColorAdjustLuma      [SHLWAPI.@]
3603  *
3604  * Adjust the luminosity of a color
3605  *
3606  * PARAMS
3607  *  cRGB         [I] RGB value to convert
3608  *  dwLuma       [I] Luma adjustment
3609  *  bUnknown     [I] Unknown
3610  *
3611  * RETURNS
3612  *  The adjusted RGB color.
3613  */
3614 COLORREF WINAPI ColorAdjustLuma(COLORREF cRGB, int dwLuma, BOOL bUnknown)
3615 {
3616   TRACE("(0x%8x,%d,%d)\n", cRGB, dwLuma, bUnknown);
3617 
3618   if (dwLuma)
3619   {
3620     WORD wH, wL, wS;
3621 
3622     ColorRGBToHLS(cRGB, &wH, &wL, &wS);
3623 
3624     FIXME("Ignoring luma adjustment\n");
3625 
3626     /* FIXME: The adjustment is not linear */
3627 
3628     cRGB = ColorHLSToRGB(wH, wL, wS);
3629   }
3630   return cRGB;
3631 }
3632 
3633 /*************************************************************************
3634  *      @	[SHLWAPI.389]
3635  *
3636  * See GetSaveFileNameW.
3637  */
3638 BOOL WINAPI GetSaveFileNameWrapW(LPOPENFILENAMEW ofn)
3639 {
3640     return GetSaveFileNameW(ofn);
3641 }
3642 
3643 /*************************************************************************
3644  *      @	[SHLWAPI.390]
3645  *
3646  * See WNetRestoreConnectionW.
3647  */
3648 DWORD WINAPI WNetRestoreConnectionWrapW(HWND hwndOwner, LPWSTR lpszDevice)
3649 {
3650     return WNetRestoreConnectionW(hwndOwner, lpszDevice);
3651 }
3652 
3653 /*************************************************************************
3654  *      @	[SHLWAPI.391]
3655  *
3656  * See WNetGetLastErrorW.
3657  */
3658 DWORD WINAPI WNetGetLastErrorWrapW(LPDWORD lpError, LPWSTR lpErrorBuf, DWORD nErrorBufSize,
3659                          LPWSTR lpNameBuf, DWORD nNameBufSize)
3660 {
3661     return WNetGetLastErrorW(lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize);
3662 }
3663 
3664 /*************************************************************************
3665  *      @	[SHLWAPI.401]
3666  *
3667  * See PageSetupDlgW.
3668  */
3669 BOOL WINAPI PageSetupDlgWrapW(LPPAGESETUPDLGW pagedlg)
3670 {
3671     return PageSetupDlgW(pagedlg);
3672 }
3673 
3674 /*************************************************************************
3675  *      @	[SHLWAPI.402]
3676  *
3677  * See PrintDlgW.
3678  */
3679 BOOL WINAPI PrintDlgWrapW(LPPRINTDLGW printdlg)
3680 {
3681     return PrintDlgW(printdlg);
3682 }
3683 
3684 /*************************************************************************
3685  *      @	[SHLWAPI.403]
3686  *
3687  * See GetOpenFileNameW.
3688  */
3689 BOOL WINAPI GetOpenFileNameWrapW(LPOPENFILENAMEW ofn)
3690 {
3691     return GetOpenFileNameW(ofn);
3692 }
3693 
3694 /*************************************************************************
3695  *      @	[SHLWAPI.404]
3696  */
3697 HRESULT WINAPI SHIShellFolder_EnumObjects(LPSHELLFOLDER lpFolder, HWND hwnd, SHCONTF flags, IEnumIDList **ppenum)
3698 {
3699     /* Windows attempts to get an IPersist interface and, if that fails, an
3700      * IPersistFolder interface on the folder passed-in here.  If one of those
3701      * interfaces is available, it then calls GetClassID on the folder... and
3702      * then calls IShellFolder_EnumObjects no matter what, even crashing if
3703      * lpFolder isn't actually an IShellFolder object.  The purpose of getting
3704      * the ClassID is unknown, so we don't do it here.
3705      *
3706      * For discussion and detailed tests, see:
3707      * "shlwapi: Be less strict on which type of IShellFolder can be enumerated"
3708      * wine-devel mailing list, 3 Jun 2010
3709      */
3710 
3711     return IShellFolder_EnumObjects(lpFolder, hwnd, flags, ppenum);
3712 }
3713 
3714 /* INTERNAL: Map from HLS color space to RGB */
3715 static WORD ConvertHue(int wHue, WORD wMid1, WORD wMid2)
3716 {
3717   wHue = wHue > 240 ? wHue - 240 : wHue < 0 ? wHue + 240 : wHue;
3718 
3719   if (wHue > 160)
3720     return wMid1;
3721   else if (wHue > 120)
3722     wHue = 160 - wHue;
3723   else if (wHue > 40)
3724     return wMid2;
3725 
3726   return ((wHue * (wMid2 - wMid1) + 20) / 40) + wMid1;
3727 }
3728 
3729 /* Convert to RGB and scale into RGB range (0..255) */
3730 #define GET_RGB(h) (ConvertHue(h, wMid1, wMid2) * 255 + 120) / 240
3731 
3732 /*************************************************************************
3733  *      ColorHLSToRGB	[SHLWAPI.@]
3734  *
3735  * Convert from hls color space into an rgb COLORREF.
3736  *
3737  * PARAMS
3738  *  wHue        [I] Hue amount
3739  *  wLuminosity [I] Luminosity amount
3740  *  wSaturation [I] Saturation amount
3741  *
3742  * RETURNS
3743  *  A COLORREF representing the converted color.
3744  *
3745  * NOTES
3746  *  Input hls values are constrained to the range (0..240).
3747  */
3748 COLORREF WINAPI ColorHLSToRGB(WORD wHue, WORD wLuminosity, WORD wSaturation)
3749 {
3750   WORD wRed;
3751 
3752   if (wSaturation)
3753   {
3754     WORD wGreen, wBlue, wMid1, wMid2;
3755 
3756     if (wLuminosity > 120)
3757       wMid2 = wSaturation + wLuminosity - (wSaturation * wLuminosity + 120) / 240;
3758     else
3759       wMid2 = ((wSaturation + 240) * wLuminosity + 120) / 240;
3760 
3761     wMid1 = wLuminosity * 2 - wMid2;
3762 
3763     wRed   = GET_RGB(wHue + 80);
3764     wGreen = GET_RGB(wHue);
3765     wBlue  = GET_RGB(wHue - 80);
3766 
3767     return RGB(wRed, wGreen, wBlue);
3768   }
3769 
3770   wRed = wLuminosity * 255 / 240;
3771   return RGB(wRed, wRed, wRed);
3772 }
3773 
3774 /*************************************************************************
3775  *      @	[SHLWAPI.413]
3776  *
3777  * Get the current docking status of the system.
3778  *
3779  * PARAMS
3780  *  dwFlags [I] DOCKINFO_ flags from "winbase.h", unused
3781  *
3782  * RETURNS
3783  *  One of DOCKINFO_UNDOCKED, DOCKINFO_UNDOCKED, or 0 if the system is not
3784  *  a notebook.
3785  */
3786 DWORD WINAPI SHGetMachineInfo(DWORD dwFlags)
3787 {
3788   HW_PROFILE_INFOA hwInfo;
3789 
3790   TRACE("(0x%08x)\n", dwFlags);
3791 
3792   GetCurrentHwProfileA(&hwInfo);
3793   switch (hwInfo.dwDockInfo & (DOCKINFO_DOCKED|DOCKINFO_UNDOCKED))
3794   {
3795   case DOCKINFO_DOCKED:
3796   case DOCKINFO_UNDOCKED:
3797     return hwInfo.dwDockInfo & (DOCKINFO_DOCKED|DOCKINFO_UNDOCKED);
3798   default:
3799     return 0;
3800   }
3801 }
3802 
3803 /*************************************************************************
3804  * @    [SHLWAPI.416]
3805  *
3806  */
3807 DWORD WINAPI SHWinHelpOnDemandW(HWND hwnd, LPCWSTR helpfile, DWORD flags1, VOID *ptr1, DWORD flags2)
3808 {
3809 
3810     FIXME("(%p, %s, 0x%x, %p, %d)\n", hwnd, debugstr_w(helpfile), flags1, ptr1, flags2);
3811     return 0;
3812 }
3813 
3814 /*************************************************************************
3815  * @    [SHLWAPI.417]
3816  *
3817  */
3818 DWORD WINAPI SHWinHelpOnDemandA(HWND hwnd, LPCSTR helpfile, DWORD flags1, VOID *ptr1, DWORD flags2)
3819 {
3820 
3821     FIXME("(%p, %s, 0x%x, %p, %d)\n", hwnd, debugstr_a(helpfile), flags1, ptr1, flags2);
3822     return 0;
3823 }
3824 
3825 /*************************************************************************
3826  *      @	[SHLWAPI.418]
3827  *
3828  * Function seems to do FreeLibrary plus other things.
3829  *
3830  * FIXME native shows the following calls:
3831  *   RtlEnterCriticalSection
3832  *   LocalFree
3833  *   GetProcAddress(Comctl32??, 150L)
3834  *   DPA_DeletePtr
3835  *   RtlLeaveCriticalSection
3836  *  followed by the FreeLibrary.
3837  *  The above code may be related to .377 above.
3838  */
3839 BOOL WINAPI MLFreeLibrary(HMODULE hModule)
3840 {
3841 	FIXME("(%p) semi-stub\n", hModule);
3842 	return FreeLibrary(hModule);
3843 }
3844 
3845 /*************************************************************************
3846  *      @	[SHLWAPI.419]
3847  */
3848 BOOL WINAPI SHFlushSFCacheWrap(void) {
3849   FIXME(": stub\n");
3850   return TRUE;
3851 }
3852 
3853 /*************************************************************************
3854  *      @      [SHLWAPI.429]
3855  * FIXME I have no idea what this function does or what its arguments are.
3856  */
3857 BOOL WINAPI MLIsMLHInstance(HINSTANCE hInst)
3858 {
3859        FIXME("(%p) stub\n", hInst);
3860        return FALSE;
3861 }
3862 
3863 
3864 /*************************************************************************
3865  *      @	[SHLWAPI.430]
3866  */
3867 DWORD WINAPI MLSetMLHInstance(HINSTANCE hInst, HANDLE hHeap)
3868 {
3869 	FIXME("(%p,%p) stub\n", hInst, hHeap);
3870 	return E_FAIL;   /* This is what is used if shlwapi not loaded */
3871 }
3872 
3873 /*************************************************************************
3874  *      @	[SHLWAPI.431]
3875  */
3876 DWORD WINAPI MLClearMLHInstance(DWORD x)
3877 {
3878 	FIXME("(0x%08x)stub\n", x);
3879 	return 0xabba1247;
3880 }
3881 
3882 /*************************************************************************
3883  * @ [SHLWAPI.432]
3884  *
3885  * See SHSendMessageBroadcastW
3886  *
3887  */
3888 DWORD WINAPI SHSendMessageBroadcastA(UINT uMsg, WPARAM wParam, LPARAM lParam)
3889 {
3890     return SendMessageTimeoutA(HWND_BROADCAST, uMsg, wParam, lParam,
3891                                SMTO_ABORTIFHUNG, 2000, NULL);
3892 }
3893 
3894 /*************************************************************************
3895  * @ [SHLWAPI.433]
3896  *
3897  * A wrapper for sending Broadcast Messages to all top level Windows
3898  *
3899  */
3900 DWORD WINAPI SHSendMessageBroadcastW(UINT uMsg, WPARAM wParam, LPARAM lParam)
3901 {
3902     return SendMessageTimeoutW(HWND_BROADCAST, uMsg, wParam, lParam,
3903                                SMTO_ABORTIFHUNG, 2000, NULL);
3904 }
3905 
3906 /*************************************************************************
3907  *      @	[SHLWAPI.436]
3908  *
3909  * Convert a Unicode string CLSID into a CLSID.
3910  *
3911  * PARAMS
3912  *  idstr      [I]   string containing a CLSID in text form
3913  *  id         [O]   CLSID extracted from the string
3914  *
3915  * RETURNS
3916  *  S_OK on success or E_INVALIDARG on failure
3917  */
3918 HRESULT WINAPI CLSIDFromStringWrap(LPCWSTR idstr, CLSID *id)
3919 {
3920     return CLSIDFromString((LPCOLESTR)idstr, id);
3921 }
3922 
3923 /*************************************************************************
3924  *      @	[SHLWAPI.437]
3925  *
3926  * Determine if the OS supports a given feature.
3927  *
3928  * PARAMS
3929  *  dwFeature [I] Feature requested (undocumented)
3930  *
3931  * RETURNS
3932  *  TRUE  If the feature is available.
3933  *  FALSE If the feature is not available.
3934  */
3935 BOOL WINAPI IsOS(DWORD feature)
3936 {
3937     OSVERSIONINFOA osvi;
3938     DWORD platform, majorv, minorv;
3939 
3940     osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
3941     if(!GetVersionExA(&osvi))  {
3942         ERR("GetVersionEx failed\n");
3943         return FALSE;
3944     }
3945 
3946     majorv = osvi.dwMajorVersion;
3947     minorv = osvi.dwMinorVersion;
3948     platform = osvi.dwPlatformId;
3949 
3950 #define ISOS_RETURN(x) \
3951     TRACE("(0x%x) ret=%d\n",feature,(x)); \
3952     return (x);
3953 
3954     switch(feature)  {
3955     case OS_WIN32SORGREATER:
3956         ISOS_RETURN(platform == VER_PLATFORM_WIN32s
3957                  || platform == VER_PLATFORM_WIN32_WINDOWS)
3958     case OS_NT:
3959         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
3960     case OS_WIN95ORGREATER:
3961         ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS)
3962     case OS_NT4ORGREATER:
3963         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 4)
3964     case OS_WIN2000ORGREATER_ALT:
3965     case OS_WIN2000ORGREATER:
3966         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5)
3967     case OS_WIN98ORGREATER:
3968         ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv >= 10)
3969     case OS_WIN98_GOLD:
3970         ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv == 10)
3971     case OS_WIN2000PRO:
3972         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5)
3973     case OS_WIN2000SERVER:
3974         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1))
3975     case OS_WIN2000ADVSERVER:
3976         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1))
3977     case OS_WIN2000DATACENTER:
3978         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1))
3979     case OS_WIN2000TERMINAL:
3980         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1))
3981     case OS_EMBEDDED:
3982         FIXME("(OS_EMBEDDED) What should we return here?\n");
3983         return FALSE;
3984     case OS_TERMINALCLIENT:
3985         FIXME("(OS_TERMINALCLIENT) What should we return here?\n");
3986         return FALSE;
3987     case OS_TERMINALREMOTEADMIN:
3988         FIXME("(OS_TERMINALREMOTEADMIN) What should we return here?\n");
3989         return FALSE;
3990     case OS_WIN95_GOLD:
3991         ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv == 0)
3992     case OS_MEORGREATER:
3993         ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv >= 90)
3994     case OS_XPORGREATER:
3995         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5 && minorv >= 1)
3996     case OS_HOME:
3997         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5 && minorv >= 1)
3998     case OS_PROFESSIONAL:
3999         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
4000     case OS_DATACENTER:
4001         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
4002     case OS_ADVSERVER:
4003         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5)
4004     case OS_SERVER:
4005         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
4006     case OS_TERMINALSERVER:
4007         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
4008     case OS_PERSONALTERMINALSERVER:
4009         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && minorv >= 1 && majorv >= 5)
4010     case OS_FASTUSERSWITCHING:
4011         FIXME("(OS_FASTUSERSWITCHING) What should we return here?\n");
4012         return TRUE;
4013     case OS_WELCOMELOGONUI:
4014         FIXME("(OS_WELCOMELOGONUI) What should we return here?\n");
4015         return FALSE;
4016     case OS_DOMAINMEMBER:
4017         FIXME("(OS_DOMAINMEMBER) What should we return here?\n");
4018         return TRUE;
4019     case OS_ANYSERVER:
4020         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
4021     case OS_WOW6432:
4022         {
4023             BOOL is_wow64;
4024             IsWow64Process(GetCurrentProcess(), &is_wow64);
4025             return is_wow64;
4026         }
4027     case OS_WEBSERVER:
4028         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
4029     case OS_SMALLBUSINESSSERVER:
4030         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
4031     case OS_TABLETPC:
4032         FIXME("(OS_TABLETPC) What should we return here?\n");
4033         return FALSE;
4034     case OS_SERVERADMINUI:
4035         FIXME("(OS_SERVERADMINUI) What should we return here?\n");
4036         return FALSE;
4037     case OS_MEDIACENTER:
4038         FIXME("(OS_MEDIACENTER) What should we return here?\n");
4039         return FALSE;
4040     case OS_APPLIANCE:
4041         FIXME("(OS_APPLIANCE) What should we return here?\n");
4042         return FALSE;
4043     case 0x25: /*OS_VISTAORGREATER*/
4044         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 6)
4045     }
4046 
4047 #undef ISOS_RETURN
4048 
4049     WARN("(0x%x) unknown parameter\n",feature);
4050 
4051     return FALSE;
4052 }
4053 
4054 /*************************************************************************
4055  * @  [SHLWAPI.439]
4056  */
4057 HRESULT WINAPI SHLoadRegUIStringW(HKEY hkey, LPCWSTR value, LPWSTR buf, DWORD size)
4058 {
4059     DWORD type, sz = size;
4060 
4061     if(RegQueryValueExW(hkey, value, NULL, &type, (LPBYTE)buf, &sz) != ERROR_SUCCESS)
4062         return E_FAIL;
4063 
4064     return SHLoadIndirectString(buf, buf, size, NULL);
4065 }
4066 
4067 /*************************************************************************
4068  * @  [SHLWAPI.478]
4069  *
4070  * Call IInputObject_TranslateAcceleratorIO() on an object.
4071  *
4072  * PARAMS
4073  *  lpUnknown [I] Object supporting the IInputObject interface.
4074  *  lpMsg     [I] Key message to be processed.
4075  *
4076  * RETURNS
4077  *  Success: S_OK.
4078  *  Failure: An HRESULT error code, or E_INVALIDARG if lpUnknown is NULL.
4079  */
4080 HRESULT WINAPI IUnknown_TranslateAcceleratorIO(IUnknown *lpUnknown, LPMSG lpMsg)
4081 {
4082   IInputObject* lpInput = NULL;
4083   HRESULT hRet = E_INVALIDARG;
4084 
4085   TRACE("(%p,%p)\n", lpUnknown, lpMsg);
4086   if (lpUnknown)
4087   {
4088     hRet = IUnknown_QueryInterface(lpUnknown, &IID_IInputObject,
4089                                    (void**)&lpInput);
4090     if (SUCCEEDED(hRet) && lpInput)
4091     {
4092       hRet = IInputObject_TranslateAcceleratorIO(lpInput, lpMsg);
4093       IInputObject_Release(lpInput);
4094     }
4095   }
4096   return hRet;
4097 }
4098 
4099 /*************************************************************************
4100  * @  [SHLWAPI.481]
4101  *
4102  * Call IInputObject_HasFocusIO() on an object.
4103  *
4104  * PARAMS
4105  *  lpUnknown [I] Object supporting the IInputObject interface.
4106  *
4107  * RETURNS
4108  *  Success: S_OK, if lpUnknown is an IInputObject object and has the focus,
4109  *           or S_FALSE otherwise.
4110  *  Failure: An HRESULT error code, or E_INVALIDARG if lpUnknown is NULL.
4111  */
4112 HRESULT WINAPI IUnknown_HasFocusIO(IUnknown *lpUnknown)
4113 {
4114   IInputObject* lpInput = NULL;
4115   HRESULT hRet = E_INVALIDARG;
4116 
4117   TRACE("(%p)\n", lpUnknown);
4118   if (lpUnknown)
4119   {
4120     hRet = IUnknown_QueryInterface(lpUnknown, &IID_IInputObject,
4121                                    (void**)&lpInput);
4122     if (SUCCEEDED(hRet) && lpInput)
4123     {
4124       hRet = IInputObject_HasFocusIO(lpInput);
4125       IInputObject_Release(lpInput);
4126     }
4127   }
4128   return hRet;
4129 }
4130 
4131 /*************************************************************************
4132  *      ColorRGBToHLS	[SHLWAPI.@]
4133  *
4134  * Convert an rgb COLORREF into the hls color space.
4135  *
4136  * PARAMS
4137  *  cRGB         [I] Source rgb value
4138  *  pwHue        [O] Destination for converted hue
4139  *  pwLuminance  [O] Destination for converted luminance
4140  *  pwSaturation [O] Destination for converted saturation
4141  *
4142  * RETURNS
4143  *  Nothing. pwHue, pwLuminance and pwSaturation are set to the converted
4144  *  values.
4145  *
4146  * NOTES
4147  *  Output HLS values are constrained to the range (0..240).
4148  *  For Achromatic conversions, Hue is set to 160.
4149  */
4150 VOID WINAPI ColorRGBToHLS(COLORREF cRGB, LPWORD pwHue,
4151 			  LPWORD pwLuminance, LPWORD pwSaturation)
4152 {
4153   int wR, wG, wB, wMax, wMin, wHue, wLuminosity, wSaturation;
4154 
4155   TRACE("(%08x,%p,%p,%p)\n", cRGB, pwHue, pwLuminance, pwSaturation);
4156 
4157   wR = GetRValue(cRGB);
4158   wG = GetGValue(cRGB);
4159   wB = GetBValue(cRGB);
4160 
4161   wMax = max(wR, max(wG, wB));
4162   wMin = min(wR, min(wG, wB));
4163 
4164   /* Luminosity */
4165   wLuminosity = ((wMax + wMin) * 240 + 255) / 510;
4166 
4167   if (wMax == wMin)
4168   {
4169     /* Achromatic case */
4170     wSaturation = 0;
4171     /* Hue is now unrepresentable, but this is what native returns... */
4172     wHue = 160;
4173   }
4174   else
4175   {
4176     /* Chromatic case */
4177     int wDelta = wMax - wMin, wRNorm, wGNorm, wBNorm;
4178 
4179     /* Saturation */
4180     if (wLuminosity <= 120)
4181       wSaturation = ((wMax + wMin)/2 + wDelta * 240) / (wMax + wMin);
4182     else
4183       wSaturation = ((510 - wMax - wMin)/2 + wDelta * 240) / (510 - wMax - wMin);
4184 
4185     /* Hue */
4186     wRNorm = (wDelta/2 + wMax * 40 - wR * 40) / wDelta;
4187     wGNorm = (wDelta/2 + wMax * 40 - wG * 40) / wDelta;
4188     wBNorm = (wDelta/2 + wMax * 40 - wB * 40) / wDelta;
4189 
4190     if (wR == wMax)
4191       wHue = wBNorm - wGNorm;
4192     else if (wG == wMax)
4193       wHue = 80 + wRNorm - wBNorm;
4194     else
4195       wHue = 160 + wGNorm - wRNorm;
4196     if (wHue < 0)
4197       wHue += 240;
4198     else if (wHue > 240)
4199       wHue -= 240;
4200   }
4201   if (pwHue)
4202     *pwHue = wHue;
4203   if (pwLuminance)
4204     *pwLuminance = wLuminosity;
4205   if (pwSaturation)
4206     *pwSaturation = wSaturation;
4207 }
4208 
4209 /*************************************************************************
4210  *      SHCreateShellPalette	[SHLWAPI.@]
4211  */
4212 HPALETTE WINAPI SHCreateShellPalette(HDC hdc)
4213 {
4214 	FIXME("stub\n");
4215 	return CreateHalftonePalette(hdc);
4216 }
4217 
4218 /*************************************************************************
4219  *	SHGetInverseCMAP (SHLWAPI.@)
4220  *
4221  * Get an inverse color map table.
4222  *
4223  * PARAMS
4224  *  lpCmap  [O] Destination for color map
4225  *  dwSize  [I] Size of memory pointed to by lpCmap
4226  *
4227  * RETURNS
4228  *  Success: S_OK.
4229  *  Failure: E_POINTER,    If lpCmap is invalid.
4230  *           E_INVALIDARG, If dwFlags is invalid
4231  *           E_OUTOFMEMORY, If there is no memory available
4232  *
4233  * NOTES
4234  *  dwSize may only be CMAP_PTR_SIZE (4) or CMAP_SIZE (8192).
4235  *  If dwSize = CMAP_PTR_SIZE, *lpCmap is set to the address of this DLL's
4236  *  internal CMap.
4237  *  If dwSize = CMAP_SIZE, lpCmap is filled with a copy of the data from
4238  *  this DLL's internal CMap.
4239  */
4240 HRESULT WINAPI SHGetInverseCMAP(LPDWORD dest, DWORD dwSize)
4241 {
4242     if (dwSize == 4) {
4243 	FIXME(" - returning bogus address for SHGetInverseCMAP\n");
4244 	*dest = (DWORD)0xabba1249;
4245 	return 0;
4246     }
4247     FIXME("(%p, %#x) stub\n", dest, dwSize);
4248     return 0;
4249 }
4250 
4251 /*************************************************************************
4252  *      SHIsLowMemoryMachine	[SHLWAPI.@]
4253  *
4254  * Determine if the current computer has low memory.
4255  *
4256  * PARAMS
4257  *  x [I] FIXME
4258  *
4259  * RETURNS
4260  *  TRUE if the users machine has 16 Megabytes of memory or less,
4261  *  FALSE otherwise.
4262  */
4263 BOOL WINAPI SHIsLowMemoryMachine (DWORD x)
4264 {
4265   FIXME("(0x%08x) stub\n", x);
4266   return FALSE;
4267 }
4268 
4269 /*************************************************************************
4270  *      GetMenuPosFromID	[SHLWAPI.@]
4271  *
4272  * Return the position of a menu item from its Id.
4273  *
4274  * PARAMS
4275  *   hMenu [I] Menu containing the item
4276  *   wID   [I] Id of the menu item
4277  *
4278  * RETURNS
4279  *  Success: The index of the menu item in hMenu.
4280  *  Failure: -1, If the item is not found.
4281  */
4282 INT WINAPI GetMenuPosFromID(HMENU hMenu, UINT wID)
4283 {
4284     MENUITEMINFOW mi;
4285     INT nCount = GetMenuItemCount(hMenu), nIter = 0;
4286 
4287     TRACE("%p %u\n", hMenu, wID);
4288 
4289     while (nIter < nCount)
4290     {
4291         mi.cbSize = sizeof(mi);
4292         mi.fMask = MIIM_ID;
4293         if (GetMenuItemInfoW(hMenu, nIter, TRUE, &mi) && mi.wID == wID)
4294         {
4295             TRACE("ret %d\n", nIter);
4296             return nIter;
4297         }
4298         nIter++;
4299     }
4300 
4301     return -1;
4302 }
4303 
4304 /*************************************************************************
4305  *      @	[SHLWAPI.179]
4306  *
4307  * Same as SHLWAPI.GetMenuPosFromID
4308  */
4309 DWORD WINAPI SHMenuIndexFromID(HMENU hMenu, UINT uID)
4310 {
4311     TRACE("%p %u\n", hMenu, uID);
4312     return GetMenuPosFromID(hMenu, uID);
4313 }
4314 
4315 
4316 /*************************************************************************
4317  *      @	[SHLWAPI.448]
4318  */
4319 VOID WINAPI FixSlashesAndColonW(LPWSTR lpwstr)
4320 {
4321     while (*lpwstr)
4322     {
4323         if (*lpwstr == '/')
4324             *lpwstr = '\\';
4325         lpwstr++;
4326     }
4327 }
4328 
4329 
4330 /*************************************************************************
4331  *      @	[SHLWAPI.461]
4332  */
4333 DWORD WINAPI SHGetAppCompatFlags(DWORD dwUnknown)
4334 {
4335   FIXME("(0x%08x) stub\n", dwUnknown);
4336   return 0;
4337 }
4338 
4339 
4340 /*************************************************************************
4341  *      @	[SHLWAPI.549]
4342  */
4343 HRESULT WINAPI SHCoCreateInstanceAC(REFCLSID rclsid, LPUNKNOWN pUnkOuter,
4344                                     DWORD dwClsContext, REFIID iid, LPVOID *ppv)
4345 {
4346     return CoCreateInstance(rclsid, pUnkOuter, dwClsContext, iid, ppv);
4347 }
4348 
4349 /*************************************************************************
4350  * SHSkipJunction	[SHLWAPI.@]
4351  *
4352  * Determine if a bind context can be bound to an object
4353  *
4354  * PARAMS
4355  *  pbc    [I] Bind context to check
4356  *  pclsid [I] CLSID of object to be bound to
4357  *
4358  * RETURNS
4359  *  TRUE: If it is safe to bind
4360  *  FALSE: If pbc is invalid or binding would not be safe
4361  *
4362  */
4363 BOOL WINAPI SHSkipJunction(IBindCtx *pbc, const CLSID *pclsid)
4364 {
4365   static WCHAR szSkipBinding[] = { 'S','k','i','p',' ',
4366     'B','i','n','d','i','n','g',' ','C','L','S','I','D','\0' };
4367   BOOL bRet = FALSE;
4368 
4369   if (pbc)
4370   {
4371     IUnknown* lpUnk;
4372 
4373     if (SUCCEEDED(IBindCtx_GetObjectParam(pbc, szSkipBinding, &lpUnk)))
4374     {
4375       CLSID clsid;
4376 
4377       if (SUCCEEDED(IUnknown_GetClassID(lpUnk, &clsid)) &&
4378           IsEqualGUID(pclsid, &clsid))
4379         bRet = TRUE;
4380 
4381       IUnknown_Release(lpUnk);
4382     }
4383   }
4384   return bRet;
4385 }
4386 
4387 /***********************************************************************
4388  *		SHGetShellKey (SHLWAPI.491)
4389  */
4390 HKEY WINAPI SHGetShellKey(DWORD flags, LPCWSTR sub_key, BOOL create)
4391 {
4392     enum _shellkey_flags {
4393         SHKEY_Root_HKCU = 0x1,
4394         SHKEY_Root_HKLM = 0x2,
4395         SHKEY_Key_Explorer  = 0x00,
4396         SHKEY_Key_Shell = 0x10,
4397         SHKEY_Key_ShellNoRoam = 0x20,
4398         SHKEY_Key_Classes = 0x30,
4399         SHKEY_Subkey_Default = 0x0000,
4400         SHKEY_Subkey_ResourceName = 0x1000,
4401         SHKEY_Subkey_Handlers = 0x2000,
4402         SHKEY_Subkey_Associations = 0x3000,
4403         SHKEY_Subkey_Volatile = 0x4000,
4404         SHKEY_Subkey_MUICache = 0x5000,
4405         SHKEY_Subkey_FileExts = 0x6000
4406     };
4407 
4408     static const WCHAR explorerW[] = {'S','o','f','t','w','a','r','e','\\',
4409         'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
4410         'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4411         'E','x','p','l','o','r','e','r','\\'};
4412     static const WCHAR shellW[] = {'S','o','f','t','w','a','r','e','\\',
4413         'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
4414         'S','h','e','l','l','\\'};
4415     static const WCHAR shell_no_roamW[] = {'S','o','f','t','w','a','r','e','\\',
4416         'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
4417         'S','h','e','l','l','N','o','R','o','a','m','\\'};
4418     static const WCHAR classesW[] = {'S','o','f','t','w','a','r','e','\\',
4419         'C','l','a','s','s','e','s','\\'};
4420 
4421     static const WCHAR localized_resource_nameW[] = {'L','o','c','a','l','i','z','e','d',
4422         'R','e','s','o','u','r','c','e','N','a','m','e','\\'};
4423     static const WCHAR handlersW[] = {'H','a','n','d','l','e','r','s','\\'};
4424     static const WCHAR associationsW[] = {'A','s','s','o','c','i','a','t','i','o','n','s','\\'};
4425     static const WCHAR volatileW[] = {'V','o','l','a','t','i','l','e','\\'};
4426     static const WCHAR mui_cacheW[] = {'M','U','I','C','a','c','h','e','\\'};
4427     static const WCHAR file_extsW[] = {'F','i','l','e','E','x','t','s','\\'};
4428 
4429     WCHAR *path;
4430     const WCHAR *key, *subkey;
4431     int size_key, size_subkey, size_user;
4432     HKEY hkey = NULL;
4433 
4434     TRACE("(0x%08x, %s, %d)\n", flags, debugstr_w(sub_key), create);
4435 
4436     /* For compatibility with Vista+ */
4437     if(flags == 0x1ffff)
4438         flags = 0x21;
4439 
4440     switch(flags&0xff0) {
4441     case SHKEY_Key_Explorer:
4442         key = explorerW;
4443         size_key = sizeof(explorerW);
4444         break;
4445     case SHKEY_Key_Shell:
4446         key = shellW;
4447         size_key = sizeof(shellW);
4448         break;
4449     case SHKEY_Key_ShellNoRoam:
4450         key = shell_no_roamW;
4451         size_key = sizeof(shell_no_roamW);
4452         break;
4453     case SHKEY_Key_Classes:
4454         key = classesW;
4455         size_key = sizeof(classesW);
4456         break;
4457     default:
4458         FIXME("unsupported flags (0x%08x)\n", flags);
4459         return NULL;
4460     }
4461 
4462     switch(flags&0xff000) {
4463     case SHKEY_Subkey_Default:
4464         subkey = NULL;
4465         size_subkey = 0;
4466         break;
4467     case SHKEY_Subkey_ResourceName:
4468         subkey = localized_resource_nameW;
4469         size_subkey = sizeof(localized_resource_nameW);
4470         break;
4471     case SHKEY_Subkey_Handlers:
4472         subkey = handlersW;
4473         size_subkey = sizeof(handlersW);
4474         break;
4475     case SHKEY_Subkey_Associations:
4476         subkey = associationsW;
4477         size_subkey = sizeof(associationsW);
4478         break;
4479     case SHKEY_Subkey_Volatile:
4480         subkey = volatileW;
4481         size_subkey = sizeof(volatileW);
4482         break;
4483     case SHKEY_Subkey_MUICache:
4484         subkey = mui_cacheW;
4485         size_subkey = sizeof(mui_cacheW);
4486         break;
4487     case SHKEY_Subkey_FileExts:
4488         subkey = file_extsW;
4489         size_subkey = sizeof(file_extsW);
4490         break;
4491     default:
4492         FIXME("unsupported flags (0x%08x)\n", flags);
4493         return NULL;
4494     }
4495 
4496     if(sub_key)
4497         size_user = lstrlenW(sub_key)*sizeof(WCHAR);
4498     else
4499         size_user = 0;
4500 
4501     path = HeapAlloc(GetProcessHeap(), 0, size_key+size_subkey+size_user+sizeof(WCHAR));
4502     if(!path) {
4503         ERR("Out of memory\n");
4504         return NULL;
4505     }
4506 
4507     memcpy(path, key, size_key);
4508     if(subkey)
4509         memcpy(path+size_key/sizeof(WCHAR), subkey, size_subkey);
4510     if(sub_key)
4511         memcpy(path+(size_key+size_subkey)/sizeof(WCHAR), sub_key, size_user);
4512     path[(size_key+size_subkey+size_user)/sizeof(WCHAR)] = '\0';
4513 
4514     if(create)
4515         RegCreateKeyExW((flags&0xf)==SHKEY_Root_HKLM?HKEY_LOCAL_MACHINE:HKEY_CURRENT_USER,
4516                 path, 0, NULL, 0, MAXIMUM_ALLOWED, NULL, &hkey, NULL);
4517     else
4518         RegOpenKeyExW((flags&0xf)==SHKEY_Root_HKLM?HKEY_LOCAL_MACHINE:HKEY_CURRENT_USER,
4519                 path, 0, MAXIMUM_ALLOWED, &hkey);
4520 
4521     HeapFree(GetProcessHeap(), 0, path);
4522     return hkey;
4523 }
4524 
4525 /***********************************************************************
4526  *		SHQueueUserWorkItem (SHLWAPI.@)
4527  */
4528 BOOL WINAPI SHQueueUserWorkItem(LPTHREAD_START_ROUTINE pfnCallback,
4529         LPVOID pContext, LONG lPriority, DWORD_PTR dwTag,
4530         DWORD_PTR *pdwId, LPCSTR pszModule, DWORD dwFlags)
4531 {
4532     TRACE("(%p, %p, %d, %lx, %p, %s, %08x)\n", pfnCallback, pContext,
4533           lPriority, dwTag, pdwId, debugstr_a(pszModule), dwFlags);
4534 
4535     if(lPriority || dwTag || pdwId || pszModule || dwFlags)
4536         FIXME("Unsupported arguments\n");
4537 
4538     return QueueUserWorkItem(pfnCallback, pContext, 0);
4539 }
4540 
4541 /***********************************************************************
4542  *		SHSetTimerQueueTimer (SHLWAPI.263)
4543  */
4544 HANDLE WINAPI SHSetTimerQueueTimer(HANDLE hQueue,
4545         WAITORTIMERCALLBACK pfnCallback, LPVOID pContext, DWORD dwDueTime,
4546         DWORD dwPeriod, LPCSTR lpszLibrary, DWORD dwFlags)
4547 {
4548     HANDLE hNewTimer;
4549 
4550     /* SHSetTimerQueueTimer flags -> CreateTimerQueueTimer flags */
4551     if (dwFlags & TPS_LONGEXECTIME) {
4552         dwFlags &= ~TPS_LONGEXECTIME;
4553         dwFlags |= WT_EXECUTELONGFUNCTION;
4554     }
4555     if (dwFlags & TPS_EXECUTEIO) {
4556         dwFlags &= ~TPS_EXECUTEIO;
4557         dwFlags |= WT_EXECUTEINIOTHREAD;
4558     }
4559 
4560     if (!CreateTimerQueueTimer(&hNewTimer, hQueue, pfnCallback, pContext,
4561                                dwDueTime, dwPeriod, dwFlags))
4562         return NULL;
4563 
4564     return hNewTimer;
4565 }
4566 
4567 /***********************************************************************
4568  *		IUnknown_OnFocusChangeIS (SHLWAPI.@)
4569  */
4570 HRESULT WINAPI IUnknown_OnFocusChangeIS(LPUNKNOWN lpUnknown, LPUNKNOWN pFocusObject, BOOL bFocus)
4571 {
4572     IInputObjectSite *pIOS = NULL;
4573     HRESULT hRet = E_INVALIDARG;
4574 
4575     TRACE("(%p, %p, %s)\n", lpUnknown, pFocusObject, bFocus ? "TRUE" : "FALSE");
4576 
4577     if (lpUnknown)
4578     {
4579         hRet = IUnknown_QueryInterface(lpUnknown, &IID_IInputObjectSite,
4580                                        (void **)&pIOS);
4581         if (SUCCEEDED(hRet) && pIOS)
4582         {
4583             hRet = IInputObjectSite_OnFocusChangeIS(pIOS, pFocusObject, bFocus);
4584             IInputObjectSite_Release(pIOS);
4585         }
4586     }
4587     return hRet;
4588 }
4589 
4590 /***********************************************************************
4591  *		SKAllocValueW (SHLWAPI.519)
4592  */
4593 HRESULT WINAPI SKAllocValueW(DWORD flags, LPCWSTR subkey, LPCWSTR value, DWORD *type,
4594         LPVOID *data, DWORD *count)
4595 {
4596     DWORD ret, size;
4597     HKEY hkey;
4598 
4599     TRACE("(0x%x, %s, %s, %p, %p, %p)\n", flags, debugstr_w(subkey),
4600         debugstr_w(value), type, data, count);
4601 
4602     hkey = SHGetShellKey(flags, subkey, FALSE);
4603     if (!hkey)
4604         return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
4605 
4606     ret = SHQueryValueExW(hkey, value, NULL, type, NULL, &size);
4607     if (ret) {
4608         RegCloseKey(hkey);
4609         return HRESULT_FROM_WIN32(ret);
4610     }
4611 
4612     size += 2;
4613     *data = LocalAlloc(0, size);
4614     if (!*data) {
4615         RegCloseKey(hkey);
4616         return E_OUTOFMEMORY;
4617     }
4618 
4619     ret = SHQueryValueExW(hkey, value, NULL, type, *data, &size);
4620     if (count)
4621         *count = size;
4622 
4623     RegCloseKey(hkey);
4624     return HRESULT_FROM_WIN32(ret);
4625 }
4626 
4627 /***********************************************************************
4628  *		SKDeleteValueW (SHLWAPI.518)
4629  */
4630 HRESULT WINAPI SKDeleteValueW(DWORD flags, LPCWSTR subkey, LPCWSTR value)
4631 {
4632     DWORD ret;
4633     HKEY hkey;
4634 
4635     TRACE("(0x%x, %s %s)\n", flags, debugstr_w(subkey), debugstr_w(value));
4636 
4637     hkey = SHGetShellKey(flags, subkey, FALSE);
4638     if (!hkey)
4639         return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
4640 
4641     ret = RegDeleteValueW(hkey, value);
4642 
4643     RegCloseKey(hkey);
4644     return HRESULT_FROM_WIN32(ret);
4645 }
4646 
4647 /***********************************************************************
4648  *		SKGetValueW (SHLWAPI.516)
4649  */
4650 HRESULT WINAPI SKGetValueW(DWORD flags, LPCWSTR subkey, LPCWSTR value, DWORD *type,
4651     void *data, DWORD *count)
4652 {
4653     DWORD ret;
4654     HKEY hkey;
4655 
4656     TRACE("(0x%x, %s, %s, %p, %p, %p)\n", flags, debugstr_w(subkey),
4657         debugstr_w(value), type, data, count);
4658 
4659     hkey = SHGetShellKey(flags, subkey, FALSE);
4660     if (!hkey)
4661         return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
4662 
4663     ret = SHQueryValueExW(hkey, value, NULL, type, data, count);
4664 
4665     RegCloseKey(hkey);
4666     return HRESULT_FROM_WIN32(ret);
4667 }
4668 
4669 /***********************************************************************
4670  *		SKSetValueW (SHLWAPI.516)
4671  */
4672 HRESULT WINAPI SKSetValueW(DWORD flags, LPCWSTR subkey, LPCWSTR value,
4673         DWORD type, void *data, DWORD count)
4674 {
4675     DWORD ret;
4676     HKEY hkey;
4677 
4678     TRACE("(0x%x, %s, %s, %x, %p, %d)\n", flags, debugstr_w(subkey),
4679             debugstr_w(value), type, data, count);
4680 
4681     hkey = SHGetShellKey(flags, subkey, TRUE);
4682     if (!hkey)
4683         return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
4684 
4685     ret = RegSetValueExW(hkey, value, 0, type, data, count);
4686 
4687     RegCloseKey(hkey);
4688     return HRESULT_FROM_WIN32(ret);
4689 }
4690 
4691 typedef HRESULT (WINAPI *DllGetVersion_func)(DLLVERSIONINFO *);
4692 
4693 /***********************************************************************
4694  *              GetUIVersion (SHLWAPI.452)
4695  */
4696 DWORD WINAPI GetUIVersion(void)
4697 {
4698     static DWORD version;
4699 
4700     if (!version)
4701     {
4702         DllGetVersion_func pDllGetVersion;
4703         HMODULE dll = LoadLibraryA("shell32.dll");
4704         if (!dll) return 0;
4705 
4706         pDllGetVersion = (DllGetVersion_func)GetProcAddress(dll, "DllGetVersion");
4707         if (pDllGetVersion)
4708         {
4709             DLLVERSIONINFO dvi;
4710             dvi.cbSize = sizeof(DLLVERSIONINFO);
4711             if (pDllGetVersion(&dvi) == S_OK) version = dvi.dwMajorVersion;
4712         }
4713         FreeLibrary( dll );
4714         if (!version) version = 3;  /* old shell dlls don't have DllGetVersion */
4715     }
4716     return version;
4717 }
4718 
4719 /***********************************************************************
4720  *              ShellMessageBoxWrapW [SHLWAPI.388]
4721  *
4722  * See shell32.ShellMessageBoxW
4723  *
4724  * NOTE:
4725  * shlwapi.ShellMessageBoxWrapW is a duplicate of shell32.ShellMessageBoxW
4726  * because we can't forward to it in the .spec file since it's exported by
4727  * ordinal. If you change the implementation here please update the code in
4728  * shell32 as well.
4729  */
4730 INT WINAPIV ShellMessageBoxWrapW(HINSTANCE hInstance, HWND hWnd, LPCWSTR lpText,
4731                                  LPCWSTR lpCaption, UINT uType, ...)
4732 {
4733     WCHAR *szText = NULL, szTitle[100];
4734     LPCWSTR pszText, pszTitle = szTitle;
4735     LPWSTR pszTemp;
4736     __ms_va_list args;
4737     int ret;
4738 
4739     __ms_va_start(args, uType);
4740 
4741     TRACE("(%p,%p,%p,%p,%08x)\n", hInstance, hWnd, lpText, lpCaption, uType);
4742 
4743     if (IS_INTRESOURCE(lpCaption))
4744         LoadStringW(hInstance, LOWORD(lpCaption), szTitle, sizeof(szTitle)/sizeof(szTitle[0]));
4745     else
4746         pszTitle = lpCaption;
4747 
4748     if (IS_INTRESOURCE(lpText))
4749     {
4750         const WCHAR *ptr;
4751         UINT len = LoadStringW(hInstance, LOWORD(lpText), (LPWSTR)&ptr, 0);
4752 
4753         if (len)
4754         {
4755             szText = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
4756             if (szText) LoadStringW(hInstance, LOWORD(lpText), szText, len + 1);
4757         }
4758         pszText = szText;
4759         if (!pszText) {
4760             WARN("Failed to load id %d\n", LOWORD(lpText));
4761             __ms_va_end(args);
4762             return 0;
4763         }
4764     }
4765     else
4766         pszText = lpText;
4767 
4768     FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
4769                    pszText, 0, 0, (LPWSTR)&pszTemp, 0, &args);
4770 
4771     __ms_va_end(args);
4772 
4773     ret = MessageBoxW(hWnd, pszTemp, pszTitle, uType);
4774 
4775     HeapFree(GetProcessHeap(), 0, szText);
4776     LocalFree(pszTemp);
4777     return ret;
4778 }
4779 
4780 /***********************************************************************
4781  *              ZoneComputePaneSize [SHLWAPI.382]
4782  */
4783 UINT WINAPI ZoneComputePaneSize(HWND hwnd)
4784 {
4785     FIXME("\n");
4786     return 0x95;
4787 }
4788 
4789 /***********************************************************************
4790  *              SHChangeNotifyWrap [SHLWAPI.394]
4791  */
4792 void WINAPI SHChangeNotifyWrap(LONG wEventId, UINT uFlags, LPCVOID dwItem1, LPCVOID dwItem2)
4793 {
4794     SHChangeNotify(wEventId, uFlags, dwItem1, dwItem2);
4795 }
4796 
4797 typedef struct SHELL_USER_SID {   /* according to MSDN this should be in shlobj.h... */
4798     SID_IDENTIFIER_AUTHORITY sidAuthority;
4799     DWORD                    dwUserGroupID;
4800     DWORD                    dwUserID;
4801 } SHELL_USER_SID, *PSHELL_USER_SID;
4802 
4803 typedef struct SHELL_USER_PERMISSION { /* ...and this should be in shlwapi.h */
4804     SHELL_USER_SID susID;
4805     DWORD          dwAccessType;
4806     BOOL           fInherit;
4807     DWORD          dwAccessMask;
4808     DWORD          dwInheritMask;
4809     DWORD          dwInheritAccessMask;
4810 } SHELL_USER_PERMISSION, *PSHELL_USER_PERMISSION;
4811 
4812 /***********************************************************************
4813  *             GetShellSecurityDescriptor [SHLWAPI.475]
4814  *
4815  * prepares SECURITY_DESCRIPTOR from a set of ACEs
4816  *
4817  * PARAMS
4818  *  apUserPerm [I] array of pointers to SHELL_USER_PERMISSION structures,
4819  *                 each of which describes permissions to apply
4820  *  cUserPerm  [I] number of entries in apUserPerm array
4821  *
4822  * RETURNS
4823  *  success: pointer to SECURITY_DESCRIPTOR
4824  *  failure: NULL
4825  *
4826  * NOTES
4827  *  Call should free returned descriptor with LocalFree
4828  */
4829 PSECURITY_DESCRIPTOR WINAPI GetShellSecurityDescriptor(const PSHELL_USER_PERMISSION *apUserPerm, int cUserPerm)
4830 {
4831     PSID *sidlist;
4832     PSID  cur_user = NULL;
4833     BYTE  tuUser[2000];
4834     DWORD acl_size;
4835     int   sid_count, i;
4836     PSECURITY_DESCRIPTOR psd = NULL;
4837 
4838     TRACE("%p %d\n", apUserPerm, cUserPerm);
4839 
4840     if (apUserPerm == NULL || cUserPerm <= 0)
4841         return NULL;
4842 
4843     sidlist = HeapAlloc(GetProcessHeap(), 0, cUserPerm * sizeof(PSID));
4844     if (!sidlist)
4845         return NULL;
4846 
4847     acl_size = sizeof(ACL);
4848 
4849     for(sid_count = 0; sid_count < cUserPerm; sid_count++)
4850     {
4851         static SHELL_USER_SID null_sid = {{SECURITY_NULL_SID_AUTHORITY}, 0, 0};
4852         PSHELL_USER_PERMISSION perm = apUserPerm[sid_count];
4853         PSHELL_USER_SID sid = &perm->susID;
4854         PSID pSid;
4855         BOOL ret = TRUE;
4856 
4857         if (!memcmp((void*)sid, (void*)&null_sid, sizeof(SHELL_USER_SID)))
4858         {  /* current user's SID */
4859             if (!cur_user)
4860             {
4861                 HANDLE Token;
4862                 DWORD bufsize = sizeof(tuUser);
4863 
4864                 ret = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &Token);
4865                 if (ret)
4866                 {
4867                     ret = GetTokenInformation(Token, TokenUser, (void*)tuUser, bufsize, &bufsize );
4868                     if (ret)
4869                         cur_user = ((PTOKEN_USER)tuUser)->User.Sid;
4870                     CloseHandle(Token);
4871                 }
4872             }
4873             pSid = cur_user;
4874         } else if (sid->dwUserID==0) /* one sub-authority */
4875             ret = AllocateAndInitializeSid(&sid->sidAuthority, 1, sid->dwUserGroupID, 0,
4876                     0, 0, 0, 0, 0, 0, &pSid);
4877         else
4878             ret = AllocateAndInitializeSid(&sid->sidAuthority, 2, sid->dwUserGroupID, sid->dwUserID,
4879                     0, 0, 0, 0, 0, 0, &pSid);
4880         if (!ret)
4881             goto free_sids;
4882 
4883         sidlist[sid_count] = pSid;
4884         /* increment acl_size (1 ACE for non-inheritable and 2 ACEs for inheritable records */
4885         acl_size += (sizeof(ACCESS_ALLOWED_ACE)-sizeof(DWORD) + GetLengthSid(pSid)) * (perm->fInherit ? 2 : 1);
4886     }
4887 
4888     psd = LocalAlloc(0, sizeof(SECURITY_DESCRIPTOR) + acl_size);
4889 
4890     if (psd != NULL)
4891     {
4892         PACL pAcl = (PACL)(((BYTE*)psd)+sizeof(SECURITY_DESCRIPTOR));
4893 
4894         if (!InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION))
4895             goto error;
4896 
4897         if (!InitializeAcl(pAcl, acl_size, ACL_REVISION))
4898             goto error;
4899 
4900         for(i = 0; i < sid_count; i++)
4901         {
4902             PSHELL_USER_PERMISSION sup = apUserPerm[i];
4903             PSID sid = sidlist[i];
4904 
4905             switch(sup->dwAccessType)
4906             {
4907                 case ACCESS_ALLOWED_ACE_TYPE:
4908                     if (!AddAccessAllowedAce(pAcl, ACL_REVISION, sup->dwAccessMask, sid))
4909                         goto error;
4910                     if (sup->fInherit && !AddAccessAllowedAceEx(pAcl, ACL_REVISION,
4911                                 (BYTE)sup->dwInheritMask, sup->dwInheritAccessMask, sid))
4912                         goto error;
4913                     break;
4914                 case ACCESS_DENIED_ACE_TYPE:
4915                     if (!AddAccessDeniedAce(pAcl, ACL_REVISION, sup->dwAccessMask, sid))
4916                         goto error;
4917                     if (sup->fInherit && !AddAccessDeniedAceEx(pAcl, ACL_REVISION,
4918                                 (BYTE)sup->dwInheritMask, sup->dwInheritAccessMask, sid))
4919                         goto error;
4920                     break;
4921                 default:
4922                     goto error;
4923             }
4924         }
4925 
4926         if (!SetSecurityDescriptorDacl(psd, TRUE, pAcl, FALSE))
4927             goto error;
4928     }
4929     goto free_sids;
4930 
4931 error:
4932     LocalFree(psd);
4933     psd = NULL;
4934 free_sids:
4935     for(i = 0; i < sid_count; i++)
4936     {
4937         if (!cur_user || sidlist[i] != cur_user)
4938             FreeSid(sidlist[i]);
4939     }
4940     HeapFree(GetProcessHeap(), 0, sidlist);
4941 
4942     return psd;
4943 }
4944 
4945 /***********************************************************************
4946  *             SHCreatePropertyBagOnRegKey [SHLWAPI.471]
4947  *
4948  * Creates a property bag from a registry key
4949  *
4950  * PARAMS
4951  *  hKey       [I] Handle to the desired registry key
4952  *  subkey     [I] Name of desired subkey, or NULL to open hKey directly
4953  *  grfMode    [I] Optional flags
4954  *  riid       [I] IID of requested property bag interface
4955  *  ppv        [O] Address to receive pointer to the new interface
4956  *
4957  * RETURNS
4958  *  success: 0
4959  *  failure: error code
4960  *
4961  */
4962 HRESULT WINAPI SHCreatePropertyBagOnRegKey (HKEY hKey, LPCWSTR subkey,
4963     DWORD grfMode, REFIID riid, void **ppv)
4964 {
4965     FIXME("%p %s %d %s %p STUB\n", hKey, debugstr_w(subkey), grfMode,
4966           debugstr_guid(riid), ppv);
4967 
4968     return E_NOTIMPL;
4969 }
4970 
4971 /***********************************************************************
4972  *             SHGetViewStatePropertyBag [SHLWAPI.515]
4973  *
4974  * Retrieves a property bag in which the view state information of a folder
4975  * can be stored.
4976  *
4977  * PARAMS
4978  *  pidl        [I] PIDL of the folder requested
4979  *  bag_name    [I] Name of the property bag requested
4980  *  flags       [I] Optional flags
4981  *  riid        [I] IID of requested property bag interface
4982  *  ppv         [O] Address to receive pointer to the new interface
4983  *
4984  * RETURNS
4985  *  success: S_OK
4986  *  failure: error code
4987  *
4988  */
4989 HRESULT WINAPI SHGetViewStatePropertyBag(LPCITEMIDLIST pidl, LPWSTR bag_name,
4990     DWORD flags, REFIID riid, void **ppv)
4991 {
4992     FIXME("%p %s %d %s %p STUB\n", pidl, debugstr_w(bag_name), flags,
4993           debugstr_guid(riid), ppv);
4994 
4995     return E_NOTIMPL;
4996 }
4997 
4998 /***********************************************************************
4999  *             SHFormatDateTimeW [SHLWAPI.354]
5000  *
5001  * Produces a string representation of a time.
5002  *
5003  * PARAMS
5004  *  fileTime   [I] Pointer to FILETIME structure specifying the time
5005  *  flags      [I] Flags specifying the desired output
5006  *  buf        [O] Pointer to buffer for output
5007  *  size       [I] Number of characters that can be contained in buffer
5008  *
5009  * RETURNS
5010  *  success: number of characters written to the buffer
5011  *  failure: 0
5012  *
5013  */
5014 INT WINAPI SHFormatDateTimeW(const FILETIME UNALIGNED *fileTime, DWORD *flags,
5015     LPWSTR buf, UINT size)
5016 {
5017 #define SHFORMATDT_UNSUPPORTED_FLAGS (FDTF_RELATIVE | FDTF_LTRDATE | FDTF_RTLDATE | FDTF_NOAUTOREADINGORDER)
5018     DWORD fmt_flags = flags ? *flags : FDTF_DEFAULT;
5019     SYSTEMTIME st;
5020     FILETIME ft;
5021     INT ret = 0;
5022 
5023     TRACE("%p %p %p %u\n", fileTime, flags, buf, size);
5024 
5025     if (!buf || !size)
5026         return 0;
5027 
5028     if (fmt_flags & SHFORMATDT_UNSUPPORTED_FLAGS)
5029         FIXME("ignoring some flags - 0x%08x\n", fmt_flags & SHFORMATDT_UNSUPPORTED_FLAGS);
5030 
5031     FileTimeToLocalFileTime(fileTime, &ft);
5032     FileTimeToSystemTime(&ft, &st);
5033 
5034     /* first of all date */
5035     if (fmt_flags & (FDTF_LONGDATE | FDTF_SHORTDATE))
5036     {
5037         static const WCHAR sep1[] = {',',' ',0};
5038         static const WCHAR sep2[] = {' ',0};
5039 
5040         DWORD date = fmt_flags & FDTF_LONGDATE ? DATE_LONGDATE : DATE_SHORTDATE;
5041         ret = GetDateFormatW(LOCALE_USER_DEFAULT, date, &st, NULL, buf, size);
5042         if (ret >= size) return ret;
5043 
5044         /* add separator */
5045         if (ret < size && (fmt_flags & (FDTF_LONGTIME | FDTF_SHORTTIME)))
5046         {
5047             if ((fmt_flags & FDTF_LONGDATE) && (ret < size + 2))
5048             {
5049                 lstrcatW(&buf[ret-1], sep1);
5050                 ret += 2;
5051             }
5052             else
5053             {
5054                 lstrcatW(&buf[ret-1], sep2);
5055                 ret++;
5056             }
5057         }
5058     }
5059     /* time part */
5060     if (fmt_flags & (FDTF_LONGTIME | FDTF_SHORTTIME))
5061     {
5062         DWORD time = fmt_flags & FDTF_LONGTIME ? 0 : TIME_NOSECONDS;
5063 
5064         if (ret) ret--;
5065         ret += GetTimeFormatW(LOCALE_USER_DEFAULT, time, &st, NULL, &buf[ret], size - ret);
5066     }
5067 
5068     return ret;
5069 
5070 #undef SHFORMATDT_UNSUPPORTED_FLAGS
5071 }
5072 
5073 /***********************************************************************
5074  *             SHFormatDateTimeA [SHLWAPI.353]
5075  *
5076  * See SHFormatDateTimeW.
5077  *
5078  */
5079 INT WINAPI SHFormatDateTimeA(const FILETIME UNALIGNED *fileTime, DWORD *flags,
5080     LPSTR buf, UINT size)
5081 {
5082     WCHAR *bufW;
5083     INT retval;
5084 
5085     if (!buf || !size)
5086         return 0;
5087 
5088     bufW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * size);
5089     retval = SHFormatDateTimeW(fileTime, flags, bufW, size);
5090 
5091     if (retval != 0)
5092         WideCharToMultiByte(CP_ACP, 0, bufW, -1, buf, size, NULL, NULL);
5093 
5094     HeapFree(GetProcessHeap(), 0, bufW);
5095     return retval;
5096 }
5097 
5098 /***********************************************************************
5099  *             ZoneCheckUrlExW [SHLWAPI.231]
5100  *
5101  * Checks the details of the security zone for the supplied site. (?)
5102  *
5103  * PARAMS
5104  *
5105  *  szURL   [I] Pointer to the URL to check
5106  *
5107  *  Other parameters currently unknown.
5108  *
5109  * RETURNS
5110  *  unknown
5111  */
5112 
5113 INT WINAPI ZoneCheckUrlExW(LPWSTR szURL, PVOID pUnknown, DWORD dwUnknown2,
5114     DWORD dwUnknown3, DWORD dwUnknown4, DWORD dwUnknown5, DWORD dwUnknown6,
5115     DWORD dwUnknown7)
5116 {
5117     FIXME("(%s,%p,%x,%x,%x,%x,%x,%x) STUB\n", debugstr_w(szURL), pUnknown, dwUnknown2,
5118         dwUnknown3, dwUnknown4, dwUnknown5, dwUnknown6, dwUnknown7);
5119 
5120     return 0;
5121 }
5122 
5123 /***********************************************************************
5124  *             SHVerbExistsNA [SHLWAPI.196]
5125  *
5126  *
5127  * PARAMS
5128  *
5129  *  verb [I] a string, often appears to be an extension.
5130  *
5131  *  Other parameters currently unknown.
5132  *
5133  * RETURNS
5134  *  unknown
5135  */
5136 INT WINAPI SHVerbExistsNA(LPSTR verb, PVOID pUnknown, PVOID pUnknown2, DWORD dwUnknown3)
5137 {
5138     FIXME("(%s, %p, %p, %i) STUB\n",verb, pUnknown, pUnknown2, dwUnknown3);
5139     return 0;
5140 }
5141 
5142 /*************************************************************************
5143  *      @	[SHLWAPI.538]
5144  *
5145  *  Undocumented:  Implementation guessed at via Name and behavior
5146  *
5147  * PARAMS
5148  *  lpUnknown [I] Object to get an IServiceProvider interface from
5149  *  riid      [I] Function requested for QueryService call
5150  *  lppOut    [O] Destination for the service interface pointer
5151  *
5152  * RETURNS
5153  *  Success: S_OK. lppOut contains an object providing the requested service
5154  *  Failure: An HRESULT error code
5155  *
5156  * NOTES
5157  *  lpUnknown is expected to support the IServiceProvider interface.
5158  */
5159 HRESULT WINAPI IUnknown_QueryServiceForWebBrowserApp(IUnknown* lpUnknown,
5160         REFGUID riid, LPVOID *lppOut)
5161 {
5162     FIXME("%p %s %p semi-STUB\n", lpUnknown, debugstr_guid(riid), lppOut);
5163     return IUnknown_QueryService(lpUnknown,&IID_IWebBrowserApp,riid,lppOut);
5164 }
5165 
5166 /**************************************************************************
5167  *  SHPropertyBag_ReadLONG (SHLWAPI.496)
5168  *
5169  * This function asks a property bag to read a named property as a LONG.
5170  *
5171  * PARAMS
5172  *  ppb: a IPropertyBag interface
5173  *  pszPropName:  Unicode string that names the property
5174  *  pValue: address to receive the property value as a 32-bit signed integer
5175  *
5176  * RETURNS
5177  *  HRESULT codes
5178  */
5179 HRESULT WINAPI SHPropertyBag_ReadLONG(IPropertyBag *ppb, LPCWSTR pszPropName, LPLONG pValue)
5180 {
5181     VARIANT var;
5182     HRESULT hr;
5183     TRACE("%p %s %p\n", ppb,debugstr_w(pszPropName),pValue);
5184     if (!pszPropName || !ppb || !pValue)
5185         return E_INVALIDARG;
5186     V_VT(&var) = VT_I4;
5187     hr = IPropertyBag_Read(ppb, pszPropName, &var, NULL);
5188     if (SUCCEEDED(hr))
5189     {
5190         if (V_VT(&var) == VT_I4)
5191             *pValue = V_I4(&var);
5192         else
5193             hr = DISP_E_BADVARTYPE;
5194     }
5195     return hr;
5196 }
5197 
5198 #ifdef __REACTOS__
5199 /**************************************************************************
5200  *  SHPropertyBag_WriteLONG (SHLWAPI.497)
5201  *
5202  * This function asks a property bag to write a named property as a LONG.
5203  *
5204  * PARAMS
5205  *  ppb: a IPropertyBag interface
5206  *  pszPropName:  Unicode string that names the property
5207  *  lValue: address to receive the property value as a 32-bit signed integer
5208  *
5209  * RETURNS
5210  *  HRESULT codes
5211  */
5212 HRESULT WINAPI SHPropertyBag_WriteLONG(IPropertyBag *ppb, LPCWSTR pszPropName, LONG lValue)
5213 {
5214 	UNIMPLEMENTED;
5215 	return E_NOTIMPL;
5216 }
5217 
5218 /**************************************************************************
5219  *  SHPropertyBag_WriteStr (SHLWAPI.495)
5220  *
5221  * This function asks a property bag to write a string as the value of a named property.
5222  *
5223  * PARAMS
5224  *  ppb: a IPropertyBag interface
5225  *  pszPropName:  Unicode string that names the property
5226  *  pValue: address to write the property value
5227  *
5228  * RETURNS
5229  *  HRESULT codes
5230  */
5231 HRESULT WINAPI SHPropertyBag_WriteStr(IPropertyBag *ppb, LPCWSTR pszPropName, LPCWSTR pszValue)
5232 {
5233 	UNIMPLEMENTED;
5234 	return E_NOTIMPL;
5235 }
5236 #endif
5237 
5238 /* return flags for SHGetObjectCompatFlags, names derived from registry value names */
5239 #define OBJCOMPAT_OTNEEDSSFCACHE           0x00000001
5240 #define OBJCOMPAT_NO_WEBVIEW               0x00000002
5241 #define OBJCOMPAT_UNBINDABLE               0x00000004
5242 #define OBJCOMPAT_PINDLL                   0x00000008
5243 #define OBJCOMPAT_NEEDSFILESYSANCESTOR     0x00000010
5244 #define OBJCOMPAT_NOTAFILESYSTEM           0x00000020
5245 #define OBJCOMPAT_CTXMENU_NOVERBS          0x00000040
5246 #define OBJCOMPAT_CTXMENU_LIMITEDQI        0x00000080
5247 #define OBJCOMPAT_COCREATESHELLFOLDERONLY  0x00000100
5248 #define OBJCOMPAT_NEEDSSTORAGEANCESTOR     0x00000200
5249 #define OBJCOMPAT_NOLEGACYWEBVIEW          0x00000400
5250 #define OBJCOMPAT_CTXMENU_XPQCMFLAGS       0x00001000
5251 #define OBJCOMPAT_NOIPROPERTYSTORE         0x00002000
5252 
5253 /* a search table for compatibility flags */
5254 struct objcompat_entry {
5255     const WCHAR name[30];
5256     DWORD value;
5257 };
5258 
5259 /* expected to be sorted by name */
5260 static const struct objcompat_entry objcompat_table[] = {
5261     { {'C','O','C','R','E','A','T','E','S','H','E','L','L','F','O','L','D','E','R','O','N','L','Y',0},
5262       OBJCOMPAT_COCREATESHELLFOLDERONLY },
5263     { {'C','T','X','M','E','N','U','_','L','I','M','I','T','E','D','Q','I',0},
5264       OBJCOMPAT_CTXMENU_LIMITEDQI },
5265     { {'C','T','X','M','E','N','U','_','N','O','V','E','R','B','S',0},
5266       OBJCOMPAT_CTXMENU_LIMITEDQI },
5267     { {'C','T','X','M','E','N','U','_','X','P','Q','C','M','F','L','A','G','S',0},
5268       OBJCOMPAT_CTXMENU_XPQCMFLAGS },
5269     { {'N','E','E','D','S','F','I','L','E','S','Y','S','A','N','C','E','S','T','O','R',0},
5270       OBJCOMPAT_NEEDSFILESYSANCESTOR },
5271     { {'N','E','E','D','S','S','T','O','R','A','G','E','A','N','C','E','S','T','O','R',0},
5272       OBJCOMPAT_NEEDSSTORAGEANCESTOR },
5273     { {'N','O','I','P','R','O','P','E','R','T','Y','S','T','O','R','E',0},
5274       OBJCOMPAT_NOIPROPERTYSTORE },
5275     { {'N','O','L','E','G','A','C','Y','W','E','B','V','I','E','W',0},
5276       OBJCOMPAT_NOLEGACYWEBVIEW },
5277     { {'N','O','T','A','F','I','L','E','S','Y','S','T','E','M',0},
5278       OBJCOMPAT_NOTAFILESYSTEM },
5279     { {'N','O','_','W','E','B','V','I','E','W',0},
5280       OBJCOMPAT_NO_WEBVIEW },
5281     { {'O','T','N','E','E','D','S','S','F','C','A','C','H','E',0},
5282       OBJCOMPAT_OTNEEDSSFCACHE },
5283     { {'P','I','N','D','L','L',0},
5284       OBJCOMPAT_PINDLL },
5285     { {'U','N','B','I','N','D','A','B','L','E',0},
5286       OBJCOMPAT_UNBINDABLE }
5287 };
5288 
5289 /**************************************************************************
5290  *  SHGetObjectCompatFlags (SHLWAPI.476)
5291  *
5292  * Function returns an integer representation of compatibility flags stored
5293  * in registry for CLSID under ShellCompatibility subkey.
5294  *
5295  * PARAMS
5296  *  pUnk:  pointer to object IUnknown interface, idetifies CLSID
5297  *  clsid: pointer to CLSID to retrieve data for
5298  *
5299  * RETURNS
5300  *  0 on failure, flags set on success
5301  */
5302 DWORD WINAPI SHGetObjectCompatFlags(IUnknown *pUnk, const CLSID *clsid)
5303 {
5304     static const WCHAR compatpathW[] =
5305         {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
5306          'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5307          'S','h','e','l','l','C','o','m','p','a','t','i','b','i','l','i','t','y','\\',
5308          'O','b','j','e','c','t','s','\\','%','s',0};
5309     WCHAR strW[sizeof(compatpathW)/sizeof(WCHAR) + 38 /* { CLSID } */];
5310     DWORD ret, length = sizeof(strW)/sizeof(WCHAR);
5311     OLECHAR *clsid_str;
5312     HKEY key;
5313     INT i;
5314 
5315     TRACE("%p %s\n", pUnk, debugstr_guid(clsid));
5316 
5317     if (!pUnk && !clsid) return 0;
5318 
5319     if (pUnk && !clsid)
5320     {
5321         FIXME("iface not handled\n");
5322         return 0;
5323     }
5324 
5325     StringFromCLSID(clsid, &clsid_str);
5326     sprintfW(strW, compatpathW, clsid_str);
5327     CoTaskMemFree(clsid_str);
5328 
5329     ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, strW, &key);
5330     if (ret != ERROR_SUCCESS) return 0;
5331 
5332     /* now collect flag values */
5333     ret = 0;
5334     for (i = 0; RegEnumValueW(key, i, strW, &length, NULL, NULL, NULL, NULL) == ERROR_SUCCESS; i++)
5335     {
5336         INT left, right, res, x;
5337 
5338         /* search in table */
5339         left  = 0;
5340         right = sizeof(objcompat_table) / sizeof(struct objcompat_entry) - 1;
5341 
5342         while (right >= left) {
5343             x = (left + right) / 2;
5344             res = strcmpW(strW, objcompat_table[x].name);
5345             if (res == 0)
5346             {
5347                 ret |= objcompat_table[x].value;
5348                 break;
5349             }
5350             else if (res < 0)
5351                 right = x - 1;
5352             else
5353                 left = x + 1;
5354         }
5355 
5356         length = sizeof(strW)/sizeof(WCHAR);
5357     }
5358 
5359     return ret;
5360 }
5361