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