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