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