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