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