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