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