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