windowscodecs: Replace a call to a deprecated libpng function.
[wine] / dlls / shlwapi / ordinal.c
1 /*
2  * SHLWAPI ordinal functions
3  *
4  * Copyright 1997 Marcus Meissner
5  *           1998 Jürgen Schmied
6  *           2001-2003 Jon Griffiths
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <string.h>
29
30 #define COBJMACROS
31 #define NONAMELESSUNION
32 #define NONAMELESSSTRUCT
33
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winnls.h"
37 #include "winreg.h"
38 #include "wingdi.h"
39 #include "winuser.h"
40 #include "winver.h"
41 #include "winnetwk.h"
42 #include "mmsystem.h"
43 #include "objbase.h"
44 #include "exdisp.h"
45 #include "shlobj.h"
46 #include "shlwapi.h"
47 #include "shellapi.h"
48 #include "commdlg.h"
49 #include "mshtmhst.h"
50 #include "wine/unicode.h"
51 #include "wine/debug.h"
52
53
54 WINE_DEFAULT_DEBUG_CHANNEL(shell);
55
56 /* DLL handles for late bound calls */
57 extern HINSTANCE shlwapi_hInstance;
58 extern DWORD SHLWAPI_ThreadRef_index;
59
60 HRESULT WINAPI IUnknown_QueryService(IUnknown*,REFGUID,REFIID,LPVOID*);
61 HRESULT WINAPI SHInvokeCommand(HWND,IShellFolder*,LPCITEMIDLIST,BOOL);
62 BOOL    WINAPI SHAboutInfoW(LPWSTR,DWORD);
63
64 /*
65  NOTES: Most functions exported by ordinal seem to be superfluous.
66  The reason for these functions to be there is to provide a wrapper
67  for unicode functions to provide these functions on systems without
68  unicode functions eg. win95/win98. Since we have such functions we just
69  call these. If running Wine with native DLLs, some late bound calls may
70  fail. However, it is better to implement the functions in the forward DLL
71  and recommend the builtin rather than reimplementing the calls here!
72 */
73
74 /*************************************************************************
75  * SHLWAPI_DupSharedHandle
76  *
77  * Internal implemetation of SHLWAPI_11.
78  */
79 static HANDLE 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 == S_OK && pIEnumFormatEtc)
425     {
426       /* Clone and register the enumerator */
427       hRet = IEnumFORMATETC_Clone(pIEnumFormatEtc, &pClone);
428       if (hRet == S_OK && 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  *  fConnect    [I] TRUE = Connection being establisted, FALSE = broken
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 fConnect,
1144                            IUnknown* lpUnknown, LPDWORD lpCookie,
1145                            IConnectionPoint **lppCP)
1146 {
1147   HRESULT hRet;
1148   IConnectionPointContainer* lpContainer;
1149   IConnectionPoint *lpCP;
1150
1151   if(!lpUnknown || (fConnect && !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(!fConnect)
1166         hRet = IConnectionPoint_Unadvise(lpCP, *lpCookie);
1167       else
1168         hRet = IConnectionPoint_Advise(lpCP, lpUnkSink, lpCookie);
1169
1170       if (FAILED(hRet))
1171         *lpCookie = 0;
1172
1173       if (lppCP && SUCCEEDED(hRet))
1174         *lppCP = lpCP; /* Caller keeps the interface */
1175       else
1176         IConnectionPoint_Release(lpCP); /* Release it */
1177     }
1178
1179     IUnknown_Release(lpContainer);
1180   }
1181   return hRet;
1182 }
1183
1184 /*************************************************************************
1185  *      @       [SHLWAPI.169]
1186  *
1187  * Release an interface.
1188  *
1189  * PARAMS
1190  *  lpUnknown [I] Object to release
1191  *
1192  * RETURNS
1193  *  Nothing.
1194  */
1195 DWORD WINAPI IUnknown_AtomicRelease(IUnknown ** lpUnknown)
1196 {
1197     IUnknown *temp;
1198
1199     TRACE("(%p)\n",lpUnknown);
1200
1201     if(!lpUnknown || !*((LPDWORD)lpUnknown)) return 0;
1202     temp = *lpUnknown;
1203     *lpUnknown = NULL;
1204
1205     TRACE("doing Release\n");
1206
1207     return IUnknown_Release(temp);
1208 }
1209
1210 /*************************************************************************
1211  *      @       [SHLWAPI.170]
1212  *
1213  * Skip '//' if present in a string.
1214  *
1215  * PARAMS
1216  *  lpszSrc [I] String to check for '//'
1217  *
1218  * RETURNS
1219  *  Success: The next character after the '//' or the string if not present
1220  *  Failure: NULL, if lpszStr is NULL.
1221  */
1222 LPCSTR WINAPI PathSkipLeadingSlashesA(LPCSTR lpszSrc)
1223 {
1224   if (lpszSrc && lpszSrc[0] == '/' && lpszSrc[1] == '/')
1225     lpszSrc += 2;
1226   return lpszSrc;
1227 }
1228
1229 /*************************************************************************
1230  *      @               [SHLWAPI.171]
1231  *
1232  * Check if two interfaces come from the same object.
1233  *
1234  * PARAMS
1235  *   lpInt1 [I] Interface to check against lpInt2.
1236  *   lpInt2 [I] Interface to check against lpInt1.
1237  *
1238  * RETURNS
1239  *   TRUE, If the interfaces come from the same object.
1240  *   FALSE Otherwise.
1241  */
1242 BOOL WINAPI SHIsSameObject(IUnknown* lpInt1, IUnknown* lpInt2)
1243 {
1244   LPVOID lpUnknown1, lpUnknown2;
1245
1246   TRACE("%p %p\n", lpInt1, lpInt2);
1247
1248   if (!lpInt1 || !lpInt2)
1249     return FALSE;
1250
1251   if (lpInt1 == lpInt2)
1252     return TRUE;
1253
1254   if (FAILED(IUnknown_QueryInterface(lpInt1, &IID_IUnknown, &lpUnknown1)))
1255     return FALSE;
1256
1257   if (FAILED(IUnknown_QueryInterface(lpInt2, &IID_IUnknown, &lpUnknown2)))
1258     return FALSE;
1259
1260   if (lpUnknown1 == lpUnknown2)
1261     return TRUE;
1262
1263   return FALSE;
1264 }
1265
1266 /*************************************************************************
1267  *      @       [SHLWAPI.172]
1268  *
1269  * Get the window handle of an object.
1270  *
1271  * PARAMS
1272  *  lpUnknown [I] Object to get the window handle of
1273  *  lphWnd    [O] Destination for window handle
1274  *
1275  * RETURNS
1276  *  Success: S_OK. lphWnd contains the objects window handle.
1277  *  Failure: An HRESULT error code.
1278  *
1279  * NOTES
1280  *  lpUnknown is expected to support one of the following interfaces:
1281  *  IOleWindow(), IInternetSecurityMgrSite(), or IShellView().
1282  */
1283 HRESULT WINAPI IUnknown_GetWindow(IUnknown *lpUnknown, HWND *lphWnd)
1284 {
1285   IUnknown *lpOle;
1286   HRESULT hRet = E_FAIL;
1287
1288   TRACE("(%p,%p)\n", lpUnknown, lphWnd);
1289
1290   if (!lpUnknown)
1291     return hRet;
1292
1293   hRet = IUnknown_QueryInterface(lpUnknown, &IID_IOleWindow, (void**)&lpOle);
1294
1295   if (FAILED(hRet))
1296   {
1297     hRet = IUnknown_QueryInterface(lpUnknown,&IID_IShellView, (void**)&lpOle);
1298
1299     if (FAILED(hRet))
1300     {
1301       hRet = IUnknown_QueryInterface(lpUnknown, &IID_IInternetSecurityMgrSite,
1302                                       (void**)&lpOle);
1303     }
1304   }
1305
1306   if (SUCCEEDED(hRet))
1307   {
1308     /* Lazyness here - Since GetWindow() is the first method for the above 3
1309      * interfaces, we use the same call for them all.
1310      */
1311     hRet = IOleWindow_GetWindow((IOleWindow*)lpOle, lphWnd);
1312     IUnknown_Release(lpOle);
1313     if (lphWnd)
1314       TRACE("Returning HWND=%p\n", *lphWnd);
1315   }
1316
1317   return hRet;
1318 }
1319
1320 /*************************************************************************
1321  *      @       [SHLWAPI.173]
1322  *
1323  * Call a method on as as yet unidentified object.
1324  *
1325  * PARAMS
1326  *  pUnk [I] Object supporting the unidentified interface,
1327  *  arg  [I] Argument for the call on the object.
1328  *
1329  * RETURNS
1330  *  S_OK.
1331  */
1332 HRESULT WINAPI IUnknown_SetOwner(IUnknown *pUnk, ULONG arg)
1333 {
1334   static const GUID guid_173 = {
1335     0x5836fb00, 0x8187, 0x11cf, { 0xa1,0x2b,0x00,0xaa,0x00,0x4a,0xe8,0x37 }
1336   };
1337   IMalloc *pUnk2;
1338
1339   TRACE("(%p,%d)\n", pUnk, arg);
1340
1341   /* Note: arg may not be a ULONG and pUnk2 is for sure not an IMalloc -
1342    *       We use this interface as its vtable entry is compatible with the
1343    *       object in question.
1344    * FIXME: Find out what this object is and where it should be defined.
1345    */
1346   if (pUnk &&
1347       SUCCEEDED(IUnknown_QueryInterface(pUnk, &guid_173, (void**)&pUnk2)))
1348   {
1349     IMalloc_Alloc(pUnk2, arg); /* Faked call!! */
1350     IMalloc_Release(pUnk2);
1351   }
1352   return S_OK;
1353 }
1354
1355 /*************************************************************************
1356  *      @       [SHLWAPI.174]
1357  *
1358  * Call either IObjectWithSite_SetSite() or IInternetSecurityManager_SetSecuritySite() on
1359  * an object.
1360  *
1361  */
1362 HRESULT WINAPI IUnknown_SetSite(
1363         IUnknown *obj,        /* [in]   OLE object     */
1364         IUnknown *site)       /* [in]   Site interface */
1365 {
1366     HRESULT hr;
1367     IObjectWithSite *iobjwithsite;
1368     IInternetSecurityManager *isecmgr;
1369
1370     if (!obj) return E_FAIL;
1371
1372     hr = IUnknown_QueryInterface(obj, &IID_IObjectWithSite, (LPVOID *)&iobjwithsite);
1373     TRACE("IID_IObjectWithSite QI ret=%08x, %p\n", hr, iobjwithsite);
1374     if (SUCCEEDED(hr))
1375     {
1376         hr = IObjectWithSite_SetSite(iobjwithsite, site);
1377         TRACE("done IObjectWithSite_SetSite ret=%08x\n", hr);
1378         IUnknown_Release(iobjwithsite);
1379     }
1380     else
1381     {
1382         hr = IUnknown_QueryInterface(obj, &IID_IInternetSecurityManager, (LPVOID *)&isecmgr);
1383         TRACE("IID_IInternetSecurityManager QI ret=%08x, %p\n", hr, isecmgr);
1384         if (FAILED(hr)) return hr;
1385
1386         hr = IInternetSecurityManager_SetSecuritySite(isecmgr, (IInternetSecurityMgrSite *)site);
1387         TRACE("done IInternetSecurityManager_SetSecuritySite ret=%08x\n", hr);
1388         IUnknown_Release(isecmgr);
1389     }
1390     return hr;
1391 }
1392
1393 /*************************************************************************
1394  *      @       [SHLWAPI.175]
1395  *
1396  * Call IPersist_GetClassID() on an object.
1397  *
1398  * PARAMS
1399  *  lpUnknown [I] Object supporting the IPersist interface
1400  *  lpClassId [O] Destination for Class Id
1401  *
1402  * RETURNS
1403  *  Success: S_OK. lpClassId contains the Class Id requested.
1404  *  Failure: E_FAIL, If lpUnknown is NULL,
1405  *           E_NOINTERFACE If lpUnknown does not support IPersist,
1406  *           Or an HRESULT error code.
1407  */
1408 HRESULT WINAPI IUnknown_GetClassID(IUnknown *lpUnknown, CLSID* lpClassId)
1409 {
1410   IPersist* lpPersist;
1411   HRESULT hRet = E_FAIL;
1412
1413   TRACE("(%p,%p)\n", lpUnknown, debugstr_guid(lpClassId));
1414
1415   if (lpUnknown)
1416   {
1417     hRet = IUnknown_QueryInterface(lpUnknown,&IID_IPersist,(void**)&lpPersist);
1418     if (SUCCEEDED(hRet))
1419     {
1420       IPersist_GetClassID(lpPersist, lpClassId);
1421       IPersist_Release(lpPersist);
1422     }
1423   }
1424   return hRet;
1425 }
1426
1427 /*************************************************************************
1428  *      @       [SHLWAPI.176]
1429  *
1430  * Retrieve a Service Interface from an object.
1431  *
1432  * PARAMS
1433  *  lpUnknown [I] Object to get an IServiceProvider interface from
1434  *  sid       [I] Service ID for IServiceProvider_QueryService() call
1435  *  riid      [I] Function requested for QueryService call
1436  *  lppOut    [O] Destination for the service interface pointer
1437  *
1438  * RETURNS
1439  *  Success: S_OK. lppOut contains an object providing the requested service
1440  *  Failure: An HRESULT error code
1441  *
1442  * NOTES
1443  *  lpUnknown is expected to support the IServiceProvider interface.
1444  */
1445 HRESULT WINAPI IUnknown_QueryService(IUnknown* lpUnknown, REFGUID sid, REFIID riid,
1446                            LPVOID *lppOut)
1447 {
1448   IServiceProvider* pService = NULL;
1449   HRESULT hRet;
1450
1451   if (!lppOut)
1452     return E_FAIL;
1453
1454   *lppOut = NULL;
1455
1456   if (!lpUnknown)
1457     return E_FAIL;
1458
1459   /* Get an IServiceProvider interface from the object */
1460   hRet = IUnknown_QueryInterface(lpUnknown, &IID_IServiceProvider,
1461                                  (LPVOID*)&pService);
1462
1463   if (hRet == S_OK && pService)
1464   {
1465     TRACE("QueryInterface returned (IServiceProvider*)%p\n", pService);
1466
1467     /* Get a Service interface from the object */
1468     hRet = IServiceProvider_QueryService(pService, sid, riid, lppOut);
1469
1470     TRACE("(IServiceProvider*)%p returned (IUnknown*)%p\n", pService, *lppOut);
1471
1472     /* Release the IServiceProvider interface */
1473     IUnknown_Release(pService);
1474   }
1475   return hRet;
1476 }
1477
1478 /*************************************************************************
1479  *      @       [SHLWAPI.479]
1480  *
1481  * Call an object's UIActivateIO method.
1482  *
1483  * PARAMS
1484  *  unknown  [I] Object to call the UIActivateIO method on
1485  *  activate [I] Parameter for UIActivateIO call
1486  *  msg      [I] Parameter for UIActivateIO call
1487  *
1488  * RETURNS
1489  *  Success: Value of UI_ActivateIO call
1490  *  Failure: An HRESULT error code
1491  *
1492  * NOTES
1493  *  unknown is expected to support the IInputObject interface.
1494  */
1495 HRESULT WINAPI IUnknown_UIActivateIO(IUnknown *unknown, BOOL activate, LPMSG msg)
1496 {
1497     IInputObject* object = NULL;
1498     HRESULT ret;
1499
1500     if (!unknown)
1501         return E_FAIL;
1502
1503     /* Get an IInputObject interface from the object */
1504     ret = IUnknown_QueryInterface(unknown, &IID_IInputObject, (LPVOID*) &object);
1505
1506     if (ret == S_OK)
1507     {
1508         ret = IInputObject_UIActivateIO(object, activate, msg);
1509         IUnknown_Release(object);
1510     }
1511
1512     return ret;
1513 }
1514
1515 /*************************************************************************
1516  *      @       [SHLWAPI.177]
1517  *
1518  * Loads a popup menu.
1519  *
1520  * PARAMS
1521  *  hInst  [I] Instance handle
1522  *  szName [I] Menu name
1523  *
1524  * RETURNS
1525  *  Success: TRUE.
1526  *  Failure: FALSE.
1527  */
1528 BOOL WINAPI SHLoadMenuPopup(HINSTANCE hInst, LPCWSTR szName)
1529 {
1530   HMENU hMenu;
1531
1532   if ((hMenu = LoadMenuW(hInst, szName)))
1533   {
1534     if (GetSubMenu(hMenu, 0))
1535       RemoveMenu(hMenu, 0, MF_BYPOSITION);
1536
1537     DestroyMenu(hMenu);
1538     return TRUE;
1539   }
1540   return FALSE;
1541 }
1542
1543 typedef struct _enumWndData
1544 {
1545   UINT   uiMsgId;
1546   WPARAM wParam;
1547   LPARAM lParam;
1548   LRESULT (WINAPI *pfnPost)(HWND,UINT,WPARAM,LPARAM);
1549 } enumWndData;
1550
1551 /* Callback for SHLWAPI_178 */
1552 static BOOL CALLBACK SHLWAPI_EnumChildProc(HWND hWnd, LPARAM lParam)
1553 {
1554   enumWndData *data = (enumWndData *)lParam;
1555
1556   TRACE("(%p,%p)\n", hWnd, data);
1557   data->pfnPost(hWnd, data->uiMsgId, data->wParam, data->lParam);
1558   return TRUE;
1559 }
1560
1561 /*************************************************************************
1562  * @  [SHLWAPI.178]
1563  *
1564  * Send or post a message to every child of a window.
1565  *
1566  * PARAMS
1567  *  hWnd    [I] Window whose children will get the messages
1568  *  uiMsgId [I] Message Id
1569  *  wParam  [I] WPARAM of message
1570  *  lParam  [I] LPARAM of message
1571  *  bSend   [I] TRUE = Use SendMessageA(), FALSE = Use PostMessageA()
1572  *
1573  * RETURNS
1574  *  Nothing.
1575  *
1576  * NOTES
1577  *  The appropriate ASCII or Unicode function is called for the window.
1578  */
1579 void WINAPI SHPropagateMessage(HWND hWnd, UINT uiMsgId, WPARAM wParam, LPARAM lParam, BOOL bSend)
1580 {
1581   enumWndData data;
1582
1583   TRACE("(%p,%u,%ld,%ld,%d)\n", hWnd, uiMsgId, wParam, lParam, bSend);
1584
1585   if(hWnd)
1586   {
1587     data.uiMsgId = uiMsgId;
1588     data.wParam  = wParam;
1589     data.lParam  = lParam;
1590
1591     if (bSend)
1592       data.pfnPost = IsWindowUnicode(hWnd) ? (void*)SendMessageW : (void*)SendMessageA;
1593     else
1594       data.pfnPost = IsWindowUnicode(hWnd) ? (void*)PostMessageW : (void*)PostMessageA;
1595
1596     EnumChildWindows(hWnd, SHLWAPI_EnumChildProc, (LPARAM)&data);
1597   }
1598 }
1599
1600 /*************************************************************************
1601  *      @       [SHLWAPI.180]
1602  *
1603  * Remove all sub-menus from a menu.
1604  *
1605  * PARAMS
1606  *  hMenu [I] Menu to remove sub-menus from
1607  *
1608  * RETURNS
1609  *  Success: 0.  All sub-menus under hMenu are removed
1610  *  Failure: -1, if any parameter is invalid
1611  */
1612 DWORD WINAPI SHRemoveAllSubMenus(HMENU hMenu)
1613 {
1614   int iItemCount = GetMenuItemCount(hMenu) - 1;
1615   while (iItemCount >= 0)
1616   {
1617     HMENU hSubMenu = GetSubMenu(hMenu, iItemCount);
1618     if (hSubMenu)
1619       RemoveMenu(hMenu, iItemCount, MF_BYPOSITION);
1620     iItemCount--;
1621   }
1622   return iItemCount;
1623 }
1624
1625 /*************************************************************************
1626  *      @       [SHLWAPI.181]
1627  *
1628  * Enable or disable a menu item.
1629  *
1630  * PARAMS
1631  *  hMenu   [I] Menu holding menu item
1632  *  uID     [I] ID of menu item to enable/disable
1633  *  bEnable [I] Whether to enable (TRUE) or disable (FALSE) the item.
1634  *
1635  * RETURNS
1636  *  The return code from EnableMenuItem.
1637  */
1638 UINT WINAPI SHEnableMenuItem(HMENU hMenu, UINT wItemID, BOOL bEnable)
1639 {
1640   return EnableMenuItem(hMenu, wItemID, bEnable ? MF_ENABLED : MF_GRAYED);
1641 }
1642
1643 /*************************************************************************
1644  * @    [SHLWAPI.182]
1645  *
1646  * Check or uncheck a menu item.
1647  *
1648  * PARAMS
1649  *  hMenu  [I] Menu holding menu item
1650  *  uID    [I] ID of menu item to check/uncheck
1651  *  bCheck [I] Whether to check (TRUE) or uncheck (FALSE) the item.
1652  *
1653  * RETURNS
1654  *  The return code from CheckMenuItem.
1655  */
1656 DWORD WINAPI SHCheckMenuItem(HMENU hMenu, UINT uID, BOOL bCheck)
1657 {
1658   return CheckMenuItem(hMenu, uID, bCheck ? MF_CHECKED : MF_UNCHECKED);
1659 }
1660
1661 /*************************************************************************
1662  *      @       [SHLWAPI.183]
1663  *
1664  * Register a window class if it isn't already.
1665  *
1666  * PARAMS
1667  *  lpWndClass [I] Window class to register
1668  *
1669  * RETURNS
1670  *  The result of the RegisterClassA call.
1671  */
1672 DWORD WINAPI SHRegisterClassA(WNDCLASSA *wndclass)
1673 {
1674   WNDCLASSA wca;
1675   if (GetClassInfoA(wndclass->hInstance, wndclass->lpszClassName, &wca))
1676     return TRUE;
1677   return (DWORD)RegisterClassA(wndclass);
1678 }
1679
1680 /*************************************************************************
1681  *      @       [SHLWAPI.186]
1682  */
1683 BOOL WINAPI SHSimulateDrop(IDropTarget *pDrop, IDataObject *pDataObj,
1684                            DWORD grfKeyState, PPOINTL lpPt, DWORD* pdwEffect)
1685 {
1686   DWORD dwEffect = DROPEFFECT_LINK | DROPEFFECT_MOVE | DROPEFFECT_COPY;
1687   POINTL pt = { 0, 0 };
1688
1689   if (!lpPt)
1690     lpPt = &pt;
1691
1692   if (!pdwEffect)
1693     pdwEffect = &dwEffect;
1694
1695   IDropTarget_DragEnter(pDrop, pDataObj, grfKeyState, *lpPt, pdwEffect);
1696
1697   if (*pdwEffect)
1698     return IDropTarget_Drop(pDrop, pDataObj, grfKeyState, *lpPt, pdwEffect);
1699
1700   IDropTarget_DragLeave(pDrop);
1701   return TRUE;
1702 }
1703
1704 /*************************************************************************
1705  *      @       [SHLWAPI.187]
1706  *
1707  * Call IPersistPropertyBag_Load() on an object.
1708  *
1709  * PARAMS
1710  *  lpUnknown [I] Object supporting the IPersistPropertyBag interface
1711  *  lpPropBag [O] Destination for loaded IPropertyBag
1712  *
1713  * RETURNS
1714  *  Success: S_OK.
1715  *  Failure: An HRESULT error code, or E_FAIL if lpUnknown is NULL.
1716  */
1717 DWORD WINAPI SHLoadFromPropertyBag(IUnknown *lpUnknown, IPropertyBag* lpPropBag)
1718 {
1719   IPersistPropertyBag* lpPPBag;
1720   HRESULT hRet = E_FAIL;
1721
1722   TRACE("(%p,%p)\n", lpUnknown, lpPropBag);
1723
1724   if (lpUnknown)
1725   {
1726     hRet = IUnknown_QueryInterface(lpUnknown, &IID_IPersistPropertyBag,
1727                                    (void**)&lpPPBag);
1728     if (SUCCEEDED(hRet) && lpPPBag)
1729     {
1730       hRet = IPersistPropertyBag_Load(lpPPBag, lpPropBag, NULL);
1731       IPersistPropertyBag_Release(lpPPBag);
1732     }
1733   }
1734   return hRet;
1735 }
1736
1737 /*************************************************************************
1738  * @  [SHLWAPI.188]
1739  *
1740  * Call IOleControlSite_TranslateAccelerator()  on an object.
1741  *
1742  * PARAMS
1743  *  lpUnknown   [I] Object supporting the IOleControlSite interface.
1744  *  lpMsg       [I] Key message to be processed.
1745  *  dwModifiers [I] Flags containing the state of the modifier keys.
1746  *
1747  * RETURNS
1748  *  Success: S_OK.
1749  *  Failure: An HRESULT error code, or E_INVALIDARG if lpUnknown is NULL.
1750  */
1751 HRESULT WINAPI IUnknown_TranslateAcceleratorOCS(IUnknown *lpUnknown, LPMSG lpMsg, DWORD dwModifiers)
1752 {
1753   IOleControlSite* lpCSite = NULL;
1754   HRESULT hRet = E_INVALIDARG;
1755
1756   TRACE("(%p,%p,0x%08x)\n", lpUnknown, lpMsg, dwModifiers);
1757   if (lpUnknown)
1758   {
1759     hRet = IUnknown_QueryInterface(lpUnknown, &IID_IOleControlSite,
1760                                    (void**)&lpCSite);
1761     if (SUCCEEDED(hRet) && lpCSite)
1762     {
1763       hRet = IOleControlSite_TranslateAccelerator(lpCSite, lpMsg, dwModifiers);
1764       IOleControlSite_Release(lpCSite);
1765     }
1766   }
1767   return hRet;
1768 }
1769
1770
1771 /*************************************************************************
1772  * @  [SHLWAPI.189]
1773  *
1774  * Call IOleControlSite_OnFocus() on an object.
1775  *
1776  * PARAMS
1777  *  lpUnknown [I] Object supporting the IOleControlSite interface.
1778  *  fGotFocus [I] Whether focus was gained (TRUE) or lost (FALSE).
1779  *
1780  * RETURNS
1781  *  Success: S_OK.
1782  *  Failure: An HRESULT error code, or E_FAIL if lpUnknown is NULL.
1783  */
1784 HRESULT WINAPI IUnknown_OnFocusOCS(IUnknown *lpUnknown, BOOL fGotFocus)
1785 {
1786   IOleControlSite* lpCSite = NULL;
1787   HRESULT hRet = E_FAIL;
1788
1789   TRACE("(%p,%s)\n", lpUnknown, fGotFocus ? "TRUE" : "FALSE");
1790   if (lpUnknown)
1791   {
1792     hRet = IUnknown_QueryInterface(lpUnknown, &IID_IOleControlSite,
1793                                    (void**)&lpCSite);
1794     if (SUCCEEDED(hRet) && lpCSite)
1795     {
1796       hRet = IOleControlSite_OnFocus(lpCSite, fGotFocus);
1797       IOleControlSite_Release(lpCSite);
1798     }
1799   }
1800   return hRet;
1801 }
1802
1803 /*************************************************************************
1804  * @    [SHLWAPI.190]
1805  */
1806 HRESULT WINAPI IUnknown_HandleIRestrict(LPUNKNOWN lpUnknown, PVOID lpArg1,
1807                                         PVOID lpArg2, PVOID lpArg3, PVOID lpArg4)
1808 {
1809   /* FIXME: {D12F26B2-D90A-11D0-830D-00AA005B4383} - What object does this represent? */
1810   static const DWORD service_id[] = { 0xd12f26b2, 0x11d0d90a, 0xaa000d83, 0x83435b00 };
1811   /* FIXME: {D12F26B1-D90A-11D0-830D-00AA005B4383} - Also Unknown/undocumented */
1812   static const DWORD function_id[] = { 0xd12f26b1, 0x11d0d90a, 0xaa000d83, 0x83435b00 };
1813   HRESULT hRet = E_INVALIDARG;
1814   LPUNKNOWN lpUnkInner = NULL; /* FIXME: Real type is unknown */
1815
1816   TRACE("(%p,%p,%p,%p,%p)\n", lpUnknown, lpArg1, lpArg2, lpArg3, lpArg4);
1817
1818   if (lpUnknown && lpArg4)
1819   {
1820      hRet = IUnknown_QueryService(lpUnknown, (REFGUID)service_id,
1821                                   (REFGUID)function_id, (void**)&lpUnkInner);
1822
1823      if (SUCCEEDED(hRet) && lpUnkInner)
1824      {
1825        /* FIXME: The type of service object requested is unknown, however
1826         * testing shows that its first method is called with 4 parameters.
1827         * Fake this by using IParseDisplayName_ParseDisplayName since the
1828         * signature and position in the vtable matches our unknown object type.
1829         */
1830        hRet = IParseDisplayName_ParseDisplayName((LPPARSEDISPLAYNAME)lpUnkInner,
1831                                                  lpArg1, lpArg2, lpArg3, lpArg4);
1832        IUnknown_Release(lpUnkInner);
1833      }
1834   }
1835   return hRet;
1836 }
1837
1838 /*************************************************************************
1839  * @    [SHLWAPI.192]
1840  *
1841  * Get a sub-menu from a menu item.
1842  *
1843  * PARAMS
1844  *  hMenu [I] Menu to get sub-menu from
1845  *  uID   [I] ID of menu item containing sub-menu
1846  *
1847  * RETURNS
1848  *  The sub-menu of the item, or a NULL handle if any parameters are invalid.
1849  */
1850 HMENU WINAPI SHGetMenuFromID(HMENU hMenu, UINT uID)
1851 {
1852   MENUITEMINFOW mi;
1853
1854   TRACE("(%p,%u)\n", hMenu, uID);
1855
1856   mi.cbSize = sizeof(mi);
1857   mi.fMask = MIIM_SUBMENU;
1858
1859   if (!GetMenuItemInfoW(hMenu, uID, FALSE, &mi))
1860     return NULL;
1861
1862   return mi.hSubMenu;
1863 }
1864
1865 /*************************************************************************
1866  *      @       [SHLWAPI.193]
1867  *
1868  * Get the color depth of the primary display.
1869  *
1870  * PARAMS
1871  *  None.
1872  *
1873  * RETURNS
1874  *  The color depth of the primary display.
1875  */
1876 DWORD WINAPI SHGetCurColorRes(void)
1877 {
1878     HDC hdc;
1879     DWORD ret;
1880
1881     TRACE("()\n");
1882
1883     hdc = GetDC(0);
1884     ret = GetDeviceCaps(hdc, BITSPIXEL) * GetDeviceCaps(hdc, PLANES);
1885     ReleaseDC(0, hdc);
1886     return ret;
1887 }
1888
1889 /*************************************************************************
1890  *      @       [SHLWAPI.194]
1891  *
1892  * Wait for a message to arrive, with a timeout.
1893  *
1894  * PARAMS
1895  *  hand      [I] Handle to query
1896  *  dwTimeout [I] Timeout in ticks or INFINITE to never timeout
1897  *
1898  * RETURNS
1899  *  STATUS_TIMEOUT if no message is received before dwTimeout ticks passes.
1900  *  Otherwise returns the value from MsgWaitForMultipleObjectsEx when a
1901  *  message is available.
1902  */
1903 DWORD WINAPI SHWaitForSendMessageThread(HANDLE hand, DWORD dwTimeout)
1904 {
1905   DWORD dwEndTicks = GetTickCount() + dwTimeout;
1906   DWORD dwRet;
1907
1908   while ((dwRet = MsgWaitForMultipleObjectsEx(1, &hand, dwTimeout, QS_SENDMESSAGE, 0)) == 1)
1909   {
1910     MSG msg;
1911
1912     PeekMessageW(&msg, NULL, 0, 0, PM_NOREMOVE);
1913
1914     if (dwTimeout != INFINITE)
1915     {
1916         if ((int)(dwTimeout = dwEndTicks - GetTickCount()) <= 0)
1917             return WAIT_TIMEOUT;
1918     }
1919   }
1920
1921   return dwRet;
1922 }
1923
1924 /*************************************************************************
1925  *      @       [SHLWAPI.195]
1926  *
1927  * Determine if a shell folder can be expanded.
1928  *
1929  * PARAMS
1930  *  lpFolder [I] Parent folder containing the object to test.
1931  *  pidl     [I] Id of the object to test.
1932  *
1933  * RETURNS
1934  *  Success: S_OK, if the object is expandable, S_FALSE otherwise.
1935  *  Failure: E_INVALIDARG, if any argument is invalid.
1936  *
1937  * NOTES
1938  *  If the object to be tested does not expose the IQueryInfo() interface it
1939  *  will not be identified as an expandable folder.
1940  */
1941 HRESULT WINAPI SHIsExpandableFolder(LPSHELLFOLDER lpFolder, LPCITEMIDLIST pidl)
1942 {
1943   HRESULT hRet = E_INVALIDARG;
1944   IQueryInfo *lpInfo;
1945
1946   if (lpFolder && pidl)
1947   {
1948     hRet = IShellFolder_GetUIObjectOf(lpFolder, NULL, 1, &pidl, &IID_IQueryInfo,
1949                                       NULL, (void**)&lpInfo);
1950     if (FAILED(hRet))
1951       hRet = S_FALSE; /* Doesn't expose IQueryInfo */
1952     else
1953     {
1954       DWORD dwFlags = 0;
1955
1956       /* MSDN states of IQueryInfo_GetInfoFlags() that "This method is not
1957        * currently used". Really? You wouldn't be holding out on me would you?
1958        */
1959       hRet = IQueryInfo_GetInfoFlags(lpInfo, &dwFlags);
1960
1961       if (SUCCEEDED(hRet))
1962       {
1963         /* 0x2 is an undocumented flag apparently indicating expandability */
1964         hRet = dwFlags & 0x2 ? S_OK : S_FALSE;
1965       }
1966
1967       IQueryInfo_Release(lpInfo);
1968     }
1969   }
1970   return hRet;
1971 }
1972
1973 /*************************************************************************
1974  *      @       [SHLWAPI.197]
1975  *
1976  * Blank out a region of text by drawing the background only.
1977  *
1978  * PARAMS
1979  *  hDC   [I] Device context to draw in
1980  *  pRect [I] Area to draw in
1981  *  cRef  [I] Color to draw in
1982  *
1983  * RETURNS
1984  *  Nothing.
1985  */
1986 DWORD WINAPI SHFillRectClr(HDC hDC, LPCRECT pRect, COLORREF cRef)
1987 {
1988     COLORREF cOldColor = SetBkColor(hDC, cRef);
1989     ExtTextOutA(hDC, 0, 0, ETO_OPAQUE, pRect, 0, 0, 0);
1990     SetBkColor(hDC, cOldColor);
1991     return 0;
1992 }
1993
1994 /*************************************************************************
1995  *      @       [SHLWAPI.198]
1996  *
1997  * Return the value associated with a key in a map.
1998  *
1999  * PARAMS
2000  *  lpKeys   [I] A list of keys of length iLen
2001  *  lpValues [I] A list of values associated with lpKeys, of length iLen
2002  *  iLen     [I] Length of both lpKeys and lpValues
2003  *  iKey     [I] The key value to look up in lpKeys
2004  *
2005  * RETURNS
2006  *  The value in lpValues associated with iKey, or -1 if iKey is not
2007  *  found in lpKeys.
2008  *
2009  * NOTES
2010  *  - If two elements in the map share the same key, this function returns
2011  *    the value closest to the start of the map
2012  *  - The native version of this function crashes if lpKeys or lpValues is NULL.
2013  */
2014 int WINAPI SHSearchMapInt(const int *lpKeys, const int *lpValues, int iLen, int iKey)
2015 {
2016   if (lpKeys && lpValues)
2017   {
2018     int i = 0;
2019
2020     while (i < iLen)
2021     {
2022       if (lpKeys[i] == iKey)
2023         return lpValues[i]; /* Found */
2024       i++;
2025     }
2026   }
2027   return -1; /* Not found */
2028 }
2029
2030
2031 /*************************************************************************
2032  *      @       [SHLWAPI.199]
2033  *
2034  * Copy an interface pointer
2035  *
2036  * PARAMS
2037  *   lppDest   [O] Destination for copy
2038  *   lpUnknown [I] Source for copy
2039  *
2040  * RETURNS
2041  *  Nothing.
2042  */
2043 VOID WINAPI IUnknown_Set(IUnknown **lppDest, IUnknown *lpUnknown)
2044 {
2045   TRACE("(%p,%p)\n", lppDest, lpUnknown);
2046
2047   if (lppDest)
2048     IUnknown_AtomicRelease(lppDest); /* Release existing interface */
2049
2050   if (lpUnknown)
2051   {
2052     /* Copy */
2053     IUnknown_AddRef(lpUnknown);
2054     *lppDest = lpUnknown;
2055   }
2056 }
2057
2058 /*************************************************************************
2059  *      @       [SHLWAPI.200]
2060  *
2061  */
2062 HRESULT WINAPI MayQSForward(IUnknown* lpUnknown, PVOID lpReserved,
2063                             REFGUID riidCmdGrp, ULONG cCmds,
2064                             OLECMD *prgCmds, OLECMDTEXT* pCmdText)
2065 {
2066   FIXME("(%p,%p,%p,%d,%p,%p) - stub\n",
2067         lpUnknown, lpReserved, riidCmdGrp, cCmds, prgCmds, pCmdText);
2068
2069   /* FIXME: Calls IsQSForward & IUnknown_QueryStatus */
2070   return DRAGDROP_E_NOTREGISTERED;
2071 }
2072
2073 /*************************************************************************
2074  *      @       [SHLWAPI.201]
2075  *
2076  */
2077 HRESULT WINAPI MayExecForward(IUnknown* lpUnknown, INT iUnk, REFGUID pguidCmdGroup,
2078                            DWORD nCmdID, DWORD nCmdexecopt, VARIANT* pvaIn,
2079                            VARIANT* pvaOut)
2080 {
2081   FIXME("(%p,%d,%p,%d,%d,%p,%p) - stub!\n", lpUnknown, iUnk, pguidCmdGroup,
2082         nCmdID, nCmdexecopt, pvaIn, pvaOut);
2083   return DRAGDROP_E_NOTREGISTERED;
2084 }
2085
2086 /*************************************************************************
2087  *      @       [SHLWAPI.202]
2088  *
2089  */
2090 HRESULT WINAPI IsQSForward(REFGUID pguidCmdGroup,ULONG cCmds, OLECMD *prgCmds)
2091 {
2092   FIXME("(%p,%d,%p) - stub!\n", pguidCmdGroup, cCmds, prgCmds);
2093   return DRAGDROP_E_NOTREGISTERED;
2094 }
2095
2096 /*************************************************************************
2097  * @    [SHLWAPI.204]
2098  *
2099  * Determine if a window is not a child of another window.
2100  *
2101  * PARAMS
2102  * hParent [I] Suspected parent window
2103  * hChild  [I] Suspected child window
2104  *
2105  * RETURNS
2106  * TRUE:  If hChild is a child window of hParent
2107  * FALSE: If hChild is not a child window of hParent, or they are equal
2108  */
2109 BOOL WINAPI SHIsChildOrSelf(HWND hParent, HWND hChild)
2110 {
2111   TRACE("(%p,%p)\n", hParent, hChild);
2112
2113   if (!hParent || !hChild)
2114     return TRUE;
2115   else if(hParent == hChild)
2116     return FALSE;
2117   return !IsChild(hParent, hChild);
2118 }
2119
2120 /*************************************************************************
2121  *    FDSA functions.  Manage a dynamic array of fixed size memory blocks.
2122  */
2123
2124 typedef struct
2125 {
2126     DWORD num_items;       /* Number of elements inserted */
2127     void *mem;             /* Ptr to array */
2128     DWORD blocks_alloced;  /* Number of elements allocated */
2129     BYTE inc;              /* Number of elements to grow by when we need to expand */
2130     BYTE block_size;       /* Size in bytes of an element */
2131     BYTE flags;            /* Flags */
2132 } FDSA_info;
2133
2134 #define FDSA_FLAG_INTERNAL_ALLOC 0x01 /* When set we have allocated mem internally */
2135
2136 /*************************************************************************
2137  *      @       [SHLWAPI.208]
2138  *
2139  * Initialize an FDSA array.
2140  */
2141 BOOL WINAPI FDSA_Initialize(DWORD block_size, DWORD inc, FDSA_info *info, void *mem,
2142                             DWORD init_blocks)
2143 {
2144     TRACE("(0x%08x 0x%08x %p %p 0x%08x)\n", block_size, inc, info, mem, init_blocks);
2145
2146     if(inc == 0)
2147         inc = 1;
2148
2149     if(mem)
2150         memset(mem, 0, block_size * init_blocks);
2151     
2152     info->num_items = 0;
2153     info->inc = inc;
2154     info->mem = mem;
2155     info->blocks_alloced = init_blocks;
2156     info->block_size = block_size;
2157     info->flags = 0;
2158
2159     return TRUE;
2160 }
2161
2162 /*************************************************************************
2163  *      @       [SHLWAPI.209]
2164  *
2165  * Destroy an FDSA array
2166  */
2167 BOOL WINAPI FDSA_Destroy(FDSA_info *info)
2168 {
2169     TRACE("(%p)\n", info);
2170
2171     if(info->flags & FDSA_FLAG_INTERNAL_ALLOC)
2172     {
2173         HeapFree(GetProcessHeap(), 0, info->mem);
2174         return FALSE;
2175     }
2176
2177     return TRUE;
2178 }
2179
2180 /*************************************************************************
2181  *      @       [SHLWAPI.210]
2182  *
2183  * Insert element into an FDSA array
2184  */
2185 DWORD WINAPI FDSA_InsertItem(FDSA_info *info, DWORD where, const void *block)
2186 {
2187     TRACE("(%p 0x%08x %p)\n", info, where, block);
2188     if(where > info->num_items)
2189         where = info->num_items;
2190
2191     if(info->num_items >= info->blocks_alloced)
2192     {
2193         DWORD size = (info->blocks_alloced + info->inc) * info->block_size;
2194         if(info->flags & 0x1)
2195             info->mem = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, info->mem, size);
2196         else
2197         {
2198             void *old_mem = info->mem;
2199             info->mem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2200             memcpy(info->mem, old_mem, info->blocks_alloced * info->block_size);
2201         }
2202         info->blocks_alloced += info->inc;
2203         info->flags |= 0x1;
2204     }
2205
2206     if(where < info->num_items)
2207     {
2208         memmove((char*)info->mem + (where + 1) * info->block_size,
2209                 (char*)info->mem + where * info->block_size,
2210                 (info->num_items - where) * info->block_size);
2211     }
2212     memcpy((char*)info->mem + where * info->block_size, block, info->block_size);
2213
2214     info->num_items++;
2215     return where;
2216 }
2217
2218 /*************************************************************************
2219  *      @       [SHLWAPI.211]
2220  *
2221  * Delete an element from an FDSA array.
2222  */
2223 BOOL WINAPI FDSA_DeleteItem(FDSA_info *info, DWORD where)
2224 {
2225     TRACE("(%p 0x%08x)\n", info, where);
2226
2227     if(where >= info->num_items)
2228         return FALSE;
2229
2230     if(where < info->num_items - 1)
2231     {
2232         memmove((char*)info->mem + where * info->block_size,
2233                 (char*)info->mem + (where + 1) * info->block_size,
2234                 (info->num_items - where - 1) * info->block_size);
2235     }
2236     memset((char*)info->mem + (info->num_items - 1) * info->block_size,
2237            0, info->block_size);
2238     info->num_items--;
2239     return TRUE;
2240 }
2241
2242
2243 typedef struct {
2244     REFIID   refid;
2245     DWORD    indx;
2246 } IFACE_INDEX_TBL;
2247
2248 /*************************************************************************
2249  *      @       [SHLWAPI.219]
2250  *
2251  * Call IUnknown_QueryInterface() on a table of objects.
2252  *
2253  * RETURNS
2254  *  Success: S_OK.
2255  *  Failure: E_POINTER or E_NOINTERFACE.
2256  */
2257 HRESULT WINAPI QISearch(
2258         LPVOID w,           /* [in]   Table of interfaces */
2259         IFACE_INDEX_TBL *x, /* [in]   Array of REFIIDs and indexes into the table */
2260         REFIID riid,        /* [in]   REFIID to get interface for */
2261         LPVOID *ppv)          /* [out]  Destination for interface pointer */
2262 {
2263         HRESULT ret;
2264         IUnknown *a_vtbl;
2265         IFACE_INDEX_TBL *xmove;
2266
2267         TRACE("(%p %p %s %p)\n", w,x,debugstr_guid(riid),ppv);
2268         if (ppv) {
2269             xmove = x;
2270             while (xmove->refid) {
2271                 TRACE("trying (indx %d) %s\n", xmove->indx, debugstr_guid(xmove->refid));
2272                 if (IsEqualIID(riid, xmove->refid)) {
2273                     a_vtbl = (IUnknown*)(xmove->indx + (LPBYTE)w);
2274                     TRACE("matched, returning (%p)\n", a_vtbl);
2275                     *ppv = a_vtbl;
2276                     IUnknown_AddRef(a_vtbl);
2277                     return S_OK;
2278                 }
2279                 xmove++;
2280             }
2281
2282             if (IsEqualIID(riid, &IID_IUnknown)) {
2283                 a_vtbl = (IUnknown*)(x->indx + (LPBYTE)w);
2284                 TRACE("returning first for IUnknown (%p)\n", a_vtbl);
2285                 *ppv = a_vtbl;
2286                 IUnknown_AddRef(a_vtbl);
2287                 return S_OK;
2288             }
2289             *ppv = 0;
2290             ret = E_NOINTERFACE;
2291         } else
2292             ret = E_POINTER;
2293
2294         TRACE("-- 0x%08x\n", ret);
2295         return ret;
2296 }
2297
2298 /*************************************************************************
2299  * @ [SHLWAPI.220]
2300  *
2301  * Set the Font for a window and the "PropDlgFont" property of the parent window.
2302  *
2303  * PARAMS
2304  *  hWnd [I] Parent Window to set the property
2305  *  id   [I] Index of child Window to set the Font
2306  *
2307  * RETURNS
2308  *  Success: S_OK
2309  *
2310  */
2311 HRESULT WINAPI SHSetDefaultDialogFont(HWND hWnd, INT id)
2312 {
2313     FIXME("(%p, %d) stub\n", hWnd, id);
2314     return S_OK;
2315 }
2316
2317 /*************************************************************************
2318  *      @       [SHLWAPI.221]
2319  *
2320  * Remove the "PropDlgFont" property from a window.
2321  *
2322  * PARAMS
2323  *  hWnd [I] Window to remove the property from
2324  *
2325  * RETURNS
2326  *  A handle to the removed property, or NULL if it did not exist.
2327  */
2328 HANDLE WINAPI SHRemoveDefaultDialogFont(HWND hWnd)
2329 {
2330   HANDLE hProp;
2331
2332   TRACE("(%p)\n", hWnd);
2333
2334   hProp = GetPropA(hWnd, "PropDlgFont");
2335
2336   if(hProp)
2337   {
2338     DeleteObject(hProp);
2339     hProp = RemovePropA(hWnd, "PropDlgFont");
2340   }
2341   return hProp;
2342 }
2343
2344 /*************************************************************************
2345  *      @       [SHLWAPI.236]
2346  *
2347  * Load the in-process server of a given GUID.
2348  *
2349  * PARAMS
2350  *  refiid [I] GUID of the server to load.
2351  *
2352  * RETURNS
2353  *  Success: A handle to the loaded server dll.
2354  *  Failure: A NULL handle.
2355  */
2356 HMODULE WINAPI SHPinDllOfCLSID(REFIID refiid)
2357 {
2358     HKEY newkey;
2359     DWORD type, count;
2360     CHAR value[MAX_PATH], string[MAX_PATH];
2361
2362     strcpy(string, "CLSID\\");
2363     SHStringFromGUIDA(refiid, string + 6, sizeof(string)/sizeof(char) - 6);
2364     strcat(string, "\\InProcServer32");
2365
2366     count = MAX_PATH;
2367     RegOpenKeyExA(HKEY_CLASSES_ROOT, string, 0, 1, &newkey);
2368     RegQueryValueExA(newkey, 0, 0, &type, (PBYTE)value, &count);
2369     RegCloseKey(newkey);
2370     return LoadLibraryExA(value, 0, 0);
2371 }
2372
2373 /*************************************************************************
2374  *      @       [SHLWAPI.237]
2375  *
2376  * Unicode version of SHLWAPI_183.
2377  */
2378 DWORD WINAPI SHRegisterClassW(WNDCLASSW * lpWndClass)
2379 {
2380         WNDCLASSW WndClass;
2381
2382         TRACE("(%p %s)\n",lpWndClass->hInstance, debugstr_w(lpWndClass->lpszClassName));
2383
2384         if (GetClassInfoW(lpWndClass->hInstance, lpWndClass->lpszClassName, &WndClass))
2385                 return TRUE;
2386         return RegisterClassW(lpWndClass);
2387 }
2388
2389 /*************************************************************************
2390  *      @       [SHLWAPI.238]
2391  *
2392  * Unregister a list of classes.
2393  *
2394  * PARAMS
2395  *  hInst      [I] Application instance that registered the classes
2396  *  lppClasses [I] List of class names
2397  *  iCount     [I] Number of names in lppClasses
2398  *
2399  * RETURNS
2400  *  Nothing.
2401  */
2402 void WINAPI SHUnregisterClassesA(HINSTANCE hInst, LPCSTR *lppClasses, INT iCount)
2403 {
2404   WNDCLASSA WndClass;
2405
2406   TRACE("(%p,%p,%d)\n", hInst, lppClasses, iCount);
2407
2408   while (iCount > 0)
2409   {
2410     if (GetClassInfoA(hInst, *lppClasses, &WndClass))
2411       UnregisterClassA(*lppClasses, hInst);
2412     lppClasses++;
2413     iCount--;
2414   }
2415 }
2416
2417 /*************************************************************************
2418  *      @       [SHLWAPI.239]
2419  *
2420  * Unicode version of SHUnregisterClassesA.
2421  */
2422 void WINAPI SHUnregisterClassesW(HINSTANCE hInst, LPCWSTR *lppClasses, INT iCount)
2423 {
2424   WNDCLASSW WndClass;
2425
2426   TRACE("(%p,%p,%d)\n", hInst, lppClasses, iCount);
2427
2428   while (iCount > 0)
2429   {
2430     if (GetClassInfoW(hInst, *lppClasses, &WndClass))
2431       UnregisterClassW(*lppClasses, hInst);
2432     lppClasses++;
2433     iCount--;
2434   }
2435 }
2436
2437 /*************************************************************************
2438  *      @       [SHLWAPI.240]
2439  *
2440  * Call The correct (Ascii/Unicode) default window procedure for a window.
2441  *
2442  * PARAMS
2443  *  hWnd     [I] Window to call the default procedure for
2444  *  uMessage [I] Message ID
2445  *  wParam   [I] WPARAM of message
2446  *  lParam   [I] LPARAM of message
2447  *
2448  * RETURNS
2449  *  The result of calling DefWindowProcA() or DefWindowProcW().
2450  */
2451 LRESULT CALLBACK SHDefWindowProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
2452 {
2453         if (IsWindowUnicode(hWnd))
2454                 return DefWindowProcW(hWnd, uMessage, wParam, lParam);
2455         return DefWindowProcA(hWnd, uMessage, wParam, lParam);
2456 }
2457
2458 /*************************************************************************
2459  *      @       [SHLWAPI.256]
2460  */
2461 HRESULT WINAPI IUnknown_GetSite(LPUNKNOWN lpUnknown, REFIID iid, PVOID *lppSite)
2462 {
2463   HRESULT hRet = E_INVALIDARG;
2464   LPOBJECTWITHSITE lpSite = NULL;
2465
2466   TRACE("(%p,%s,%p)\n", lpUnknown, debugstr_guid(iid), lppSite);
2467
2468   if (lpUnknown && iid && lppSite)
2469   {
2470     hRet = IUnknown_QueryInterface(lpUnknown, &IID_IObjectWithSite,
2471                                    (void**)&lpSite);
2472     if (SUCCEEDED(hRet) && lpSite)
2473     {
2474       hRet = IObjectWithSite_GetSite(lpSite, iid, lppSite);
2475       IObjectWithSite_Release(lpSite);
2476     }
2477   }
2478   return hRet;
2479 }
2480
2481 /*************************************************************************
2482  *      @       [SHLWAPI.257]
2483  *
2484  * Create a worker window using CreateWindowExA().
2485  *
2486  * PARAMS
2487  *  wndProc    [I] Window procedure
2488  *  hWndParent [I] Parent window
2489  *  dwExStyle  [I] Extra style flags
2490  *  dwStyle    [I] Style flags
2491  *  hMenu      [I] Window menu
2492  *  z          [I] Unknown
2493  *
2494  * RETURNS
2495  *  Success: The window handle of the newly created window.
2496  *  Failure: 0.
2497  */
2498 HWND WINAPI SHCreateWorkerWindowA(LONG wndProc, HWND hWndParent, DWORD dwExStyle,
2499                         DWORD dwStyle, HMENU hMenu, LONG z)
2500 {
2501   static const char szClass[] = "WorkerA";
2502   WNDCLASSA wc;
2503   HWND hWnd;
2504
2505   TRACE("(0x%08x,%p,0x%08x,0x%08x,%p,0x%08x)\n",
2506          wndProc, hWndParent, dwExStyle, dwStyle, hMenu, z);
2507
2508   /* Create Window class */
2509   wc.style         = 0;
2510   wc.lpfnWndProc   = DefWindowProcA;
2511   wc.cbClsExtra    = 0;
2512   wc.cbWndExtra    = 4;
2513   wc.hInstance     = shlwapi_hInstance;
2514   wc.hIcon         = NULL;
2515   wc.hCursor       = LoadCursorA(NULL, (LPSTR)IDC_ARROW);
2516   wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
2517   wc.lpszMenuName  = NULL;
2518   wc.lpszClassName = szClass;
2519
2520   SHRegisterClassA(&wc); /* Register class */
2521
2522   /* FIXME: Set extra bits in dwExStyle */
2523
2524   hWnd = CreateWindowExA(dwExStyle, szClass, 0, dwStyle, 0, 0, 0, 0,
2525                          hWndParent, hMenu, shlwapi_hInstance, 0);
2526   if (hWnd)
2527   {
2528     SetWindowLongPtrW(hWnd, DWLP_MSGRESULT, z);
2529
2530     if (wndProc)
2531       SetWindowLongPtrA(hWnd, GWLP_WNDPROC, wndProc);
2532   }
2533   return hWnd;
2534 }
2535
2536 typedef struct tagPOLICYDATA
2537 {
2538   DWORD policy;        /* flags value passed to SHRestricted */
2539   LPCWSTR appstr;      /* application str such as "Explorer" */
2540   LPCWSTR keystr;      /* name of the actual registry key / policy */
2541 } POLICYDATA, *LPPOLICYDATA;
2542
2543 #define SHELL_NO_POLICY 0xffffffff
2544
2545 /* default shell policy registry key */
2546 static const WCHAR strRegistryPolicyW[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o',
2547                                       's','o','f','t','\\','W','i','n','d','o','w','s','\\',
2548                                       'C','u','r','r','e','n','t','V','e','r','s','i','o','n',
2549                                       '\\','P','o','l','i','c','i','e','s',0};
2550
2551 /*************************************************************************
2552  * @                          [SHLWAPI.271]
2553  *
2554  * Retrieve a policy value from the registry.
2555  *
2556  * PARAMS
2557  *  lpSubKey   [I]   registry key name
2558  *  lpSubName  [I]   subname of registry key
2559  *  lpValue    [I]   value name of registry value
2560  *
2561  * RETURNS
2562  *  the value associated with the registry key or 0 if not found
2563  */
2564 DWORD WINAPI SHGetRestriction(LPCWSTR lpSubKey, LPCWSTR lpSubName, LPCWSTR lpValue)
2565 {
2566         DWORD retval, datsize = sizeof(retval);
2567         HKEY hKey;
2568
2569         if (!lpSubKey)
2570           lpSubKey = strRegistryPolicyW;
2571
2572         retval = RegOpenKeyW(HKEY_LOCAL_MACHINE, lpSubKey, &hKey);
2573     if (retval != ERROR_SUCCESS)
2574           retval = RegOpenKeyW(HKEY_CURRENT_USER, lpSubKey, &hKey);
2575         if (retval != ERROR_SUCCESS)
2576           return 0;
2577
2578         SHGetValueW(hKey, lpSubName, lpValue, NULL, &retval, &datsize);
2579         RegCloseKey(hKey);
2580         return retval;
2581 }
2582
2583 /*************************************************************************
2584  * @                         [SHLWAPI.266]
2585  *
2586  * Helper function to retrieve the possibly cached value for a specific policy
2587  *
2588  * PARAMS
2589  *  policy     [I]   The policy to look for
2590  *  initial    [I]   Main registry key to open, if NULL use default
2591  *  polTable   [I]   Table of known policies, 0 terminated
2592  *  polArr     [I]   Cache array of policy values
2593  *
2594  * RETURNS
2595  *  The retrieved policy value or 0 if not successful
2596  *
2597  * NOTES
2598  *  This function is used by the native SHRestricted function to search for the
2599  *  policy and cache it once retrieved. The current Wine implementation uses a
2600  *  different POLICYDATA structure and implements a similar algorithm adapted to
2601  *  that structure.
2602  */
2603 DWORD WINAPI SHRestrictionLookup(
2604         DWORD policy,
2605         LPCWSTR initial,
2606         LPPOLICYDATA polTable,
2607         LPDWORD polArr)
2608 {
2609         TRACE("(0x%08x %s %p %p)\n", policy, debugstr_w(initial), polTable, polArr);
2610
2611         if (!polTable || !polArr)
2612           return 0;
2613
2614         for (;polTable->policy; polTable++, polArr++)
2615         {
2616           if (policy == polTable->policy)
2617           {
2618             /* we have a known policy */
2619
2620             /* check if this policy has been cached */
2621                 if (*polArr == SHELL_NO_POLICY)
2622               *polArr = SHGetRestriction(initial, polTable->appstr, polTable->keystr);
2623             return *polArr;
2624           }
2625         }
2626         /* we don't know this policy, return 0 */
2627         TRACE("unknown policy: (%08x)\n", policy);
2628         return 0;
2629 }
2630
2631 /*************************************************************************
2632  *      @       [SHLWAPI.267]
2633  *
2634  * Get an interface from an object.
2635  *
2636  * RETURNS
2637  *  Success: S_OK. ppv contains the requested interface.
2638  *  Failure: An HRESULT error code.
2639  *
2640  * NOTES
2641  *   This QueryInterface asks the inner object for an interface. In case
2642  *   of aggregation this request would be forwarded by the inner to the
2643  *   outer object. This function asks the inner object directly for the
2644  *   interface circumventing the forwarding to the outer object.
2645  */
2646 HRESULT WINAPI SHWeakQueryInterface(
2647         IUnknown * pUnk,   /* [in] Outer object */
2648         IUnknown * pInner, /* [in] Inner object */
2649         IID * riid, /* [in] Interface GUID to query for */
2650         LPVOID* ppv) /* [out] Destination for queried interface */
2651 {
2652         HRESULT hret = E_NOINTERFACE;
2653         TRACE("(pUnk=%p pInner=%p\n\tIID:  %s %p)\n",pUnk,pInner,debugstr_guid(riid), ppv);
2654
2655         *ppv = NULL;
2656         if(pUnk && pInner) {
2657             hret = IUnknown_QueryInterface(pInner, riid, ppv);
2658             if (SUCCEEDED(hret)) IUnknown_Release(pUnk);
2659         }
2660         TRACE("-- 0x%08x\n", hret);
2661         return hret;
2662 }
2663
2664 /*************************************************************************
2665  *      @       [SHLWAPI.268]
2666  *
2667  * Move a reference from one interface to another.
2668  *
2669  * PARAMS
2670  *   lpDest     [O] Destination to receive the reference
2671  *   lppUnknown [O] Source to give up the reference to lpDest
2672  *
2673  * RETURNS
2674  *  Nothing.
2675  */
2676 VOID WINAPI SHWeakReleaseInterface(IUnknown *lpDest, IUnknown **lppUnknown)
2677 {
2678   TRACE("(%p,%p)\n", lpDest, lppUnknown);
2679
2680   if (*lppUnknown)
2681   {
2682     /* Copy Reference*/
2683     IUnknown_AddRef(lpDest);
2684     IUnknown_AtomicRelease(lppUnknown); /* Release existing interface */
2685   }
2686 }
2687
2688 /*************************************************************************
2689  *      @       [SHLWAPI.269]
2690  *
2691  * Convert an ASCII string of a CLSID into a CLSID.
2692  *
2693  * PARAMS
2694  *  idstr [I] String representing a CLSID in registry format
2695  *  id    [O] Destination for the converted CLSID
2696  *
2697  * RETURNS
2698  *  Success: TRUE. id contains the converted CLSID.
2699  *  Failure: FALSE.
2700  */
2701 BOOL WINAPI GUIDFromStringA(LPCSTR idstr, CLSID *id)
2702 {
2703   WCHAR wClsid[40];
2704   MultiByteToWideChar(CP_ACP, 0, idstr, -1, wClsid, sizeof(wClsid)/sizeof(WCHAR));
2705   return SUCCEEDED(CLSIDFromString(wClsid, id));
2706 }
2707
2708 /*************************************************************************
2709  *      @       [SHLWAPI.270]
2710  *
2711  * Unicode version of GUIDFromStringA.
2712  */
2713 BOOL WINAPI GUIDFromStringW(LPCWSTR idstr, CLSID *id)
2714 {
2715     return SUCCEEDED(CLSIDFromString((LPOLESTR)idstr, id));
2716 }
2717
2718 /*************************************************************************
2719  *      @       [SHLWAPI.276]
2720  *
2721  * Determine if the browser is integrated into the shell, and set a registry
2722  * key accordingly.
2723  *
2724  * PARAMS
2725  *  None.
2726  *
2727  * RETURNS
2728  *  1, If the browser is not integrated.
2729  *  2, If the browser is integrated.
2730  *
2731  * NOTES
2732  *  The key "HKLM\Software\Microsoft\Internet Explorer\IntegratedBrowser" is
2733  *  either set to TRUE, or removed depending on whether the browser is deemed
2734  *  to be integrated.
2735  */
2736 DWORD WINAPI WhichPlatform(void)
2737 {
2738   static const char szIntegratedBrowser[] = "IntegratedBrowser";
2739   static DWORD dwState = 0;
2740   HKEY hKey;
2741   DWORD dwRet, dwData, dwSize;
2742   HMODULE hshell32;
2743
2744   if (dwState)
2745     return dwState;
2746
2747   /* If shell32 exports DllGetVersion(), the browser is integrated */
2748   dwState = 1;
2749   hshell32 = LoadLibraryA("shell32.dll");
2750   if (hshell32)
2751   {
2752     FARPROC pDllGetVersion;
2753     pDllGetVersion = GetProcAddress(hshell32, "DllGetVersion");
2754     dwState = pDllGetVersion ? 2 : 1;
2755     FreeLibrary(hshell32);
2756   }
2757
2758   /* Set or delete the key accordingly */
2759   dwRet = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
2760                         "Software\\Microsoft\\Internet Explorer", 0,
2761                          KEY_ALL_ACCESS, &hKey);
2762   if (!dwRet)
2763   {
2764     dwRet = RegQueryValueExA(hKey, szIntegratedBrowser, 0, 0,
2765                              (LPBYTE)&dwData, &dwSize);
2766
2767     if (!dwRet && dwState == 1)
2768     {
2769       /* Value exists but browser is not integrated */
2770       RegDeleteValueA(hKey, szIntegratedBrowser);
2771     }
2772     else if (dwRet && dwState == 2)
2773     {
2774       /* Browser is integrated but value does not exist */
2775       dwData = TRUE;
2776       RegSetValueExA(hKey, szIntegratedBrowser, 0, REG_DWORD,
2777                      (LPBYTE)&dwData, sizeof(dwData));
2778     }
2779     RegCloseKey(hKey);
2780   }
2781   return dwState;
2782 }
2783
2784 /*************************************************************************
2785  *      @       [SHLWAPI.278]
2786  *
2787  * Unicode version of SHCreateWorkerWindowA.
2788  */
2789 HWND WINAPI SHCreateWorkerWindowW(LONG wndProc, HWND hWndParent, DWORD dwExStyle,
2790                         DWORD dwStyle, HMENU hMenu, LONG z)
2791 {
2792   static const WCHAR szClass[] = { 'W', 'o', 'r', 'k', 'e', 'r', 'W', '\0' };
2793   WNDCLASSW wc;
2794   HWND hWnd;
2795
2796   TRACE("(0x%08x,%p,0x%08x,0x%08x,%p,0x%08x)\n",
2797          wndProc, hWndParent, dwExStyle, dwStyle, hMenu, z);
2798
2799   /* If our OS is natively ASCII, use the ASCII version */
2800   if (!(GetVersion() & 0x80000000))  /* NT */
2801     return SHCreateWorkerWindowA(wndProc, hWndParent, dwExStyle, dwStyle, hMenu, z);
2802
2803   /* Create Window class */
2804   wc.style         = 0;
2805   wc.lpfnWndProc   = DefWindowProcW;
2806   wc.cbClsExtra    = 0;
2807   wc.cbWndExtra    = 4;
2808   wc.hInstance     = shlwapi_hInstance;
2809   wc.hIcon         = NULL;
2810   wc.hCursor       = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
2811   wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
2812   wc.lpszMenuName  = NULL;
2813   wc.lpszClassName = szClass;
2814
2815   SHRegisterClassW(&wc); /* Register class */
2816
2817   /* FIXME: Set extra bits in dwExStyle */
2818
2819   hWnd = CreateWindowExW(dwExStyle, szClass, 0, dwStyle, 0, 0, 0, 0,
2820                          hWndParent, hMenu, shlwapi_hInstance, 0);
2821   if (hWnd)
2822   {
2823     SetWindowLongPtrW(hWnd, DWLP_MSGRESULT, z);
2824
2825     if (wndProc)
2826       SetWindowLongPtrW(hWnd, GWLP_WNDPROC, wndProc);
2827   }
2828   return hWnd;
2829 }
2830
2831 /*************************************************************************
2832  *      @       [SHLWAPI.279]
2833  *
2834  * Get and show a context menu from a shell folder.
2835  *
2836  * PARAMS
2837  *  hWnd           [I] Window displaying the shell folder
2838  *  lpFolder       [I] IShellFolder interface
2839  *  lpApidl        [I] Id for the particular folder desired
2840  *
2841  * RETURNS
2842  *  Success: S_OK.
2843  *  Failure: An HRESULT error code indicating the error.
2844  */
2845 HRESULT WINAPI SHInvokeDefaultCommand(HWND hWnd, IShellFolder* lpFolder, LPCITEMIDLIST lpApidl)
2846 {
2847   return SHInvokeCommand(hWnd, lpFolder, lpApidl, FALSE);
2848 }
2849
2850 /*************************************************************************
2851  *      @       [SHLWAPI.281]
2852  *
2853  * _SHPackDispParamsV
2854  */
2855 HRESULT WINAPI SHPackDispParamsV(DISPPARAMS *params, VARIANTARG *args, UINT cnt, __ms_va_list valist)
2856 {
2857   VARIANTARG *iter;
2858
2859   TRACE("(%p %p %u ...)\n", params, args, cnt);
2860
2861   params->rgvarg = args;
2862   params->rgdispidNamedArgs = NULL;
2863   params->cArgs = cnt;
2864   params->cNamedArgs = 0;
2865
2866   iter = args+cnt;
2867
2868   while(iter-- > args) {
2869     V_VT(iter) = va_arg(valist, enum VARENUM);
2870
2871     TRACE("vt=%d\n", V_VT(iter));
2872
2873     if(V_VT(iter) & VT_BYREF) {
2874       V_BYREF(iter) = va_arg(valist, LPVOID);
2875     } else {
2876       switch(V_VT(iter)) {
2877       case VT_I4:
2878         V_I4(iter) = va_arg(valist, LONG);
2879         break;
2880       case VT_BSTR:
2881         V_BSTR(iter) = va_arg(valist, BSTR);
2882         break;
2883       case VT_DISPATCH:
2884         V_DISPATCH(iter) = va_arg(valist, IDispatch*);
2885         break;
2886       case VT_BOOL:
2887         V_BOOL(iter) = va_arg(valist, int);
2888         break;
2889       case VT_UNKNOWN:
2890         V_UNKNOWN(iter) = va_arg(valist, IUnknown*);
2891         break;
2892       default:
2893         V_VT(iter) = VT_I4;
2894         V_I4(iter) = va_arg(valist, LONG);
2895       }
2896     }
2897   }
2898
2899   return S_OK;
2900 }
2901
2902 /*************************************************************************
2903  *      @       [SHLWAPI.282]
2904  *
2905  * SHPackDispParams
2906  */
2907 HRESULT WINAPIV SHPackDispParams(DISPPARAMS *params, VARIANTARG *args, UINT cnt, ...)
2908 {
2909   __ms_va_list valist;
2910   HRESULT hres;
2911
2912   __ms_va_start(valist, cnt);
2913   hres = SHPackDispParamsV(params, args, cnt, valist);
2914   __ms_va_end(valist);
2915   return hres;
2916 }
2917
2918 /*************************************************************************
2919  *      SHLWAPI_InvokeByIID
2920  *
2921  *   This helper function calls IDispatch::Invoke for each sink
2922  * which implements given iid or IDispatch.
2923  *
2924  */
2925 static HRESULT SHLWAPI_InvokeByIID(
2926         IConnectionPoint* iCP,
2927         REFIID iid,
2928         DISPID dispId,
2929         DISPPARAMS* dispParams)
2930 {
2931   IEnumConnections *enumerator;
2932   CONNECTDATA rgcd;
2933   static DISPPARAMS empty = {NULL, NULL, 0, 0};
2934   DISPPARAMS* params = dispParams;
2935
2936   HRESULT result = IConnectionPoint_EnumConnections(iCP, &enumerator);
2937   if (FAILED(result))
2938     return result;
2939
2940   /* Invoke is never happening with an NULL dispParams */
2941   if (!params)
2942     params = &empty;
2943
2944   while(IEnumConnections_Next(enumerator, 1, &rgcd, NULL)==S_OK)
2945   {
2946     IDispatch *dispIface;
2947     if ((iid && SUCCEEDED(IUnknown_QueryInterface(rgcd.pUnk, iid, (LPVOID*)&dispIface))) ||
2948         SUCCEEDED(IUnknown_QueryInterface(rgcd.pUnk, &IID_IDispatch, (LPVOID*)&dispIface)))
2949     {
2950       IDispatch_Invoke(dispIface, dispId, &IID_NULL, 0, DISPATCH_METHOD, params, NULL, NULL, NULL);
2951       IDispatch_Release(dispIface);
2952     }
2953     IUnknown_Release(rgcd.pUnk);
2954   }
2955
2956   IEnumConnections_Release(enumerator);
2957
2958   return S_OK;
2959 }
2960
2961 /*************************************************************************
2962  *  IConnectionPoint_InvokeWithCancel   [SHLWAPI.283]
2963  */
2964 HRESULT WINAPI IConnectionPoint_InvokeWithCancel( IConnectionPoint* iCP,
2965                                                   DISPID dispId, DISPPARAMS* dispParams,
2966                                                   DWORD unknown1, DWORD unknown2 )
2967 {
2968     IID iid;
2969     HRESULT result;
2970
2971     FIXME("(%p)->(0x%x %p %x %x) partial stub\n", iCP, dispId, dispParams, unknown1, unknown2);
2972
2973     result = IConnectionPoint_GetConnectionInterface(iCP, &iid);
2974     if (SUCCEEDED(result))
2975         result = SHLWAPI_InvokeByIID(iCP, &iid, dispId, dispParams);
2976     else
2977         result = SHLWAPI_InvokeByIID(iCP, NULL, dispId, dispParams);
2978
2979     return result;
2980 }
2981
2982
2983 /*************************************************************************
2984  *      @       [SHLWAPI.284]
2985  *
2986  *  IConnectionPoint_SimpleInvoke
2987  */
2988 HRESULT WINAPI IConnectionPoint_SimpleInvoke(
2989         IConnectionPoint* iCP,
2990         DISPID dispId,
2991         DISPPARAMS* dispParams)
2992 {
2993   IID iid;
2994   HRESULT result;
2995
2996   TRACE("(%p)->(0x%x %p)\n",iCP,dispId,dispParams);
2997
2998   result = IConnectionPoint_GetConnectionInterface(iCP, &iid);
2999   if (SUCCEEDED(result))
3000     result = SHLWAPI_InvokeByIID(iCP, &iid, dispId, dispParams);
3001   else
3002     result = SHLWAPI_InvokeByIID(iCP, NULL, dispId, dispParams);
3003
3004   return result;
3005 }
3006
3007 /*************************************************************************
3008  *      @       [SHLWAPI.285]
3009  *
3010  * Notify an IConnectionPoint object of changes.
3011  *
3012  * PARAMS
3013  *  lpCP   [I] Object to notify
3014  *  dispID [I]
3015  *
3016  * RETURNS
3017  *  Success: S_OK.
3018  *  Failure: E_NOINTERFACE, if lpCP is NULL or does not support the
3019  *           IConnectionPoint interface.
3020  */
3021 HRESULT WINAPI IConnectionPoint_OnChanged(IConnectionPoint* lpCP, DISPID dispID)
3022 {
3023   IEnumConnections *lpEnum;
3024   HRESULT hRet = E_NOINTERFACE;
3025
3026   TRACE("(%p,0x%8X)\n", lpCP, dispID);
3027
3028   /* Get an enumerator for the connections */
3029   if (lpCP)
3030     hRet = IConnectionPoint_EnumConnections(lpCP, &lpEnum);
3031
3032   if (SUCCEEDED(hRet))
3033   {
3034     IPropertyNotifySink *lpSink;
3035     CONNECTDATA connData;
3036     ULONG ulFetched;
3037
3038     /* Call OnChanged() for every notify sink in the connection point */
3039     while (IEnumConnections_Next(lpEnum, 1, &connData, &ulFetched) == S_OK)
3040     {
3041       if (SUCCEEDED(IUnknown_QueryInterface(connData.pUnk, &IID_IPropertyNotifySink, (void**)&lpSink)) &&
3042           lpSink)
3043       {
3044         IPropertyNotifySink_OnChanged(lpSink, dispID);
3045         IPropertyNotifySink_Release(lpSink);
3046       }
3047       IUnknown_Release(connData.pUnk);
3048     }
3049
3050     IEnumConnections_Release(lpEnum);
3051   }
3052   return hRet;
3053 }
3054
3055 /*************************************************************************
3056  *      @       [SHLWAPI.286]
3057  *
3058  *  IUnknown_CPContainerInvokeParam
3059  */
3060 HRESULT WINAPIV IUnknown_CPContainerInvokeParam(
3061         IUnknown *container,
3062         REFIID riid,
3063         DISPID dispId,
3064         VARIANTARG* buffer,
3065         DWORD cParams, ...)
3066 {
3067   HRESULT result;
3068   IConnectionPoint *iCP;
3069   IConnectionPointContainer *iCPC;
3070   DISPPARAMS dispParams = {buffer, NULL, cParams, 0};
3071   __ms_va_list valist;
3072
3073   if (!container)
3074     return E_NOINTERFACE;
3075
3076   result = IUnknown_QueryInterface(container, &IID_IConnectionPointContainer,(LPVOID*) &iCPC);
3077   if (FAILED(result))
3078       return result;
3079
3080   result = IConnectionPointContainer_FindConnectionPoint(iCPC, riid, &iCP);
3081   IConnectionPointContainer_Release(iCPC);
3082   if(FAILED(result))
3083       return result;
3084
3085   __ms_va_start(valist, cParams);
3086   SHPackDispParamsV(&dispParams, buffer, cParams, valist);
3087   __ms_va_end(valist);
3088
3089   result = SHLWAPI_InvokeByIID(iCP, riid, dispId, &dispParams);
3090   IConnectionPoint_Release(iCP);
3091
3092   return result;
3093 }
3094
3095 /*************************************************************************
3096  *      @       [SHLWAPI.287]
3097  *
3098  * Notify an IConnectionPointContainer object of changes.
3099  *
3100  * PARAMS
3101  *  lpUnknown [I] Object to notify
3102  *  dispID    [I]
3103  *
3104  * RETURNS
3105  *  Success: S_OK.
3106  *  Failure: E_NOINTERFACE, if lpUnknown is NULL or does not support the
3107  *           IConnectionPointContainer interface.
3108  */
3109 HRESULT WINAPI IUnknown_CPContainerOnChanged(IUnknown *lpUnknown, DISPID dispID)
3110 {
3111   IConnectionPointContainer* lpCPC = NULL;
3112   HRESULT hRet = E_NOINTERFACE;
3113
3114   TRACE("(%p,0x%8X)\n", lpUnknown, dispID);
3115
3116   if (lpUnknown)
3117     hRet = IUnknown_QueryInterface(lpUnknown, &IID_IConnectionPointContainer, (void**)&lpCPC);
3118
3119   if (SUCCEEDED(hRet))
3120   {
3121     IConnectionPoint* lpCP;
3122
3123     hRet = IConnectionPointContainer_FindConnectionPoint(lpCPC, &IID_IPropertyNotifySink, &lpCP);
3124     IConnectionPointContainer_Release(lpCPC);
3125
3126     hRet = IConnectionPoint_OnChanged(lpCP, dispID);
3127     IConnectionPoint_Release(lpCP);
3128   }
3129   return hRet;
3130 }
3131
3132 /*************************************************************************
3133  *      @       [SHLWAPI.289]
3134  *
3135  * See PlaySoundW.
3136  */
3137 BOOL WINAPI PlaySoundWrapW(LPCWSTR pszSound, HMODULE hmod, DWORD fdwSound)
3138 {
3139     return PlaySoundW(pszSound, hmod, fdwSound);
3140 }
3141
3142 /*************************************************************************
3143  *      @       [SHLWAPI.294]
3144  */
3145 BOOL WINAPI SHGetIniStringW(LPCWSTR str1, LPCWSTR str2, LPWSTR pStr, DWORD some_len, LPCWSTR lpStr2)
3146 {
3147     FIXME("(%s,%s,%p,%08x,%s): stub!\n", debugstr_w(str1), debugstr_w(str2),
3148         pStr, some_len, debugstr_w(lpStr2));
3149     return TRUE;
3150 }
3151
3152 /*************************************************************************
3153  *      @       [SHLWAPI.295]
3154  *
3155  * Called by ICQ2000b install via SHDOCVW:
3156  * str1: "InternetShortcut"
3157  * x: some unknown pointer
3158  * str2: "http://free.aol.com/tryaolfree/index.adp?139269"
3159  * str3: "C:\\WINDOWS\\Desktop.new2\\Free AOL & Unlimited Internet.url"
3160  *
3161  * In short: this one maybe creates a desktop link :-)
3162  */
3163 BOOL WINAPI SHSetIniStringW(LPWSTR str1, LPVOID x, LPWSTR str2, LPWSTR str3)
3164 {
3165     FIXME("(%s, %p, %s, %s), stub.\n", debugstr_w(str1), x, debugstr_w(str2), debugstr_w(str3));
3166     return TRUE;
3167 }
3168
3169 /*************************************************************************
3170  *      @       [SHLWAPI.313]
3171  *
3172  * See SHGetFileInfoW.
3173  */
3174 DWORD WINAPI SHGetFileInfoWrapW(LPCWSTR path, DWORD dwFileAttributes,
3175                          SHFILEINFOW *psfi, UINT sizeofpsfi, UINT flags)
3176 {
3177     return SHGetFileInfoW(path, dwFileAttributes, psfi, sizeofpsfi, flags);
3178 }
3179
3180 /*************************************************************************
3181  *      @       [SHLWAPI.318]
3182  *
3183  * See DragQueryFileW.
3184  */
3185 UINT WINAPI DragQueryFileWrapW(HDROP hDrop, UINT lFile, LPWSTR lpszFile, UINT lLength)
3186 {
3187     return DragQueryFileW(hDrop, lFile, lpszFile, lLength);
3188 }
3189
3190 /*************************************************************************
3191  *      @       [SHLWAPI.333]
3192  *
3193  * See SHBrowseForFolderW.
3194  */
3195 LPITEMIDLIST WINAPI SHBrowseForFolderWrapW(LPBROWSEINFOW lpBi)
3196 {
3197     return SHBrowseForFolderW(lpBi);
3198 }
3199
3200 /*************************************************************************
3201  *      @       [SHLWAPI.334]
3202  *
3203  * See SHGetPathFromIDListW.
3204  */
3205 BOOL WINAPI SHGetPathFromIDListWrapW(LPCITEMIDLIST pidl,LPWSTR pszPath)
3206 {
3207     return SHGetPathFromIDListW(pidl, pszPath);
3208 }
3209
3210 /*************************************************************************
3211  *      @       [SHLWAPI.335]
3212  *
3213  * See ShellExecuteExW.
3214  */
3215 BOOL WINAPI ShellExecuteExWrapW(LPSHELLEXECUTEINFOW lpExecInfo)
3216 {
3217     return ShellExecuteExW(lpExecInfo);
3218 }
3219
3220 /*************************************************************************
3221  *      @       [SHLWAPI.336]
3222  *
3223  * See SHFileOperationW.
3224  */
3225 INT WINAPI SHFileOperationWrapW(LPSHFILEOPSTRUCTW lpFileOp)
3226 {
3227     return SHFileOperationW(lpFileOp);
3228 }
3229
3230 /*************************************************************************
3231  *      @       [SHLWAPI.342]
3232  *
3233  */
3234 PVOID WINAPI SHInterlockedCompareExchange( PVOID *dest, PVOID xchg, PVOID compare )
3235 {
3236     return InterlockedCompareExchangePointer( dest, xchg, compare );
3237 }
3238
3239 /*************************************************************************
3240  *      @       [SHLWAPI.350]
3241  *
3242  * See GetFileVersionInfoSizeW.
3243  */
3244 DWORD WINAPI GetFileVersionInfoSizeWrapW( LPCWSTR filename, LPDWORD handle )
3245 {
3246     return GetFileVersionInfoSizeW( filename, handle );
3247 }
3248
3249 /*************************************************************************
3250  *      @       [SHLWAPI.351]
3251  *
3252  * See GetFileVersionInfoW.
3253  */
3254 BOOL  WINAPI GetFileVersionInfoWrapW( LPCWSTR filename, DWORD handle,
3255                                       DWORD datasize, LPVOID data )
3256 {
3257     return GetFileVersionInfoW( filename, handle, datasize, data );
3258 }
3259
3260 /*************************************************************************
3261  *      @       [SHLWAPI.352]
3262  *
3263  * See VerQueryValueW.
3264  */
3265 WORD WINAPI VerQueryValueWrapW( LPVOID pBlock, LPCWSTR lpSubBlock,
3266                                 LPVOID *lplpBuffer, UINT *puLen )
3267 {
3268     return VerQueryValueW( pBlock, lpSubBlock, lplpBuffer, puLen );
3269 }
3270
3271 #define IsIface(type) SUCCEEDED((hRet = IUnknown_QueryInterface(lpUnknown, &IID_##type, (void**)&lpObj)))
3272 #define IShellBrowser_EnableModeless IShellBrowser_EnableModelessSB
3273 #define EnableModeless(type) type##_EnableModeless((type*)lpObj, bModeless)
3274
3275 /*************************************************************************
3276  *      @       [SHLWAPI.355]
3277  *
3278  * Change the modality of a shell object.
3279  *
3280  * PARAMS
3281  *  lpUnknown [I] Object to make modeless
3282  *  bModeless [I] TRUE=Make modeless, FALSE=Make modal
3283  *
3284  * RETURNS
3285  *  Success: S_OK. The modality lpUnknown is changed.
3286  *  Failure: An HRESULT error code indicating the error.
3287  *
3288  * NOTES
3289  *  lpUnknown must support the IOleInPlaceFrame interface, the
3290  *  IInternetSecurityMgrSite interface, the IShellBrowser interface
3291  *  the IDocHostUIHandler interface, or the IOleInPlaceActiveObject interface,
3292  *  or this call will fail.
3293  */
3294 HRESULT WINAPI IUnknown_EnableModeless(IUnknown *lpUnknown, BOOL bModeless)
3295 {
3296   IUnknown *lpObj;
3297   HRESULT hRet;
3298
3299   TRACE("(%p,%d)\n", lpUnknown, bModeless);
3300
3301   if (!lpUnknown)
3302     return E_FAIL;
3303
3304   if (IsIface(IOleInPlaceActiveObject))
3305     EnableModeless(IOleInPlaceActiveObject);
3306   else if (IsIface(IOleInPlaceFrame))
3307     EnableModeless(IOleInPlaceFrame);
3308   else if (IsIface(IShellBrowser))
3309     EnableModeless(IShellBrowser);
3310   else if (IsIface(IInternetSecurityMgrSite))
3311     EnableModeless(IInternetSecurityMgrSite);
3312   else if (IsIface(IDocHostUIHandler))
3313     EnableModeless(IDocHostUIHandler);
3314   else
3315     return hRet;
3316
3317   IUnknown_Release(lpObj);
3318   return S_OK;
3319 }
3320
3321 /*************************************************************************
3322  *      @       [SHLWAPI.357]
3323  *
3324  * See SHGetNewLinkInfoW.
3325  */
3326 BOOL WINAPI SHGetNewLinkInfoWrapW(LPCWSTR pszLinkTo, LPCWSTR pszDir, LPWSTR pszName,
3327                         BOOL *pfMustCopy, UINT uFlags)
3328 {
3329     return SHGetNewLinkInfoW(pszLinkTo, pszDir, pszName, pfMustCopy, uFlags);
3330 }
3331
3332 /*************************************************************************
3333  *      @       [SHLWAPI.358]
3334  *
3335  * See SHDefExtractIconW.
3336  */
3337 UINT WINAPI SHDefExtractIconWrapW(LPCWSTR pszIconFile, int iIndex, UINT uFlags, HICON* phiconLarge,
3338                          HICON* phiconSmall, UINT nIconSize)
3339 {
3340     return SHDefExtractIconW(pszIconFile, iIndex, uFlags, phiconLarge, phiconSmall, nIconSize);
3341 }
3342
3343 /*************************************************************************
3344  *      @       [SHLWAPI.363]
3345  *
3346  * Get and show a context menu from a shell folder.
3347  *
3348  * PARAMS
3349  *  hWnd           [I] Window displaying the shell folder
3350  *  lpFolder       [I] IShellFolder interface
3351  *  lpApidl        [I] Id for the particular folder desired
3352  *  bInvokeDefault [I] Whether to invoke the default menu item
3353  *
3354  * RETURNS
3355  *  Success: S_OK. If bInvokeDefault is TRUE, the default menu action was
3356  *           executed.
3357  *  Failure: An HRESULT error code indicating the error.
3358  */
3359 HRESULT WINAPI SHInvokeCommand(HWND hWnd, IShellFolder* lpFolder, LPCITEMIDLIST lpApidl, BOOL bInvokeDefault)
3360 {
3361   IContextMenu *iContext;
3362   HRESULT hRet = E_FAIL;
3363
3364   TRACE("(%p,%p,%p,%d)\n", hWnd, lpFolder, lpApidl, bInvokeDefault);
3365
3366   if (!lpFolder)
3367     return hRet;
3368
3369   /* Get the context menu from the shell folder */
3370   hRet = IShellFolder_GetUIObjectOf(lpFolder, hWnd, 1, &lpApidl,
3371                                     &IID_IContextMenu, 0, (void**)&iContext);
3372   if (SUCCEEDED(hRet))
3373   {
3374     HMENU hMenu;
3375     if ((hMenu = CreatePopupMenu()))
3376     {
3377       HRESULT hQuery;
3378       DWORD dwDefaultId = 0;
3379
3380       /* Add the context menu entries to the popup */
3381       hQuery = IContextMenu_QueryContextMenu(iContext, hMenu, 0, 1, 0x7FFF,
3382                                              bInvokeDefault ? CMF_NORMAL : CMF_DEFAULTONLY);
3383
3384       if (SUCCEEDED(hQuery))
3385       {
3386         if (bInvokeDefault &&
3387             (dwDefaultId = GetMenuDefaultItem(hMenu, 0, 0)) != 0xFFFFFFFF)
3388         {
3389           CMINVOKECOMMANDINFO cmIci;
3390           /* Invoke the default item */
3391           memset(&cmIci,0,sizeof(cmIci));
3392           cmIci.cbSize = sizeof(cmIci);
3393           cmIci.fMask = CMIC_MASK_ASYNCOK;
3394           cmIci.hwnd = hWnd;
3395           cmIci.lpVerb = MAKEINTRESOURCEA(dwDefaultId);
3396           cmIci.nShow = SW_SCROLLCHILDREN;
3397
3398           hRet = IContextMenu_InvokeCommand(iContext, &cmIci);
3399         }
3400       }
3401       DestroyMenu(hMenu);
3402     }
3403     IContextMenu_Release(iContext);
3404   }
3405   return hRet;
3406 }
3407
3408 /*************************************************************************
3409  *      @       [SHLWAPI.370]
3410  *
3411  * See ExtractIconW.
3412  */
3413 HICON WINAPI ExtractIconWrapW(HINSTANCE hInstance, LPCWSTR lpszExeFileName,
3414                          UINT nIconIndex)
3415 {
3416     return ExtractIconW(hInstance, lpszExeFileName, nIconIndex);
3417 }
3418
3419 /*************************************************************************
3420  *      @       [SHLWAPI.377]
3421  *
3422  * Load a library from the directory of a particular process.
3423  *
3424  * PARAMS
3425  *  new_mod        [I] Library name
3426  *  inst_hwnd      [I] Module whose directory is to be used
3427  *  dwCrossCodePage [I] Should be FALSE (currently ignored)
3428  *
3429  * RETURNS
3430  *  Success: A handle to the loaded module
3431  *  Failure: A NULL handle.
3432  */
3433 HMODULE WINAPI MLLoadLibraryA(LPCSTR new_mod, HMODULE inst_hwnd, DWORD dwCrossCodePage)
3434 {
3435   /* FIXME: Native appears to do DPA_Create and a DPA_InsertPtr for
3436    *        each call here.
3437    * FIXME: Native shows calls to:
3438    *  SHRegGetUSValue for "Software\Microsoft\Internet Explorer\International"
3439    *                      CheckVersion
3440    *  RegOpenKeyExA for "HKLM\Software\Microsoft\Internet Explorer"
3441    *  RegQueryValueExA for "LPKInstalled"
3442    *  RegCloseKey
3443    *  RegOpenKeyExA for "HKCU\Software\Microsoft\Internet Explorer\International"
3444    *  RegQueryValueExA for "ResourceLocale"
3445    *  RegCloseKey
3446    *  RegOpenKeyExA for "HKLM\Software\Microsoft\Active Setup\Installed Components\{guid}"
3447    *  RegQueryValueExA for "Locale"
3448    *  RegCloseKey
3449    *  and then tests the Locale ("en" for me).
3450    *     code below
3451    *  after the code then a DPA_Create (first time) and DPA_InsertPtr are done.
3452    */
3453     CHAR mod_path[2*MAX_PATH];
3454     LPSTR ptr;
3455     DWORD len;
3456
3457     FIXME("(%s,%p,%d) semi-stub!\n", debugstr_a(new_mod), inst_hwnd, dwCrossCodePage);
3458     len = GetModuleFileNameA(inst_hwnd, mod_path, sizeof(mod_path));
3459     if (!len || len >= sizeof(mod_path)) return NULL;
3460
3461     ptr = strrchr(mod_path, '\\');
3462     if (ptr) {
3463         strcpy(ptr+1, new_mod);
3464         TRACE("loading %s\n", debugstr_a(mod_path));
3465         return LoadLibraryA(mod_path);
3466     }
3467     return NULL;
3468 }
3469
3470 /*************************************************************************
3471  *      @       [SHLWAPI.378]
3472  *
3473  * Unicode version of MLLoadLibraryA.
3474  */
3475 HMODULE WINAPI MLLoadLibraryW(LPCWSTR new_mod, HMODULE inst_hwnd, DWORD dwCrossCodePage)
3476 {
3477     WCHAR mod_path[2*MAX_PATH];
3478     LPWSTR ptr;
3479     DWORD len;
3480
3481     FIXME("(%s,%p,%d) semi-stub!\n", debugstr_w(new_mod), inst_hwnd, dwCrossCodePage);
3482     len = GetModuleFileNameW(inst_hwnd, mod_path, sizeof(mod_path) / sizeof(WCHAR));
3483     if (!len || len >= sizeof(mod_path) / sizeof(WCHAR)) return NULL;
3484
3485     ptr = strrchrW(mod_path, '\\');
3486     if (ptr) {
3487         strcpyW(ptr+1, new_mod);
3488         TRACE("loading %s\n", debugstr_w(mod_path));
3489         return LoadLibraryW(mod_path);
3490     }
3491     return NULL;
3492 }
3493
3494 /*************************************************************************
3495  * ColorAdjustLuma      [SHLWAPI.@]
3496  *
3497  * Adjust the luminosity of a color
3498  *
3499  * PARAMS
3500  *  cRGB         [I] RGB value to convert
3501  *  dwLuma       [I] Luma adjustment
3502  *  bUnknown     [I] Unknown
3503  *
3504  * RETURNS
3505  *  The adjusted RGB color.
3506  */
3507 COLORREF WINAPI ColorAdjustLuma(COLORREF cRGB, int dwLuma, BOOL bUnknown)
3508 {
3509   TRACE("(0x%8x,%d,%d)\n", cRGB, dwLuma, bUnknown);
3510
3511   if (dwLuma)
3512   {
3513     WORD wH, wL, wS;
3514
3515     ColorRGBToHLS(cRGB, &wH, &wL, &wS);
3516
3517     FIXME("Ignoring luma adjustment\n");
3518
3519     /* FIXME: The adjustment is not linear */
3520
3521     cRGB = ColorHLSToRGB(wH, wL, wS);
3522   }
3523   return cRGB;
3524 }
3525
3526 /*************************************************************************
3527  *      @       [SHLWAPI.389]
3528  *
3529  * See GetSaveFileNameW.
3530  */
3531 BOOL WINAPI GetSaveFileNameWrapW(LPOPENFILENAMEW ofn)
3532 {
3533     return GetSaveFileNameW(ofn);
3534 }
3535
3536 /*************************************************************************
3537  *      @       [SHLWAPI.390]
3538  *
3539  * See WNetRestoreConnectionW.
3540  */
3541 DWORD WINAPI WNetRestoreConnectionWrapW(HWND hwndOwner, LPWSTR lpszDevice)
3542 {
3543     return WNetRestoreConnectionW(hwndOwner, lpszDevice);
3544 }
3545
3546 /*************************************************************************
3547  *      @       [SHLWAPI.391]
3548  *
3549  * See WNetGetLastErrorW.
3550  */
3551 DWORD WINAPI WNetGetLastErrorWrapW(LPDWORD lpError, LPWSTR lpErrorBuf, DWORD nErrorBufSize,
3552                          LPWSTR lpNameBuf, DWORD nNameBufSize)
3553 {
3554     return WNetGetLastErrorW(lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize);
3555 }
3556
3557 /*************************************************************************
3558  *      @       [SHLWAPI.401]
3559  *
3560  * See PageSetupDlgW.
3561  */
3562 BOOL WINAPI PageSetupDlgWrapW(LPPAGESETUPDLGW pagedlg)
3563 {
3564     return PageSetupDlgW(pagedlg);
3565 }
3566
3567 /*************************************************************************
3568  *      @       [SHLWAPI.402]
3569  *
3570  * See PrintDlgW.
3571  */
3572 BOOL WINAPI PrintDlgWrapW(LPPRINTDLGW printdlg)
3573 {
3574     return PrintDlgW(printdlg);
3575 }
3576
3577 /*************************************************************************
3578  *      @       [SHLWAPI.403]
3579  *
3580  * See GetOpenFileNameW.
3581  */
3582 BOOL WINAPI GetOpenFileNameWrapW(LPOPENFILENAMEW ofn)
3583 {
3584     return GetOpenFileNameW(ofn);
3585 }
3586
3587 /*************************************************************************
3588  *      @       [SHLWAPI.404]
3589  */
3590 HRESULT WINAPI SHIShellFolder_EnumObjects(LPSHELLFOLDER lpFolder, HWND hwnd, SHCONTF flags, IEnumIDList **ppenum)
3591 {
3592     IPersist *persist;
3593     HRESULT hr;
3594
3595     hr = IShellFolder_QueryInterface(lpFolder, &IID_IPersist, (LPVOID)&persist);
3596     if(SUCCEEDED(hr))
3597     {
3598         CLSID clsid;
3599         hr = IPersist_GetClassID(persist, &clsid);
3600         if(SUCCEEDED(hr))
3601         {
3602             if(IsEqualCLSID(&clsid, &CLSID_ShellFSFolder))
3603                 hr = IShellFolder_EnumObjects(lpFolder, hwnd, flags, ppenum);
3604             else
3605                 hr = E_FAIL;
3606         }
3607         IPersist_Release(persist);
3608     }
3609     return hr;
3610 }
3611
3612 /* INTERNAL: Map from HLS color space to RGB */
3613 static WORD ConvertHue(int wHue, WORD wMid1, WORD wMid2)
3614 {
3615   wHue = wHue > 240 ? wHue - 240 : wHue < 0 ? wHue + 240 : wHue;
3616
3617   if (wHue > 160)
3618     return wMid1;
3619   else if (wHue > 120)
3620     wHue = 160 - wHue;
3621   else if (wHue > 40)
3622     return wMid2;
3623
3624   return ((wHue * (wMid2 - wMid1) + 20) / 40) + wMid1;
3625 }
3626
3627 /* Convert to RGB and scale into RGB range (0..255) */
3628 #define GET_RGB(h) (ConvertHue(h, wMid1, wMid2) * 255 + 120) / 240
3629
3630 /*************************************************************************
3631  *      ColorHLSToRGB   [SHLWAPI.@]
3632  *
3633  * Convert from hls color space into an rgb COLORREF.
3634  *
3635  * PARAMS
3636  *  wHue        [I] Hue amount
3637  *  wLuminosity [I] Luminosity amount
3638  *  wSaturation [I] Saturation amount
3639  *
3640  * RETURNS
3641  *  A COLORREF representing the converted color.
3642  *
3643  * NOTES
3644  *  Input hls values are constrained to the range (0..240).
3645  */
3646 COLORREF WINAPI ColorHLSToRGB(WORD wHue, WORD wLuminosity, WORD wSaturation)
3647 {
3648   WORD wRed;
3649
3650   if (wSaturation)
3651   {
3652     WORD wGreen, wBlue, wMid1, wMid2;
3653
3654     if (wLuminosity > 120)
3655       wMid2 = wSaturation + wLuminosity - (wSaturation * wLuminosity + 120) / 240;
3656     else
3657       wMid2 = ((wSaturation + 240) * wLuminosity + 120) / 240;
3658
3659     wMid1 = wLuminosity * 2 - wMid2;
3660
3661     wRed   = GET_RGB(wHue + 80);
3662     wGreen = GET_RGB(wHue);
3663     wBlue  = GET_RGB(wHue - 80);
3664
3665     return RGB(wRed, wGreen, wBlue);
3666   }
3667
3668   wRed = wLuminosity * 255 / 240;
3669   return RGB(wRed, wRed, wRed);
3670 }
3671
3672 /*************************************************************************
3673  *      @       [SHLWAPI.413]
3674  *
3675  * Get the current docking status of the system.
3676  *
3677  * PARAMS
3678  *  dwFlags [I] DOCKINFO_ flags from "winbase.h", unused
3679  *
3680  * RETURNS
3681  *  One of DOCKINFO_UNDOCKED, DOCKINFO_UNDOCKED, or 0 if the system is not
3682  *  a notebook.
3683  */
3684 DWORD WINAPI SHGetMachineInfo(DWORD dwFlags)
3685 {
3686   HW_PROFILE_INFOA hwInfo;
3687
3688   TRACE("(0x%08x)\n", dwFlags);
3689
3690   GetCurrentHwProfileA(&hwInfo);
3691   switch (hwInfo.dwDockInfo & (DOCKINFO_DOCKED|DOCKINFO_UNDOCKED))
3692   {
3693   case DOCKINFO_DOCKED:
3694   case DOCKINFO_UNDOCKED:
3695     return hwInfo.dwDockInfo & (DOCKINFO_DOCKED|DOCKINFO_UNDOCKED);
3696   default:
3697     return 0;
3698   }
3699 }
3700
3701 /*************************************************************************
3702  *      @       [SHLWAPI.418]
3703  *
3704  * Function seems to do FreeLibrary plus other things.
3705  *
3706  * FIXME native shows the following calls:
3707  *   RtlEnterCriticalSection
3708  *   LocalFree
3709  *   GetProcAddress(Comctl32??, 150L)
3710  *   DPA_DeletePtr
3711  *   RtlLeaveCriticalSection
3712  *  followed by the FreeLibrary.
3713  *  The above code may be related to .377 above.
3714  */
3715 BOOL WINAPI MLFreeLibrary(HMODULE hModule)
3716 {
3717         FIXME("(%p) semi-stub\n", hModule);
3718         return FreeLibrary(hModule);
3719 }
3720
3721 /*************************************************************************
3722  *      @       [SHLWAPI.419]
3723  */
3724 BOOL WINAPI SHFlushSFCacheWrap(void) {
3725   FIXME(": stub\n");
3726   return TRUE;
3727 }
3728
3729 /*************************************************************************
3730  *      @      [SHLWAPI.429]
3731  * FIXME I have no idea what this function does or what its arguments are.
3732  */
3733 BOOL WINAPI MLIsMLHInstance(HINSTANCE hInst)
3734 {
3735        FIXME("(%p) stub\n", hInst);
3736        return FALSE;
3737 }
3738
3739
3740 /*************************************************************************
3741  *      @       [SHLWAPI.430]
3742  */
3743 DWORD WINAPI MLSetMLHInstance(HINSTANCE hInst, HANDLE hHeap)
3744 {
3745         FIXME("(%p,%p) stub\n", hInst, hHeap);
3746         return E_FAIL;   /* This is what is used if shlwapi not loaded */
3747 }
3748
3749 /*************************************************************************
3750  *      @       [SHLWAPI.431]
3751  */
3752 DWORD WINAPI MLClearMLHInstance(DWORD x)
3753 {
3754         FIXME("(0x%08x)stub\n", x);
3755         return 0xabba1247;
3756 }
3757
3758 /*************************************************************************
3759  * @ [SHLWAPI.432]
3760  *
3761  * See SHSendMessageBroadcastW
3762  *
3763  */
3764 DWORD WINAPI SHSendMessageBroadcastA(UINT uMsg, WPARAM wParam, LPARAM lParam)
3765 {
3766     return SendMessageTimeoutA(HWND_BROADCAST, uMsg, wParam, lParam,
3767                                SMTO_ABORTIFHUNG, 2000, NULL);
3768 }
3769
3770 /*************************************************************************
3771  * @ [SHLWAPI.433]
3772  *
3773  * A wrapper for sending Broadcast Messages to all top level Windows
3774  *
3775  */
3776 DWORD WINAPI SHSendMessageBroadcastW(UINT uMsg, WPARAM wParam, LPARAM lParam)
3777 {
3778     return SendMessageTimeoutW(HWND_BROADCAST, uMsg, wParam, lParam,
3779                                SMTO_ABORTIFHUNG, 2000, NULL);
3780 }
3781
3782 /*************************************************************************
3783  *      @       [SHLWAPI.436]
3784  *
3785  * Convert a Unicode string CLSID into a CLSID.
3786  *
3787  * PARAMS
3788  *  idstr      [I]   string containing a CLSID in text form
3789  *  id         [O]   CLSID extracted from the string
3790  *
3791  * RETURNS
3792  *  S_OK on success or E_INVALIDARG on failure
3793  */
3794 HRESULT WINAPI CLSIDFromStringWrap(LPCWSTR idstr, CLSID *id)
3795 {
3796     return CLSIDFromString((LPOLESTR)idstr, id);
3797 }
3798
3799 /*************************************************************************
3800  *      @       [SHLWAPI.437]
3801  *
3802  * Determine if the OS supports a given feature.
3803  *
3804  * PARAMS
3805  *  dwFeature [I] Feature requested (undocumented)
3806  *
3807  * RETURNS
3808  *  TRUE  If the feature is available.
3809  *  FALSE If the feature is not available.
3810  */
3811 BOOL WINAPI IsOS(DWORD feature)
3812 {
3813     OSVERSIONINFOA osvi;
3814     DWORD platform, majorv, minorv;
3815
3816     osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
3817     if(!GetVersionExA(&osvi))  {
3818         ERR("GetVersionEx failed\n");
3819         return FALSE;
3820     }
3821
3822     majorv = osvi.dwMajorVersion;
3823     minorv = osvi.dwMinorVersion;
3824     platform = osvi.dwPlatformId;
3825
3826 #define ISOS_RETURN(x) \
3827     TRACE("(0x%x) ret=%d\n",feature,(x)); \
3828     return (x);
3829
3830     switch(feature)  {
3831     case OS_WIN32SORGREATER:
3832         ISOS_RETURN(platform == VER_PLATFORM_WIN32s
3833                  || platform == VER_PLATFORM_WIN32_WINDOWS)
3834     case OS_NT:
3835         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
3836     case OS_WIN95ORGREATER:
3837         ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS)
3838     case OS_NT4ORGREATER:
3839         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 4)
3840     case OS_WIN2000ORGREATER_ALT:
3841     case OS_WIN2000ORGREATER:
3842         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5)
3843     case OS_WIN98ORGREATER:
3844         ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv >= 10)
3845     case OS_WIN98_GOLD:
3846         ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv == 10)
3847     case OS_WIN2000PRO:
3848         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5)
3849     case OS_WIN2000SERVER:
3850         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1))
3851     case OS_WIN2000ADVSERVER:
3852         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1))
3853     case OS_WIN2000DATACENTER:
3854         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1))
3855     case OS_WIN2000TERMINAL:
3856         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1))
3857     case OS_EMBEDDED:
3858         FIXME("(OS_EMBEDDED) What should we return here?\n");
3859         return FALSE;
3860     case OS_TERMINALCLIENT:
3861         FIXME("(OS_TERMINALCLIENT) What should we return here?\n");
3862         return FALSE;
3863     case OS_TERMINALREMOTEADMIN:
3864         FIXME("(OS_TERMINALREMOTEADMIN) What should we return here?\n");
3865         return FALSE;
3866     case OS_WIN95_GOLD:
3867         ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv == 0)
3868     case OS_MEORGREATER:
3869         ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv >= 90)
3870     case OS_XPORGREATER:
3871         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5 && minorv >= 1)
3872     case OS_HOME:
3873         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5 && minorv >= 1)
3874     case OS_PROFESSIONAL:
3875         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
3876     case OS_DATACENTER:
3877         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
3878     case OS_ADVSERVER:
3879         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5)
3880     case OS_SERVER:
3881         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
3882     case OS_TERMINALSERVER:
3883         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
3884     case OS_PERSONALTERMINALSERVER:
3885         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && minorv >= 1 && majorv >= 5)
3886     case OS_FASTUSERSWITCHING:
3887         FIXME("(OS_FASTUSERSWITCHING) What should we return here?\n");
3888         return TRUE;
3889     case OS_WELCOMELOGONUI:
3890         FIXME("(OS_WELCOMELOGONUI) What should we return here?\n");
3891         return FALSE;
3892     case OS_DOMAINMEMBER:
3893         FIXME("(OS_DOMAINMEMBER) What should we return here?\n");
3894         return TRUE;
3895     case OS_ANYSERVER:
3896         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
3897     case OS_WOW6432:
3898         FIXME("(OS_WOW6432) Should we check this?\n");
3899         return FALSE;
3900     case OS_WEBSERVER:
3901         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
3902     case OS_SMALLBUSINESSSERVER:
3903         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
3904     case OS_TABLETPC:
3905         FIXME("(OS_TABLEPC) What should we return here?\n");
3906         return FALSE;
3907     case OS_SERVERADMINUI:
3908         FIXME("(OS_SERVERADMINUI) What should we return here?\n");
3909         return FALSE;
3910     case OS_MEDIACENTER:
3911         FIXME("(OS_MEDIACENTER) What should we return here?\n");
3912         return FALSE;
3913     case OS_APPLIANCE:
3914         FIXME("(OS_APPLIANCE) What should we return here?\n");
3915         return FALSE;
3916     case 0x25: /*OS_VISTAORGREATER*/
3917         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 6)
3918     }
3919
3920 #undef ISOS_RETURN
3921
3922     WARN("(0x%x) unknown parameter\n",feature);
3923
3924     return FALSE;
3925 }
3926
3927 /*************************************************************************
3928  * @  [SHLWAPI.439]
3929  */
3930 HRESULT WINAPI SHLoadRegUIStringW(HKEY hkey, LPCWSTR value, LPWSTR buf, DWORD size)
3931 {
3932     DWORD type, sz = size;
3933
3934     if(RegQueryValueExW(hkey, value, NULL, &type, (LPBYTE)buf, &sz) != ERROR_SUCCESS)
3935         return E_FAIL;
3936
3937     return SHLoadIndirectString(buf, buf, size, NULL);
3938 }
3939
3940 /*************************************************************************
3941  * @  [SHLWAPI.478]
3942  *
3943  * Call IInputObject_TranslateAcceleratorIO() on an object.
3944  *
3945  * PARAMS
3946  *  lpUnknown [I] Object supporting the IInputObject interface.
3947  *  lpMsg     [I] Key message to be processed.
3948  *
3949  * RETURNS
3950  *  Success: S_OK.
3951  *  Failure: An HRESULT error code, or E_INVALIDARG if lpUnknown is NULL.
3952  */
3953 HRESULT WINAPI IUnknown_TranslateAcceleratorIO(IUnknown *lpUnknown, LPMSG lpMsg)
3954 {
3955   IInputObject* lpInput = NULL;
3956   HRESULT hRet = E_INVALIDARG;
3957
3958   TRACE("(%p,%p)\n", lpUnknown, lpMsg);
3959   if (lpUnknown)
3960   {
3961     hRet = IUnknown_QueryInterface(lpUnknown, &IID_IInputObject,
3962                                    (void**)&lpInput);
3963     if (SUCCEEDED(hRet) && lpInput)
3964     {
3965       hRet = IInputObject_TranslateAcceleratorIO(lpInput, lpMsg);
3966       IInputObject_Release(lpInput);
3967     }
3968   }
3969   return hRet;
3970 }
3971
3972 /*************************************************************************
3973  * @  [SHLWAPI.481]
3974  *
3975  * Call IInputObject_HasFocusIO() on an object.
3976  *
3977  * PARAMS
3978  *  lpUnknown [I] Object supporting the IInputObject interface.
3979  *
3980  * RETURNS
3981  *  Success: S_OK, if lpUnknown is an IInputObject object and has the focus,
3982  *           or S_FALSE otherwise.
3983  *  Failure: An HRESULT error code, or E_INVALIDARG if lpUnknown is NULL.
3984  */
3985 HRESULT WINAPI IUnknown_HasFocusIO(IUnknown *lpUnknown)
3986 {
3987   IInputObject* lpInput = NULL;
3988   HRESULT hRet = E_INVALIDARG;
3989
3990   TRACE("(%p)\n", lpUnknown);
3991   if (lpUnknown)
3992   {
3993     hRet = IUnknown_QueryInterface(lpUnknown, &IID_IInputObject,
3994                                    (void**)&lpInput);
3995     if (SUCCEEDED(hRet) && lpInput)
3996     {
3997       hRet = IInputObject_HasFocusIO(lpInput);
3998       IInputObject_Release(lpInput);
3999     }
4000   }
4001   return hRet;
4002 }
4003
4004 /*************************************************************************
4005  *      ColorRGBToHLS   [SHLWAPI.@]
4006  *
4007  * Convert an rgb COLORREF into the hls color space.
4008  *
4009  * PARAMS
4010  *  cRGB         [I] Source rgb value
4011  *  pwHue        [O] Destination for converted hue
4012  *  pwLuminance  [O] Destination for converted luminance
4013  *  pwSaturation [O] Destination for converted saturation
4014  *
4015  * RETURNS
4016  *  Nothing. pwHue, pwLuminance and pwSaturation are set to the converted
4017  *  values.
4018  *
4019  * NOTES
4020  *  Output HLS values are constrained to the range (0..240).
4021  *  For Achromatic conversions, Hue is set to 160.
4022  */
4023 VOID WINAPI ColorRGBToHLS(COLORREF cRGB, LPWORD pwHue,
4024                           LPWORD pwLuminance, LPWORD pwSaturation)
4025 {
4026   int wR, wG, wB, wMax, wMin, wHue, wLuminosity, wSaturation;
4027
4028   TRACE("(%08x,%p,%p,%p)\n", cRGB, pwHue, pwLuminance, pwSaturation);
4029
4030   wR = GetRValue(cRGB);
4031   wG = GetGValue(cRGB);
4032   wB = GetBValue(cRGB);
4033
4034   wMax = max(wR, max(wG, wB));
4035   wMin = min(wR, min(wG, wB));
4036
4037   /* Luminosity */
4038   wLuminosity = ((wMax + wMin) * 240 + 255) / 510;
4039
4040   if (wMax == wMin)
4041   {
4042     /* Achromatic case */
4043     wSaturation = 0;
4044     /* Hue is now unrepresentable, but this is what native returns... */
4045     wHue = 160;
4046   }
4047   else
4048   {
4049     /* Chromatic case */
4050     int wDelta = wMax - wMin, wRNorm, wGNorm, wBNorm;
4051
4052     /* Saturation */
4053     if (wLuminosity <= 120)
4054       wSaturation = ((wMax + wMin)/2 + wDelta * 240) / (wMax + wMin);
4055     else
4056       wSaturation = ((510 - wMax - wMin)/2 + wDelta * 240) / (510 - wMax - wMin);
4057
4058     /* Hue */
4059     wRNorm = (wDelta/2 + wMax * 40 - wR * 40) / wDelta;
4060     wGNorm = (wDelta/2 + wMax * 40 - wG * 40) / wDelta;
4061     wBNorm = (wDelta/2 + wMax * 40 - wB * 40) / wDelta;
4062
4063     if (wR == wMax)
4064       wHue = wBNorm - wGNorm;
4065     else if (wG == wMax)
4066       wHue = 80 + wRNorm - wBNorm;
4067     else
4068       wHue = 160 + wGNorm - wRNorm;
4069     if (wHue < 0)
4070       wHue += 240;
4071     else if (wHue > 240)
4072       wHue -= 240;
4073   }
4074   if (pwHue)
4075     *pwHue = wHue;
4076   if (pwLuminance)
4077     *pwLuminance = wLuminosity;
4078   if (pwSaturation)
4079     *pwSaturation = wSaturation;
4080 }
4081
4082 /*************************************************************************
4083  *      SHCreateShellPalette    [SHLWAPI.@]
4084  */
4085 HPALETTE WINAPI SHCreateShellPalette(HDC hdc)
4086 {
4087         FIXME("stub\n");
4088         return CreateHalftonePalette(hdc);
4089 }
4090
4091 /*************************************************************************
4092  *      SHGetInverseCMAP (SHLWAPI.@)
4093  *
4094  * Get an inverse color map table.
4095  *
4096  * PARAMS
4097  *  lpCmap  [O] Destination for color map
4098  *  dwSize  [I] Size of memory pointed to by lpCmap
4099  *
4100  * RETURNS
4101  *  Success: S_OK.
4102  *  Failure: E_POINTER,    If lpCmap is invalid.
4103  *           E_INVALIDARG, If dwFlags is invalid
4104  *           E_OUTOFMEMORY, If there is no memory available
4105  *
4106  * NOTES
4107  *  dwSize may only be CMAP_PTR_SIZE (4) or CMAP_SIZE (8192).
4108  *  If dwSize = CMAP_PTR_SIZE, *lpCmap is set to the address of this DLL's
4109  *  internal CMap.
4110  *  If dwSize = CMAP_SIZE, lpCmap is filled with a copy of the data from
4111  *  this DLL's internal CMap.
4112  */
4113 HRESULT WINAPI SHGetInverseCMAP(LPDWORD dest, DWORD dwSize)
4114 {
4115     if (dwSize == 4) {
4116         FIXME(" - returning bogus address for SHGetInverseCMAP\n");
4117         *dest = (DWORD)0xabba1249;
4118         return 0;
4119     }
4120     FIXME("(%p, %#x) stub\n", dest, dwSize);
4121     return 0;
4122 }
4123
4124 /*************************************************************************
4125  *      SHIsLowMemoryMachine    [SHLWAPI.@]
4126  *
4127  * Determine if the current computer has low memory.
4128  *
4129  * PARAMS
4130  *  x [I] FIXME
4131  *
4132  * RETURNS
4133  *  TRUE if the users machine has 16 Megabytes of memory or less,
4134  *  FALSE otherwise.
4135  */
4136 BOOL WINAPI SHIsLowMemoryMachine (DWORD x)
4137 {
4138   FIXME("(0x%08x) stub\n", x);
4139   return FALSE;
4140 }
4141
4142 /*************************************************************************
4143  *      GetMenuPosFromID        [SHLWAPI.@]
4144  *
4145  * Return the position of a menu item from its Id.
4146  *
4147  * PARAMS
4148  *   hMenu [I] Menu containing the item
4149  *   wID   [I] Id of the menu item
4150  *
4151  * RETURNS
4152  *  Success: The index of the menu item in hMenu.
4153  *  Failure: -1, If the item is not found.
4154  */
4155 INT WINAPI GetMenuPosFromID(HMENU hMenu, UINT wID)
4156 {
4157  MENUITEMINFOW mi;
4158  INT nCount = GetMenuItemCount(hMenu), nIter = 0;
4159
4160  while (nIter < nCount)
4161  {
4162    mi.cbSize = sizeof(mi);
4163    mi.fMask = MIIM_ID;
4164    if (GetMenuItemInfoW(hMenu, nIter, TRUE, &mi) && mi.wID == wID)
4165      return nIter;
4166    nIter++;
4167  }
4168  return -1;
4169 }
4170
4171 /*************************************************************************
4172  *      @       [SHLWAPI.179]
4173  *
4174  * Same as SHLWAPI.GetMenuPosFromID
4175  */
4176 DWORD WINAPI SHMenuIndexFromID(HMENU hMenu, UINT uID)
4177 {
4178     return GetMenuPosFromID(hMenu, uID);
4179 }
4180
4181
4182 /*************************************************************************
4183  *      @       [SHLWAPI.448]
4184  */
4185 VOID WINAPI FixSlashesAndColonW(LPWSTR lpwstr)
4186 {
4187     while (*lpwstr)
4188     {
4189         if (*lpwstr == '/')
4190             *lpwstr = '\\';
4191         lpwstr++;
4192     }
4193 }
4194
4195
4196 /*************************************************************************
4197  *      @       [SHLWAPI.461]
4198  */
4199 DWORD WINAPI SHGetAppCompatFlags(DWORD dwUnknown)
4200 {
4201   FIXME("(0x%08x) stub\n", dwUnknown);
4202   return 0;
4203 }
4204
4205
4206 /*************************************************************************
4207  *      @       [SHLWAPI.549]
4208  */
4209 HRESULT WINAPI SHCoCreateInstanceAC(REFCLSID rclsid, LPUNKNOWN pUnkOuter,
4210                                     DWORD dwClsContext, REFIID iid, LPVOID *ppv)
4211 {
4212     return CoCreateInstance(rclsid, pUnkOuter, dwClsContext, iid, ppv);
4213 }
4214
4215 /*************************************************************************
4216  * SHSkipJunction       [SHLWAPI.@]
4217  *
4218  * Determine if a bind context can be bound to an object
4219  *
4220  * PARAMS
4221  *  pbc    [I] Bind context to check
4222  *  pclsid [I] CLSID of object to be bound to
4223  *
4224  * RETURNS
4225  *  TRUE: If it is safe to bind
4226  *  FALSE: If pbc is invalid or binding would not be safe
4227  *
4228  */
4229 BOOL WINAPI SHSkipJunction(IBindCtx *pbc, const CLSID *pclsid)
4230 {
4231   static WCHAR szSkipBinding[] = { 'S','k','i','p',' ',
4232     'B','i','n','d','i','n','g',' ','C','L','S','I','D','\0' };
4233   BOOL bRet = FALSE;
4234
4235   if (pbc)
4236   {
4237     IUnknown* lpUnk;
4238
4239     if (SUCCEEDED(IBindCtx_GetObjectParam(pbc, szSkipBinding, &lpUnk)))
4240     {
4241       CLSID clsid;
4242
4243       if (SUCCEEDED(IUnknown_GetClassID(lpUnk, &clsid)) &&
4244           IsEqualGUID(pclsid, &clsid))
4245         bRet = TRUE;
4246
4247       IUnknown_Release(lpUnk);
4248     }
4249   }
4250   return bRet;
4251 }
4252
4253 /***********************************************************************
4254  *              SHGetShellKey (SHLWAPI.@)
4255  */
4256 DWORD WINAPI SHGetShellKey(DWORD a, DWORD b, DWORD c)
4257 {
4258     FIXME("(%x, %x, %x): stub\n", a, b, c);
4259     return 0x50;
4260 }
4261
4262 /***********************************************************************
4263  *              SHQueueUserWorkItem (SHLWAPI.@)
4264  */
4265 BOOL WINAPI SHQueueUserWorkItem(LPTHREAD_START_ROUTINE pfnCallback, 
4266         LPVOID pContext, LONG lPriority, DWORD_PTR dwTag,
4267         DWORD_PTR *pdwId, LPCSTR pszModule, DWORD dwFlags)
4268 {
4269     TRACE("(%p, %p, %d, %lx, %p, %s, %08x)\n", pfnCallback, pContext,
4270           lPriority, dwTag, pdwId, debugstr_a(pszModule), dwFlags);
4271
4272     if(lPriority || dwTag || pdwId || pszModule || dwFlags)
4273         FIXME("Unsupported arguments\n");
4274
4275     return QueueUserWorkItem(pfnCallback, pContext, 0);
4276 }
4277
4278 /***********************************************************************
4279  *              SHSetTimerQueueTimer (SHLWAPI.263)
4280  */
4281 HANDLE WINAPI SHSetTimerQueueTimer(HANDLE hQueue,
4282         WAITORTIMERCALLBACK pfnCallback, LPVOID pContext, DWORD dwDueTime,
4283         DWORD dwPeriod, LPCSTR lpszLibrary, DWORD dwFlags)
4284 {
4285     HANDLE hNewTimer;
4286
4287     /* SHSetTimerQueueTimer flags -> CreateTimerQueueTimer flags */
4288     if (dwFlags & TPS_LONGEXECTIME) {
4289         dwFlags &= ~TPS_LONGEXECTIME;
4290         dwFlags |= WT_EXECUTELONGFUNCTION;
4291     }
4292     if (dwFlags & TPS_EXECUTEIO) {
4293         dwFlags &= ~TPS_EXECUTEIO;
4294         dwFlags |= WT_EXECUTEINIOTHREAD;
4295     }
4296
4297     if (!CreateTimerQueueTimer(&hNewTimer, hQueue, pfnCallback, pContext,
4298                                dwDueTime, dwPeriod, dwFlags))
4299         return NULL;
4300
4301     return hNewTimer;
4302 }
4303
4304 /***********************************************************************
4305  *              IUnknown_OnFocusChangeIS (SHLWAPI.@)
4306  */
4307 HRESULT WINAPI IUnknown_OnFocusChangeIS(LPUNKNOWN lpUnknown, LPUNKNOWN pFocusObject, BOOL bFocus)
4308 {
4309     IInputObjectSite *pIOS = NULL;
4310     HRESULT hRet = E_INVALIDARG;
4311
4312     TRACE("(%p, %p, %s)\n", lpUnknown, pFocusObject, bFocus ? "TRUE" : "FALSE");
4313
4314     if (lpUnknown)
4315     {
4316         hRet = IUnknown_QueryInterface(lpUnknown, &IID_IInputObjectSite,
4317                                        (void **)&pIOS);
4318         if (SUCCEEDED(hRet) && pIOS)
4319         {
4320             hRet = IInputObjectSite_OnFocusChangeIS(pIOS, pFocusObject, bFocus);
4321             IInputObjectSite_Release(pIOS);
4322         }
4323     }
4324     return hRet;
4325 }
4326
4327 /***********************************************************************
4328  *              SHGetValueW (SHLWAPI.@)
4329  */
4330 HRESULT WINAPI SKGetValueW(DWORD a, LPWSTR b, LPWSTR c, DWORD d, DWORD e, DWORD f)
4331 {
4332     FIXME("(%x, %s, %s, %x, %x, %x): stub\n", a, debugstr_w(b), debugstr_w(c), d, e, f);
4333     return E_FAIL;
4334 }
4335
4336 typedef HRESULT (WINAPI *DllGetVersion_func)(DLLVERSIONINFO *);
4337
4338 /***********************************************************************
4339  *              GetUIVersion (SHLWAPI.452)
4340  */
4341 DWORD WINAPI GetUIVersion(void)
4342 {
4343     static DWORD version;
4344
4345     if (!version)
4346     {
4347         DllGetVersion_func pDllGetVersion;
4348         HMODULE dll = LoadLibraryA("shell32.dll");
4349         if (!dll) return 0;
4350
4351         pDllGetVersion = (DllGetVersion_func)GetProcAddress(dll, "DllGetVersion");
4352         if (pDllGetVersion)
4353         {
4354             DLLVERSIONINFO dvi;
4355             dvi.cbSize = sizeof(DLLVERSIONINFO);
4356             if (pDllGetVersion(&dvi) == S_OK) version = dvi.dwMajorVersion;
4357         }
4358         FreeLibrary( dll );
4359         if (!version) version = 3;  /* old shell dlls don't have DllGetVersion */
4360     }
4361     return version;
4362 }
4363
4364 /***********************************************************************
4365  *              ShellMessageBoxWrapW [SHLWAPI.388]
4366  *
4367  * See shell32.ShellMessageBoxW
4368  *
4369  * NOTE:
4370  * shlwapi.ShellMessageBoxWrapW is a duplicate of shell32.ShellMessageBoxW
4371  * because we can't forward to it in the .spec file since it's exported by
4372  * ordinal. If you change the implementation here please update the code in
4373  * shell32 as well.
4374  */
4375 INT WINAPIV ShellMessageBoxWrapW(HINSTANCE hInstance, HWND hWnd, LPCWSTR lpText,
4376                                  LPCWSTR lpCaption, UINT uType, ...)
4377 {
4378     WCHAR szText[100], szTitle[100];
4379     LPCWSTR pszText = szText, pszTitle = szTitle;
4380     LPWSTR pszTemp;
4381     __ms_va_list args;
4382     int ret;
4383
4384     __ms_va_start(args, uType);
4385
4386     TRACE("(%p,%p,%p,%p,%08x)\n", hInstance, hWnd, lpText, lpCaption, uType);
4387
4388     if (IS_INTRESOURCE(lpCaption))
4389         LoadStringW(hInstance, LOWORD(lpCaption), szTitle, sizeof(szTitle)/sizeof(szTitle[0]));
4390     else
4391         pszTitle = lpCaption;
4392
4393     if (IS_INTRESOURCE(lpText))
4394         LoadStringW(hInstance, LOWORD(lpText), szText, sizeof(szText)/sizeof(szText[0]));
4395     else
4396         pszText = lpText;
4397
4398     FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
4399                    pszText, 0, 0, (LPWSTR)&pszTemp, 0, &args);
4400
4401     __ms_va_end(args);
4402
4403     ret = MessageBoxW(hWnd, pszTemp, pszTitle, uType);
4404     LocalFree(pszTemp);
4405     return ret;
4406 }
4407
4408 HRESULT WINAPI IUnknown_QueryServiceExec(IUnknown *unk, REFIID service, REFIID clsid,
4409                                          DWORD x1, DWORD x2, DWORD x3, void **ppvOut)
4410 {
4411     FIXME("%p %s %s %08x %08x %08x %p\n", unk,
4412           debugstr_guid(service), debugstr_guid(clsid), x1, x2, x3, ppvOut);
4413     return E_NOTIMPL;
4414 }
4415
4416 HRESULT WINAPI IUnknown_ProfferService(IUnknown *unk, void *x0, void *x1, void *x2)
4417 {
4418     FIXME("%p %p %p %p\n", unk, x0, x1, x2);
4419     return E_NOTIMPL;
4420 }
4421
4422 /***********************************************************************
4423  *              ZoneComputePaneSize [SHLWAPI.382]
4424  */
4425 UINT WINAPI ZoneComputePaneSize(HWND hwnd)
4426 {
4427     FIXME("\n");
4428     return 0x95;
4429 }
4430
4431 /***********************************************************************
4432  *              SHChangeNotifyWrap [SHLWAPI.394]
4433  */
4434 void WINAPI SHChangeNotifyWrap(LONG wEventId, UINT uFlags, LPCVOID dwItem1, LPCVOID dwItem2)
4435 {
4436     SHChangeNotify(wEventId, uFlags, dwItem1, dwItem2);
4437 }
4438
4439 typedef struct SHELL_USER_SID {   /* according to MSDN this should be in shlobj.h... */
4440     SID_IDENTIFIER_AUTHORITY sidAuthority;
4441     DWORD                    dwUserGroupID;
4442     DWORD                    dwUserID;
4443 } SHELL_USER_SID, *PSHELL_USER_SID;
4444
4445 typedef struct SHELL_USER_PERMISSION { /* ...and this should be in shlwapi.h */
4446     SHELL_USER_SID susID;
4447     DWORD          dwAccessType;
4448     BOOL           fInherit;
4449     DWORD          dwAccessMask;
4450     DWORD          dwInheritMask;
4451     DWORD          dwInheritAccessMask;
4452 } SHELL_USER_PERMISSION, *PSHELL_USER_PERMISSION;
4453
4454 /***********************************************************************
4455  *             GetShellSecurityDescriptor [SHLWAPI.475]
4456  *
4457  * prepares SECURITY_DESCRIPTOR from a set of ACEs
4458  *
4459  * PARAMS
4460  *  apUserPerm [I] array of pointers to SHELL_USER_PERMISSION structures,
4461  *                 each of which describes permissions to apply
4462  *  cUserPerm  [I] number of entries in apUserPerm array
4463  *
4464  * RETURNS
4465  *  success: pointer to SECURITY_DESCRIPTOR
4466  *  failure: NULL
4467  *
4468  * NOTES
4469  *  Call should free returned descriptor with LocalFree
4470  */
4471 PSECURITY_DESCRIPTOR WINAPI GetShellSecurityDescriptor(PSHELL_USER_PERMISSION *apUserPerm, int cUserPerm)
4472 {
4473     PSID *sidlist;
4474     PSID  cur_user = NULL;
4475     BYTE  tuUser[2000];
4476     DWORD acl_size;
4477     int   sid_count, i;
4478     PSECURITY_DESCRIPTOR psd = NULL;
4479
4480     TRACE("%p %d\n", apUserPerm, cUserPerm);
4481
4482     if (apUserPerm == NULL || cUserPerm <= 0)
4483         return NULL;
4484
4485     sidlist = HeapAlloc(GetProcessHeap(), 0, cUserPerm * sizeof(PSID));
4486     if (!sidlist)
4487         return NULL;
4488
4489     acl_size = sizeof(ACL);
4490
4491     for(sid_count = 0; sid_count < cUserPerm; sid_count++)
4492     {
4493         static SHELL_USER_SID null_sid = {{SECURITY_NULL_SID_AUTHORITY}, 0, 0};
4494         PSHELL_USER_PERMISSION perm = apUserPerm[sid_count];
4495         PSHELL_USER_SID sid = &perm->susID;
4496         PSID pSid;
4497         BOOL ret = TRUE;
4498
4499         if (!memcmp((void*)sid, (void*)&null_sid, sizeof(SHELL_USER_SID)))
4500         {  /* current user's SID */ 
4501             if (!cur_user)
4502             {
4503                 HANDLE Token;
4504                 DWORD bufsize = sizeof(tuUser);
4505
4506                 ret = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &Token);
4507                 if (ret)
4508                 {
4509                     ret = GetTokenInformation(Token, TokenUser, (void*)tuUser, bufsize, &bufsize );
4510                     if (ret)
4511                         cur_user = ((PTOKEN_USER)tuUser)->User.Sid;
4512                     CloseHandle(Token);
4513                 }
4514             }
4515             pSid = cur_user;
4516         } else if (sid->dwUserID==0) /* one sub-authority */
4517             ret = AllocateAndInitializeSid(&sid->sidAuthority, 1, sid->dwUserGroupID, 0,
4518                     0, 0, 0, 0, 0, 0, &pSid);
4519         else
4520             ret = AllocateAndInitializeSid(&sid->sidAuthority, 2, sid->dwUserGroupID, sid->dwUserID,
4521                     0, 0, 0, 0, 0, 0, &pSid);
4522         if (!ret)
4523             goto free_sids;
4524
4525         sidlist[sid_count] = pSid;
4526         /* increment acl_size (1 ACE for non-inheritable and 2 ACEs for inheritable records */
4527         acl_size += (sizeof(ACCESS_ALLOWED_ACE)-sizeof(DWORD) + GetLengthSid(pSid)) * (perm->fInherit ? 2 : 1);
4528     }
4529
4530     psd = LocalAlloc(0, sizeof(SECURITY_DESCRIPTOR) + acl_size);
4531
4532     if (psd != NULL)
4533     {
4534         PACL pAcl = (PACL)(((BYTE*)psd)+sizeof(SECURITY_DESCRIPTOR));
4535
4536         if (!InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION))
4537             goto error;
4538
4539         if (!InitializeAcl(pAcl, acl_size, ACL_REVISION))
4540             goto error;
4541
4542         for(i = 0; i < sid_count; i++)
4543         {
4544             PSHELL_USER_PERMISSION sup = apUserPerm[i];
4545             PSID sid = sidlist[i];
4546
4547             switch(sup->dwAccessType)
4548             {
4549                 case ACCESS_ALLOWED_ACE_TYPE:
4550                     if (!AddAccessAllowedAce(pAcl, ACL_REVISION, sup->dwAccessMask, sid))
4551                         goto error;
4552                     if (sup->fInherit && !AddAccessAllowedAceEx(pAcl, ACL_REVISION, 
4553                                 (BYTE)sup->dwInheritMask, sup->dwInheritAccessMask, sid))
4554                         goto error;
4555                     break;
4556                 case ACCESS_DENIED_ACE_TYPE:
4557                     if (!AddAccessDeniedAce(pAcl, ACL_REVISION, sup->dwAccessMask, sid))
4558                         goto error;
4559                     if (sup->fInherit && !AddAccessDeniedAceEx(pAcl, ACL_REVISION, 
4560                                 (BYTE)sup->dwInheritMask, sup->dwInheritAccessMask, sid))
4561                         goto error;
4562                     break;
4563                 default:
4564                     goto error;
4565             }
4566         }
4567
4568         if (!SetSecurityDescriptorDacl(psd, TRUE, pAcl, FALSE))
4569             goto error;
4570     }
4571     goto free_sids;
4572
4573 error:
4574     LocalFree(psd);
4575     psd = NULL;
4576 free_sids:
4577     for(i = 0; i < sid_count; i++)
4578     {
4579         if (!cur_user || sidlist[i] != cur_user)
4580             FreeSid(sidlist[i]);
4581     }
4582     HeapFree(GetProcessHeap(), 0, sidlist);
4583
4584     return psd;
4585 }
4586
4587 /***********************************************************************
4588  *             SHCreatePropertyBagOnRegKey [SHLWAPI.471]
4589  *
4590  * Creates a property bag from a registry key
4591  *
4592  * PARAMS
4593  *  hKey       [I] Handle to the desired registry key
4594  *  subkey     [I] Name of desired subkey, or NULL to open hKey directly
4595  *  grfMode    [I] Optional flags
4596  *  riid       [I] IID of requested property bag interface
4597  *  ppv        [O] Address to receive pointer to the new interface
4598  *
4599  * RETURNS
4600  *  success: 0
4601  *  failure: error code
4602  *
4603  */
4604 HRESULT WINAPI SHCreatePropertyBagOnRegKey (HKEY hKey, LPCWSTR subkey,
4605     DWORD grfMode, REFIID riid, void **ppv)
4606 {
4607     FIXME("%p %s %d %s %p STUB\n", hKey, debugstr_w(subkey), grfMode,
4608           debugstr_guid(riid), ppv);
4609
4610     return E_NOTIMPL;
4611 }
4612
4613 /***********************************************************************
4614  *             SHGetViewStatePropertyBag [SHLWAPI.515]
4615  *
4616  * Retrieves a property bag in which the view state information of a folder
4617  * can be stored.
4618  *
4619  * PARAMS
4620  *  pidl        [I] PIDL of the folder requested
4621  *  bag_name    [I] Name of the property bag requested
4622  *  flags       [I] Optional flags
4623  *  riid        [I] IID of requested property bag interface
4624  *  ppv         [O] Address to receive pointer to the new interface
4625  *
4626  * RETURNS
4627  *  success: S_OK
4628  *  failure: error code
4629  *
4630  */
4631 HRESULT WINAPI SHGetViewStatePropertyBag(LPCITEMIDLIST pidl, LPWSTR bag_name,
4632     DWORD flags, REFIID riid, void **ppv)
4633 {
4634     FIXME("%p %s %d %s %p STUB\n", pidl, debugstr_w(bag_name), flags,
4635           debugstr_guid(riid), ppv);
4636
4637     return E_NOTIMPL;
4638 }
4639
4640 /***********************************************************************
4641  *             SHFormatDateTimeW [SHLWAPI.354]
4642  *
4643  * Produces a string representation of a time.
4644  *
4645  * PARAMS
4646  *  fileTime   [I] Pointer to FILETIME structure specifying the time
4647  *  flags      [I] Flags specifying the desired output
4648  *  buf        [O] Pointer to buffer for output
4649  *  bufSize    [I] Number of characters that can be contained in buffer
4650  *
4651  * RETURNS
4652  *  success: number of characters written to the buffer
4653  *  failure: 0
4654  *
4655  */
4656 INT WINAPI SHFormatDateTimeW(const FILETIME UNALIGNED *fileTime, DWORD *flags,
4657     LPWSTR buf, UINT bufSize)
4658 {
4659     FIXME("%p %p %s %d STUB\n", fileTime, flags, debugstr_w(buf), bufSize);
4660     return 0;
4661 }
4662
4663 /***********************************************************************
4664  *             SHFormatDateTimeA [SHLWAPI.353]
4665  *
4666  * See SHFormatDateTimeW.
4667  *
4668  */
4669 INT WINAPI SHFormatDateTimeA(const FILETIME UNALIGNED *fileTime, DWORD *flags,
4670     LPCSTR buf, UINT bufSize)
4671 {
4672     WCHAR *bufW;
4673     DWORD buflenW, convlen;
4674     INT retval;
4675
4676     if (!buf || !bufSize)
4677         return 0;
4678
4679     buflenW = bufSize;
4680     bufW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * buflenW);
4681     retval = SHFormatDateTimeW(fileTime, flags, bufW, buflenW);
4682
4683     if (retval != 0)
4684         convlen = WideCharToMultiByte(CP_ACP, 0, bufW, -1, (LPSTR) buf, bufSize, NULL, NULL);
4685
4686     HeapFree(GetProcessHeap(), 0, bufW);
4687     return retval;
4688 }
4689
4690 /***********************************************************************
4691  *             ZoneCheckUrlExW [SHLWAPI.231]
4692  *
4693  * Checks the details of the security zone for the supplied site. (?)
4694  *
4695  * PARAMS
4696  *
4697  *  szURL   [I] Pointer to the URL to check
4698  *
4699  *  Other parameters currently unknown.
4700  *
4701  * RETURNS
4702  *  unknown
4703  */
4704
4705 INT WINAPI ZoneCheckUrlExW(LPWSTR szURL, PVOID pUnknown, DWORD dwUnknown2,
4706     DWORD dwUnknown3, DWORD dwUnknown4, DWORD dwUnknown5, DWORD dwUnknown6,
4707     DWORD dwUnknown7)
4708 {
4709     FIXME("(%s,%p,%x,%x,%x,%x,%x,%x) STUB\n", debugstr_w(szURL), pUnknown, dwUnknown2,
4710         dwUnknown3, dwUnknown4, dwUnknown5, dwUnknown6, dwUnknown7);
4711
4712     return 0;
4713 }
4714
4715 /***********************************************************************
4716  *             SHVerbExistsNA [SHLWAPI.196]
4717  *
4718  *
4719  * PARAMS
4720  *
4721  *  verb [I] a string, often appears to be an extension.
4722  *
4723  *  Other parameters currently unknown.
4724  *
4725  * RETURNS
4726  *  unknown
4727  */
4728 INT WINAPI SHVerbExistsNA(LPSTR verb, PVOID pUnknown, PVOID pUnknown2, DWORD dwUnknown3)
4729 {
4730     FIXME("(%s, %p, %p, %i) STUB\n",verb, pUnknown, pUnknown2, dwUnknown3);
4731     return 0;
4732 }
4733
4734 /*************************************************************************
4735  *      @       [SHLWAPI.538]
4736  *
4737  *  Undocumented:  Implementation guessed at via Name and behavior
4738  *
4739  * PARAMS
4740  *  lpUnknown [I] Object to get an IServiceProvider interface from
4741  *  riid      [I] Function requested for QueryService call
4742  *  lppOut    [O] Destination for the service interface pointer
4743  *
4744  * RETURNS
4745  *  Success: S_OK. lppOut contains an object providing the requested service
4746  *  Failure: An HRESULT error code
4747  *
4748  * NOTES
4749  *  lpUnknown is expected to support the IServiceProvider interface.
4750  */
4751 HRESULT WINAPI IUnknown_QueryServiceForWebBrowserApp(IUnknown* lpUnknown,
4752         REFGUID riid, LPVOID *lppOut)
4753 {
4754     FIXME("%p %s %p semi-STUB\n", lpUnknown, debugstr_guid(riid), lppOut);
4755     return IUnknown_QueryService(lpUnknown,&IID_IWebBrowserApp,riid,lppOut);
4756 }
4757
4758 /**************************************************************************
4759  *  SHPropertyBag_ReadLONG (SHLWAPI.496)
4760  *
4761  * This function asks a property bag to read a named property as a LONG.
4762  *
4763  * PARAMS
4764  *  ppb: a IPropertyBag interface
4765  *  pszPropName:  Unicode string that names the property
4766  *  pValue: address to receive the property value as a 32-bit signed integer
4767  *
4768  * RETURNS
4769  *  0 for Success
4770  */
4771 BOOL WINAPI SHPropertyBag_ReadLONG(IPropertyBag *ppb, LPCWSTR pszPropName, LPLONG pValue)
4772 {
4773     VARIANT var;
4774     HRESULT hr;
4775     TRACE("%p %s %p\n", ppb,debugstr_w(pszPropName),pValue);
4776     if (!pszPropName || !ppb || !pValue)
4777         return E_INVALIDARG;
4778     V_VT(&var) = VT_I4;
4779     hr = IPropertyBag_Read(ppb, pszPropName, &var, NULL);
4780     if (SUCCEEDED(hr))
4781     {
4782         if (V_VT(&var) == VT_I4)
4783             *pValue = V_I4(&var);
4784         else
4785             hr = DISP_E_BADVARTYPE;
4786     }
4787     return hr;
4788 }