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