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