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