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