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