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