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