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