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