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