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