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