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