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