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