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