kernel32: Properly handle bare console on input.
[wine] / dlls / shlwapi / ordinal.c
1 /*
2  * SHLWAPI ordinal functions
3  *
4  * Copyright 1997 Marcus Meissner
5  *           1998 Jürgen Schmied
6  *           2001-2003 Jon Griffiths
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <string.h>
29
30 #define COBJMACROS
31 #define NONAMELESSUNION
32 #define NONAMELESSSTRUCT
33
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winnls.h"
37 #include "winreg.h"
38 #include "wingdi.h"
39 #include "winuser.h"
40 #include "winver.h"
41 #include "winnetwk.h"
42 #include "mmsystem.h"
43 #include "objbase.h"
44 #include "exdisp.h"
45 #include "shdeprecated.h"
46 #include "shlobj.h"
47 #include "shlwapi.h"
48 #include "shellapi.h"
49 #include "commdlg.h"
50 #include "mlang.h"
51 #include "mshtmhst.h"
52 #include "wine/unicode.h"
53 #include "wine/debug.h"
54
55
56 WINE_DEFAULT_DEBUG_CHANNEL(shell);
57
58 /* DLL handles for late bound calls */
59 extern HINSTANCE shlwapi_hInstance;
60 extern DWORD SHLWAPI_ThreadRef_index;
61
62 HRESULT WINAPI IUnknown_QueryService(IUnknown*,REFGUID,REFIID,LPVOID*);
63 HRESULT WINAPI SHInvokeCommand(HWND,IShellFolder*,LPCITEMIDLIST,BOOL);
64 BOOL    WINAPI SHAboutInfoW(LPWSTR,DWORD);
65
66 /*
67  NOTES: Most functions exported by ordinal seem to be superfluous.
68  The reason for these functions to be there is to provide a wrapper
69  for unicode functions to provide these functions on systems without
70  unicode functions eg. win95/win98. Since we have such functions we just
71  call these. If running Wine with native DLLs, some late bound calls may
72  fail. However, it is better to implement the functions in the forward DLL
73  and recommend the builtin rather than reimplementing the calls here!
74 */
75
76 /*************************************************************************
77  * SHLWAPI_DupSharedHandle
78  *
79  * Internal implemetation of SHLWAPI_11.
80  */
81 static HANDLE SHLWAPI_DupSharedHandle(HANDLE hShared, DWORD dwDstProcId,
82                                       DWORD dwSrcProcId, DWORD dwAccess,
83                                       DWORD dwOptions)
84 {
85   HANDLE hDst, hSrc;
86   DWORD dwMyProcId = GetCurrentProcessId();
87   HANDLE hRet = NULL;
88
89   TRACE("(%p,%d,%d,%08x,%08x)\n", hShared, dwDstProcId, dwSrcProcId,
90         dwAccess, dwOptions);
91
92   /* Get dest process handle */
93   if (dwDstProcId == dwMyProcId)
94     hDst = GetCurrentProcess();
95   else
96     hDst = OpenProcess(PROCESS_DUP_HANDLE, 0, dwDstProcId);
97
98   if (hDst)
99   {
100     /* Get src process handle */
101     if (dwSrcProcId == dwMyProcId)
102       hSrc = GetCurrentProcess();
103     else
104       hSrc = OpenProcess(PROCESS_DUP_HANDLE, 0, dwSrcProcId);
105
106     if (hSrc)
107     {
108       /* Make handle available to dest process */
109       if (!DuplicateHandle(hDst, hShared, hSrc, &hRet,
110                            dwAccess, 0, dwOptions | DUPLICATE_SAME_ACCESS))
111         hRet = NULL;
112
113       if (dwSrcProcId != dwMyProcId)
114         CloseHandle(hSrc);
115     }
116
117     if (dwDstProcId != dwMyProcId)
118       CloseHandle(hDst);
119   }
120
121   TRACE("Returning handle %p\n", hRet);
122   return hRet;
123 }
124
125 /*************************************************************************
126  * @  [SHLWAPI.7]
127  *
128  * Create a block of sharable memory and initialise it with data.
129  *
130  * PARAMS
131  * lpvData  [I] Pointer to data to write
132  * dwSize   [I] Size of data
133  * dwProcId [I] ID of process owning data
134  *
135  * RETURNS
136  * Success: A shared memory handle
137  * Failure: NULL
138  *
139  * NOTES
140  * Ordinals 7-11 provide a set of calls to create shared memory between a
141  * group of processes. The shared memory is treated opaquely in that its size
142  * is not exposed to clients who map it. This is accomplished by storing
143  * the size of the map as the first DWORD of mapped data, and then offsetting
144  * the view pointer returned by this size.
145  *
146  */
147 HANDLE WINAPI SHAllocShared(LPCVOID lpvData, DWORD dwSize, DWORD dwProcId)
148 {
149   HANDLE hMap;
150   LPVOID pMapped;
151   HANDLE hRet = NULL;
152
153   TRACE("(%p,%d,%d)\n", lpvData, dwSize, dwProcId);
154
155   /* Create file mapping of the correct length */
156   hMap = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, FILE_MAP_READ, 0,
157                             dwSize + sizeof(dwSize), NULL);
158   if (!hMap)
159     return hRet;
160
161   /* Get a view in our process address space */
162   pMapped = MapViewOfFile(hMap, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
163
164   if (pMapped)
165   {
166     /* Write size of data, followed by the data, to the view */
167     *((DWORD*)pMapped) = dwSize;
168     if (lpvData)
169       memcpy((char *) pMapped + sizeof(dwSize), lpvData, dwSize);
170
171     /* Release view. All further views mapped will be opaque */
172     UnmapViewOfFile(pMapped);
173     hRet = SHLWAPI_DupSharedHandle(hMap, dwProcId,
174                                    GetCurrentProcessId(), FILE_MAP_ALL_ACCESS,
175                                    DUPLICATE_SAME_ACCESS);
176   }
177
178   CloseHandle(hMap);
179   return hRet;
180 }
181
182 /*************************************************************************
183  * @ [SHLWAPI.8]
184  *
185  * Get a pointer to a block of shared memory from a shared memory handle.
186  *
187  * PARAMS
188  * hShared  [I] Shared memory handle
189  * dwProcId [I] ID of process owning hShared
190  *
191  * RETURNS
192  * Success: A pointer to the shared memory
193  * Failure: NULL
194  *
195  */
196 PVOID WINAPI SHLockShared(HANDLE hShared, DWORD dwProcId)
197 {
198   HANDLE hDup;
199   LPVOID pMapped;
200
201   TRACE("(%p %d)\n", hShared, dwProcId);
202
203   /* Get handle to shared memory for current process */
204   hDup = SHLWAPI_DupSharedHandle(hShared, dwProcId, GetCurrentProcessId(),
205                                  FILE_MAP_ALL_ACCESS, 0);
206   /* Get View */
207   pMapped = MapViewOfFile(hDup, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
208   CloseHandle(hDup);
209
210   if (pMapped)
211     return (char *) pMapped + sizeof(DWORD); /* Hide size */
212   return NULL;
213 }
214
215 /*************************************************************************
216  * @ [SHLWAPI.9]
217  *
218  * Release a pointer to a block of shared memory.
219  *
220  * PARAMS
221  * lpView [I] Shared memory pointer
222  *
223  * RETURNS
224  * Success: TRUE
225  * Failure: FALSE
226  *
227  */
228 BOOL WINAPI SHUnlockShared(LPVOID lpView)
229 {
230   TRACE("(%p)\n", lpView);
231   return UnmapViewOfFile((char *) lpView - sizeof(DWORD)); /* Include size */
232 }
233
234 /*************************************************************************
235  * @ [SHLWAPI.10]
236  *
237  * Destroy a block of sharable memory.
238  *
239  * PARAMS
240  * hShared  [I] Shared memory handle
241  * dwProcId [I] ID of process owning hShared
242  *
243  * RETURNS
244  * Success: TRUE
245  * Failure: FALSE
246  *
247  */
248 BOOL WINAPI SHFreeShared(HANDLE hShared, DWORD dwProcId)
249 {
250   HANDLE hClose;
251
252   TRACE("(%p %d)\n", hShared, dwProcId);
253
254   /* Get a copy of the handle for our process, closing the source handle */
255   hClose = SHLWAPI_DupSharedHandle(hShared, dwProcId, GetCurrentProcessId(),
256                                    FILE_MAP_ALL_ACCESS,DUPLICATE_CLOSE_SOURCE);
257   /* Close local copy */
258   return CloseHandle(hClose);
259 }
260
261 /*************************************************************************
262  * @   [SHLWAPI.11]
263  *
264  * Copy a sharable memory handle from one process to another.
265  *
266  * PARAMS
267  * hShared     [I] Shared memory handle to duplicate
268  * dwDstProcId [I] ID of the process wanting the duplicated handle
269  * dwSrcProcId [I] ID of the process owning hShared
270  * dwAccess    [I] Desired DuplicateHandle() access
271  * dwOptions   [I] Desired DuplicateHandle() options
272  *
273  * RETURNS
274  * Success: A handle suitable for use by the dwDstProcId process.
275  * Failure: A NULL handle.
276  *
277  */
278 HANDLE WINAPI SHMapHandle(HANDLE hShared, DWORD dwDstProcId, DWORD dwSrcProcId,
279                           DWORD dwAccess, DWORD dwOptions)
280 {
281   HANDLE hRet;
282
283   hRet = SHLWAPI_DupSharedHandle(hShared, dwDstProcId, dwSrcProcId,
284                                  dwAccess, dwOptions);
285   return hRet;
286 }
287
288 /*************************************************************************
289  *      @       [SHLWAPI.13]
290  *
291  * Create and register a clipboard enumerator for a web browser.
292  *
293  * PARAMS
294  *  lpBC      [I] Binding context
295  *  lpUnknown [I] An object exposing the IWebBrowserApp interface
296  *
297  * RETURNS
298  *  Success: S_OK.
299  *  Failure: An HRESULT error code.
300  *
301  * NOTES
302  *  The enumerator is stored as a property of the web browser. If it does not
303  *  yet exist, it is created and set before being registered.
304  */
305 HRESULT WINAPI RegisterDefaultAcceptHeaders(LPBC lpBC, IUnknown *lpUnknown)
306 {
307   static const WCHAR szProperty[] = { '{','D','0','F','C','A','4','2','0',
308       '-','D','3','F','5','-','1','1','C','F', '-','B','2','1','1','-','0',
309       '0','A','A','0','0','4','A','E','8','3','7','}','\0' };
310   BSTR property;
311   IEnumFORMATETC* pIEnumFormatEtc = NULL;
312   VARIANTARG var;
313   HRESULT hr;
314   IWebBrowserApp* pBrowser;
315
316   TRACE("(%p, %p)\n", lpBC, lpUnknown);
317
318   hr = IUnknown_QueryService(lpUnknown, &IID_IWebBrowserApp, &IID_IWebBrowserApp, (void**)&pBrowser);
319   if (FAILED(hr))
320     return hr;
321
322   V_VT(&var) = VT_EMPTY;
323
324   /* The property we get is the browsers clipboard enumerator */
325   property = SysAllocString(szProperty);
326   hr = IWebBrowserApp_GetProperty(pBrowser, property, &var);
327   SysFreeString(property);
328   if (FAILED(hr)) goto exit;
329
330   if (V_VT(&var) == VT_EMPTY)
331   {
332     /* Iterate through accepted documents and RegisterClipBoardFormatA() them */
333     char szKeyBuff[128], szValueBuff[128];
334     DWORD dwKeySize, dwValueSize, dwRet = 0, dwCount = 0, dwNumValues, dwType;
335     FORMATETC* formatList, *format;
336     HKEY hDocs;
337
338     TRACE("Registering formats and creating IEnumFORMATETC instance\n");
339
340     if (!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\Current"
341                      "Version\\Internet Settings\\Accepted Documents", &hDocs))
342     {
343       hr = E_FAIL;
344       goto exit;
345     }
346
347     /* Get count of values in key */
348     while (!dwRet)
349     {
350       dwKeySize = sizeof(szKeyBuff);
351       dwRet = RegEnumValueA(hDocs,dwCount,szKeyBuff,&dwKeySize,0,&dwType,0,0);
352       dwCount++;
353     }
354
355     dwNumValues = dwCount;
356
357     /* Note: dwCount = number of items + 1; The extra item is the end node */
358     format = formatList = HeapAlloc(GetProcessHeap(), 0, dwCount * sizeof(FORMATETC));
359     if (!formatList)
360     {
361       RegCloseKey(hDocs);
362       hr = E_OUTOFMEMORY;
363       goto exit;
364     }
365
366     if (dwNumValues > 1)
367     {
368       dwRet = 0;
369       dwCount = 0;
370
371       dwNumValues--;
372
373       /* Register clipboard formats for the values and populate format list */
374       while(!dwRet && dwCount < dwNumValues)
375       {
376         dwKeySize = sizeof(szKeyBuff);
377         dwValueSize = sizeof(szValueBuff);
378         dwRet = RegEnumValueA(hDocs, dwCount, szKeyBuff, &dwKeySize, 0, &dwType,
379                               (PBYTE)szValueBuff, &dwValueSize);
380         if (!dwRet)
381         {
382           HeapFree(GetProcessHeap(), 0, formatList);
383           RegCloseKey(hDocs);
384           hr = E_FAIL;
385           goto exit;
386         }
387
388         format->cfFormat = RegisterClipboardFormatA(szValueBuff);
389         format->ptd = NULL;
390         format->dwAspect = 1;
391         format->lindex = 4;
392         format->tymed = -1;
393
394         format++;
395         dwCount++;
396       }
397     }
398
399     RegCloseKey(hDocs);
400
401     /* Terminate the (maybe empty) list, last entry has a cfFormat of 0 */
402     format->cfFormat = 0;
403     format->ptd = NULL;
404     format->dwAspect = 1;
405     format->lindex = 4;
406     format->tymed = -1;
407
408     /* Create a clipboard enumerator */
409     hr = CreateFormatEnumerator(dwNumValues, formatList, &pIEnumFormatEtc);
410     HeapFree(GetProcessHeap(), 0, formatList);
411     if (FAILED(hr)) goto exit;
412
413     /* Set our enumerator as the browsers property */
414     V_VT(&var) = VT_UNKNOWN;
415     V_UNKNOWN(&var) = (IUnknown*)pIEnumFormatEtc;
416
417     property = SysAllocString(szProperty);
418     hr = IWebBrowserApp_PutProperty(pBrowser, property, var);
419     SysFreeString(property);
420     if (FAILED(hr))
421     {
422        IEnumFORMATETC_Release(pIEnumFormatEtc);
423        goto exit;
424     }
425   }
426
427   if (V_VT(&var) == VT_UNKNOWN)
428   {
429     /* Our variant is holding the clipboard enumerator */
430     IUnknown* pIUnknown = V_UNKNOWN(&var);
431     IEnumFORMATETC* pClone = NULL;
432
433     TRACE("Retrieved IEnumFORMATETC property\n");
434
435     /* Get an IEnumFormatEtc interface from the variants value */
436     pIEnumFormatEtc = NULL;
437     hr = IUnknown_QueryInterface(pIUnknown, &IID_IEnumFORMATETC, (void**)&pIEnumFormatEtc);
438     if (hr == S_OK && pIEnumFormatEtc)
439     {
440       /* Clone and register the enumerator */
441       hr = IEnumFORMATETC_Clone(pIEnumFormatEtc, &pClone);
442       if (hr == S_OK && pClone)
443       {
444         RegisterFormatEnumerator(lpBC, pClone, 0);
445
446         IEnumFORMATETC_Release(pClone);
447       }
448
449       IEnumFORMATETC_Release(pIUnknown);
450     }
451     IUnknown_Release(V_UNKNOWN(&var));
452   }
453
454 exit:
455   IWebBrowserApp_Release(pBrowser);
456   return hr;
457 }
458
459 /*************************************************************************
460  *      @       [SHLWAPI.15]
461  *
462  * Get Explorers "AcceptLanguage" setting.
463  *
464  * PARAMS
465  *  langbuf [O] Destination for language string
466  *  buflen  [I] Length of langbuf in characters
467  *          [0] Success: used length of langbuf
468  *
469  * RETURNS
470  *  Success: S_OK.   langbuf is set to the language string found.
471  *  Failure: E_FAIL, If any arguments are invalid, error occurred, or Explorer
472  *           does not contain the setting.
473  *           HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), If the buffer is not big enough
474  */
475 HRESULT WINAPI GetAcceptLanguagesW( LPWSTR langbuf, LPDWORD buflen)
476 {
477     static const WCHAR szkeyW[] = {
478         'S','o','f','t','w','a','r','e','\\',
479         'M','i','c','r','o','s','o','f','t','\\',
480         'I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r','\\',
481         'I','n','t','e','r','n','a','t','i','o','n','a','l',0};
482     static const WCHAR valueW[] = {
483         'A','c','c','e','p','t','L','a','n','g','u','a','g','e',0};
484     DWORD mystrlen, mytype;
485     DWORD len;
486     HKEY mykey;
487     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 0;
1140
1141   if(hWndParent)
1142     SHSetWindowBits(hWnd, GWL_STYLE, WS_CHILD, WS_CHILD);
1143   else
1144     SHSetWindowBits(hWnd, GWL_STYLE, WS_POPUP, WS_POPUP);
1145
1146   return SetParent(hWnd, hWndParent);
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     /* Lazyness 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,%p)\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             hr = IProfferService_RevokeService(proffer, *pCookie);
1575
1576         IProfferService_Release(proffer);
1577     }
1578
1579     return hr;
1580 }
1581
1582 /*************************************************************************
1583  *      @       [SHLWAPI.479]
1584  *
1585  * Call an object's UIActivateIO method.
1586  *
1587  * PARAMS
1588  *  unknown  [I] Object to call the UIActivateIO method on
1589  *  activate [I] Parameter for UIActivateIO call
1590  *  msg      [I] Parameter for UIActivateIO call
1591  *
1592  * RETURNS
1593  *  Success: Value of UI_ActivateIO call
1594  *  Failure: An HRESULT error code
1595  *
1596  * NOTES
1597  *  unknown is expected to support the IInputObject interface.
1598  */
1599 HRESULT WINAPI IUnknown_UIActivateIO(IUnknown *unknown, BOOL activate, LPMSG msg)
1600 {
1601     IInputObject* object = NULL;
1602     HRESULT ret;
1603
1604     if (!unknown)
1605         return E_FAIL;
1606
1607     /* Get an IInputObject interface from the object */
1608     ret = IUnknown_QueryInterface(unknown, &IID_IInputObject, (LPVOID*) &object);
1609
1610     if (ret == S_OK)
1611     {
1612         ret = IInputObject_UIActivateIO(object, activate, msg);
1613         IUnknown_Release(object);
1614     }
1615
1616     return ret;
1617 }
1618
1619 /*************************************************************************
1620  *      @       [SHLWAPI.177]
1621  *
1622  * Loads a popup menu.
1623  *
1624  * PARAMS
1625  *  hInst  [I] Instance handle
1626  *  szName [I] Menu name
1627  *
1628  * RETURNS
1629  *  Success: TRUE.
1630  *  Failure: FALSE.
1631  */
1632 BOOL WINAPI SHLoadMenuPopup(HINSTANCE hInst, LPCWSTR szName)
1633 {
1634   HMENU hMenu;
1635
1636   TRACE("%p %s\n", hInst, debugstr_w(szName));
1637
1638   if ((hMenu = LoadMenuW(hInst, szName)))
1639   {
1640     if (GetSubMenu(hMenu, 0))
1641       RemoveMenu(hMenu, 0, MF_BYPOSITION);
1642
1643     DestroyMenu(hMenu);
1644     return TRUE;
1645   }
1646   return FALSE;
1647 }
1648
1649 typedef struct _enumWndData
1650 {
1651   UINT   uiMsgId;
1652   WPARAM wParam;
1653   LPARAM lParam;
1654   LRESULT (WINAPI *pfnPost)(HWND,UINT,WPARAM,LPARAM);
1655 } enumWndData;
1656
1657 /* Callback for SHLWAPI_178 */
1658 static BOOL CALLBACK SHLWAPI_EnumChildProc(HWND hWnd, LPARAM lParam)
1659 {
1660   enumWndData *data = (enumWndData *)lParam;
1661
1662   TRACE("(%p,%p)\n", hWnd, data);
1663   data->pfnPost(hWnd, data->uiMsgId, data->wParam, data->lParam);
1664   return TRUE;
1665 }
1666
1667 /*************************************************************************
1668  * @  [SHLWAPI.178]
1669  *
1670  * Send or post a message to every child of a window.
1671  *
1672  * PARAMS
1673  *  hWnd    [I] Window whose children will get the messages
1674  *  uiMsgId [I] Message Id
1675  *  wParam  [I] WPARAM of message
1676  *  lParam  [I] LPARAM of message
1677  *  bSend   [I] TRUE = Use SendMessageA(), FALSE = Use PostMessageA()
1678  *
1679  * RETURNS
1680  *  Nothing.
1681  *
1682  * NOTES
1683  *  The appropriate ASCII or Unicode function is called for the window.
1684  */
1685 void WINAPI SHPropagateMessage(HWND hWnd, UINT uiMsgId, WPARAM wParam, LPARAM lParam, BOOL bSend)
1686 {
1687   enumWndData data;
1688
1689   TRACE("(%p,%u,%ld,%ld,%d)\n", hWnd, uiMsgId, wParam, lParam, bSend);
1690
1691   if(hWnd)
1692   {
1693     data.uiMsgId = uiMsgId;
1694     data.wParam  = wParam;
1695     data.lParam  = lParam;
1696
1697     if (bSend)
1698       data.pfnPost = IsWindowUnicode(hWnd) ? (void*)SendMessageW : (void*)SendMessageA;
1699     else
1700       data.pfnPost = IsWindowUnicode(hWnd) ? (void*)PostMessageW : (void*)PostMessageA;
1701
1702     EnumChildWindows(hWnd, SHLWAPI_EnumChildProc, (LPARAM)&data);
1703   }
1704 }
1705
1706 /*************************************************************************
1707  *      @       [SHLWAPI.180]
1708  *
1709  * Remove all sub-menus from a menu.
1710  *
1711  * PARAMS
1712  *  hMenu [I] Menu to remove sub-menus from
1713  *
1714  * RETURNS
1715  *  Success: 0.  All sub-menus under hMenu are removed
1716  *  Failure: -1, if any parameter is invalid
1717  */
1718 DWORD WINAPI SHRemoveAllSubMenus(HMENU hMenu)
1719 {
1720   int iItemCount = GetMenuItemCount(hMenu) - 1;
1721
1722   TRACE("%p\n", hMenu);
1723
1724   while (iItemCount >= 0)
1725   {
1726     HMENU hSubMenu = GetSubMenu(hMenu, iItemCount);
1727     if (hSubMenu)
1728       RemoveMenu(hMenu, iItemCount, MF_BYPOSITION);
1729     iItemCount--;
1730   }
1731   return iItemCount;
1732 }
1733
1734 /*************************************************************************
1735  *      @       [SHLWAPI.181]
1736  *
1737  * Enable or disable a menu item.
1738  *
1739  * PARAMS
1740  *  hMenu   [I] Menu holding menu item
1741  *  uID     [I] ID of menu item to enable/disable
1742  *  bEnable [I] Whether to enable (TRUE) or disable (FALSE) the item.
1743  *
1744  * RETURNS
1745  *  The return code from EnableMenuItem.
1746  */
1747 UINT WINAPI SHEnableMenuItem(HMENU hMenu, UINT wItemID, BOOL bEnable)
1748 {
1749   TRACE("%p, %u, %d\n", hMenu, wItemID, bEnable);
1750   return EnableMenuItem(hMenu, wItemID, bEnable ? MF_ENABLED : MF_GRAYED);
1751 }
1752
1753 /*************************************************************************
1754  * @    [SHLWAPI.182]
1755  *
1756  * Check or uncheck a menu item.
1757  *
1758  * PARAMS
1759  *  hMenu  [I] Menu holding menu item
1760  *  uID    [I] ID of menu item to check/uncheck
1761  *  bCheck [I] Whether to check (TRUE) or uncheck (FALSE) the item.
1762  *
1763  * RETURNS
1764  *  The return code from CheckMenuItem.
1765  */
1766 DWORD WINAPI SHCheckMenuItem(HMENU hMenu, UINT uID, BOOL bCheck)
1767 {
1768   TRACE("%p, %u, %d\n", hMenu, uID, bCheck);
1769   return CheckMenuItem(hMenu, uID, bCheck ? MF_CHECKED : MF_UNCHECKED);
1770 }
1771
1772 /*************************************************************************
1773  *      @       [SHLWAPI.183]
1774  *
1775  * Register a window class if it isn't already.
1776  *
1777  * PARAMS
1778  *  lpWndClass [I] Window class to register
1779  *
1780  * RETURNS
1781  *  The result of the RegisterClassA call.
1782  */
1783 DWORD WINAPI SHRegisterClassA(WNDCLASSA *wndclass)
1784 {
1785   WNDCLASSA wca;
1786   if (GetClassInfoA(wndclass->hInstance, wndclass->lpszClassName, &wca))
1787     return TRUE;
1788   return (DWORD)RegisterClassA(wndclass);
1789 }
1790
1791 /*************************************************************************
1792  *      @       [SHLWAPI.186]
1793  */
1794 BOOL WINAPI SHSimulateDrop(IDropTarget *pDrop, IDataObject *pDataObj,
1795                            DWORD grfKeyState, PPOINTL lpPt, DWORD* pdwEffect)
1796 {
1797   DWORD dwEffect = DROPEFFECT_LINK | DROPEFFECT_MOVE | DROPEFFECT_COPY;
1798   POINTL pt = { 0, 0 };
1799
1800   TRACE("%p %p 0x%08x %p %p\n", pDrop, pDataObj, grfKeyState, lpPt, pdwEffect);
1801
1802   if (!lpPt)
1803     lpPt = &pt;
1804
1805   if (!pdwEffect)
1806     pdwEffect = &dwEffect;
1807
1808   IDropTarget_DragEnter(pDrop, pDataObj, grfKeyState, *lpPt, pdwEffect);
1809
1810   if (*pdwEffect != DROPEFFECT_NONE)
1811     return IDropTarget_Drop(pDrop, pDataObj, grfKeyState, *lpPt, pdwEffect);
1812
1813   IDropTarget_DragLeave(pDrop);
1814   return TRUE;
1815 }
1816
1817 /*************************************************************************
1818  *      @       [SHLWAPI.187]
1819  *
1820  * Call IPersistPropertyBag_Load() on an object.
1821  *
1822  * PARAMS
1823  *  lpUnknown [I] Object supporting the IPersistPropertyBag interface
1824  *  lpPropBag [O] Destination for loaded IPropertyBag
1825  *
1826  * RETURNS
1827  *  Success: S_OK.
1828  *  Failure: An HRESULT error code, or E_FAIL if lpUnknown is NULL.
1829  */
1830 DWORD WINAPI SHLoadFromPropertyBag(IUnknown *lpUnknown, IPropertyBag* lpPropBag)
1831 {
1832   IPersistPropertyBag* lpPPBag;
1833   HRESULT hRet = E_FAIL;
1834
1835   TRACE("(%p,%p)\n", lpUnknown, lpPropBag);
1836
1837   if (lpUnknown)
1838   {
1839     hRet = IUnknown_QueryInterface(lpUnknown, &IID_IPersistPropertyBag,
1840                                    (void**)&lpPPBag);
1841     if (SUCCEEDED(hRet) && lpPPBag)
1842     {
1843       hRet = IPersistPropertyBag_Load(lpPPBag, lpPropBag, NULL);
1844       IPersistPropertyBag_Release(lpPPBag);
1845     }
1846   }
1847   return hRet;
1848 }
1849
1850 /*************************************************************************
1851  * @  [SHLWAPI.188]
1852  *
1853  * Call IOleControlSite_TranslateAccelerator()  on an object.
1854  *
1855  * PARAMS
1856  *  lpUnknown   [I] Object supporting the IOleControlSite interface.
1857  *  lpMsg       [I] Key message to be processed.
1858  *  dwModifiers [I] Flags containing the state of the modifier keys.
1859  *
1860  * RETURNS
1861  *  Success: S_OK.
1862  *  Failure: An HRESULT error code, or E_INVALIDARG if lpUnknown is NULL.
1863  */
1864 HRESULT WINAPI IUnknown_TranslateAcceleratorOCS(IUnknown *lpUnknown, LPMSG lpMsg, DWORD dwModifiers)
1865 {
1866   IOleControlSite* lpCSite = NULL;
1867   HRESULT hRet = E_INVALIDARG;
1868
1869   TRACE("(%p,%p,0x%08x)\n", lpUnknown, lpMsg, dwModifiers);
1870   if (lpUnknown)
1871   {
1872     hRet = IUnknown_QueryInterface(lpUnknown, &IID_IOleControlSite,
1873                                    (void**)&lpCSite);
1874     if (SUCCEEDED(hRet) && lpCSite)
1875     {
1876       hRet = IOleControlSite_TranslateAccelerator(lpCSite, lpMsg, dwModifiers);
1877       IOleControlSite_Release(lpCSite);
1878     }
1879   }
1880   return hRet;
1881 }
1882
1883
1884 /*************************************************************************
1885  * @  [SHLWAPI.189]
1886  *
1887  * Call IOleControlSite_OnFocus() on an object.
1888  *
1889  * PARAMS
1890  *  lpUnknown [I] Object supporting the IOleControlSite interface.
1891  *  fGotFocus [I] Whether focus was gained (TRUE) or lost (FALSE).
1892  *
1893  * RETURNS
1894  *  Success: S_OK.
1895  *  Failure: An HRESULT error code, or E_FAIL if lpUnknown is NULL.
1896  */
1897 HRESULT WINAPI IUnknown_OnFocusOCS(IUnknown *lpUnknown, BOOL fGotFocus)
1898 {
1899   IOleControlSite* lpCSite = NULL;
1900   HRESULT hRet = E_FAIL;
1901
1902   TRACE("(%p, %d)\n", lpUnknown, fGotFocus);
1903   if (lpUnknown)
1904   {
1905     hRet = IUnknown_QueryInterface(lpUnknown, &IID_IOleControlSite,
1906                                    (void**)&lpCSite);
1907     if (SUCCEEDED(hRet) && lpCSite)
1908     {
1909       hRet = IOleControlSite_OnFocus(lpCSite, fGotFocus);
1910       IOleControlSite_Release(lpCSite);
1911     }
1912   }
1913   return hRet;
1914 }
1915
1916 /*************************************************************************
1917  * @    [SHLWAPI.190]
1918  */
1919 HRESULT WINAPI IUnknown_HandleIRestrict(LPUNKNOWN lpUnknown, PVOID lpArg1,
1920                                         PVOID lpArg2, PVOID lpArg3, PVOID lpArg4)
1921 {
1922   /* FIXME: {D12F26B2-D90A-11D0-830D-00AA005B4383} - What object does this represent? */
1923   static const DWORD service_id[] = { 0xd12f26b2, 0x11d0d90a, 0xaa000d83, 0x83435b00 };
1924   /* FIXME: {D12F26B1-D90A-11D0-830D-00AA005B4383} - Also Unknown/undocumented */
1925   static const DWORD function_id[] = { 0xd12f26b1, 0x11d0d90a, 0xaa000d83, 0x83435b00 };
1926   HRESULT hRet = E_INVALIDARG;
1927   LPUNKNOWN lpUnkInner = NULL; /* FIXME: Real type is unknown */
1928
1929   TRACE("(%p,%p,%p,%p,%p)\n", lpUnknown, lpArg1, lpArg2, lpArg3, lpArg4);
1930
1931   if (lpUnknown && lpArg4)
1932   {
1933      hRet = IUnknown_QueryService(lpUnknown, (REFGUID)service_id,
1934                                   (REFGUID)function_id, (void**)&lpUnkInner);
1935
1936      if (SUCCEEDED(hRet) && lpUnkInner)
1937      {
1938        /* FIXME: The type of service object requested is unknown, however
1939         * testing shows that its first method is called with 4 parameters.
1940         * Fake this by using IParseDisplayName_ParseDisplayName since the
1941         * signature and position in the vtable matches our unknown object type.
1942         */
1943        hRet = IParseDisplayName_ParseDisplayName((LPPARSEDISPLAYNAME)lpUnkInner,
1944                                                  lpArg1, lpArg2, lpArg3, lpArg4);
1945        IUnknown_Release(lpUnkInner);
1946      }
1947   }
1948   return hRet;
1949 }
1950
1951 /*************************************************************************
1952  * @    [SHLWAPI.192]
1953  *
1954  * Get a sub-menu from a menu item.
1955  *
1956  * PARAMS
1957  *  hMenu [I] Menu to get sub-menu from
1958  *  uID   [I] ID of menu item containing sub-menu
1959  *
1960  * RETURNS
1961  *  The sub-menu of the item, or a NULL handle if any parameters are invalid.
1962  */
1963 HMENU WINAPI SHGetMenuFromID(HMENU hMenu, UINT uID)
1964 {
1965   MENUITEMINFOW mi;
1966
1967   TRACE("(%p,%u)\n", hMenu, uID);
1968
1969   mi.cbSize = sizeof(mi);
1970   mi.fMask = MIIM_SUBMENU;
1971
1972   if (!GetMenuItemInfoW(hMenu, uID, FALSE, &mi))
1973     return NULL;
1974
1975   return mi.hSubMenu;
1976 }
1977
1978 /*************************************************************************
1979  *      @       [SHLWAPI.193]
1980  *
1981  * Get the color depth of the primary display.
1982  *
1983  * PARAMS
1984  *  None.
1985  *
1986  * RETURNS
1987  *  The color depth of the primary display.
1988  */
1989 DWORD WINAPI SHGetCurColorRes(void)
1990 {
1991     HDC hdc;
1992     DWORD ret;
1993
1994     TRACE("()\n");
1995
1996     hdc = GetDC(0);
1997     ret = GetDeviceCaps(hdc, BITSPIXEL) * GetDeviceCaps(hdc, PLANES);
1998     ReleaseDC(0, hdc);
1999     return ret;
2000 }
2001
2002 /*************************************************************************
2003  *      @       [SHLWAPI.194]
2004  *
2005  * Wait for a message to arrive, with a timeout.
2006  *
2007  * PARAMS
2008  *  hand      [I] Handle to query
2009  *  dwTimeout [I] Timeout in ticks or INFINITE to never timeout
2010  *
2011  * RETURNS
2012  *  STATUS_TIMEOUT if no message is received before dwTimeout ticks passes.
2013  *  Otherwise returns the value from MsgWaitForMultipleObjectsEx when a
2014  *  message is available.
2015  */
2016 DWORD WINAPI SHWaitForSendMessageThread(HANDLE hand, DWORD dwTimeout)
2017 {
2018   DWORD dwEndTicks = GetTickCount() + dwTimeout;
2019   DWORD dwRet;
2020
2021   while ((dwRet = MsgWaitForMultipleObjectsEx(1, &hand, dwTimeout, QS_SENDMESSAGE, 0)) == 1)
2022   {
2023     MSG msg;
2024
2025     PeekMessageW(&msg, NULL, 0, 0, PM_NOREMOVE);
2026
2027     if (dwTimeout != INFINITE)
2028     {
2029         if ((int)(dwTimeout = dwEndTicks - GetTickCount()) <= 0)
2030             return WAIT_TIMEOUT;
2031     }
2032   }
2033
2034   return dwRet;
2035 }
2036
2037 /*************************************************************************
2038  *      @       [SHLWAPI.195]
2039  *
2040  * Determine if a shell folder can be expanded.
2041  *
2042  * PARAMS
2043  *  lpFolder [I] Parent folder containing the object to test.
2044  *  pidl     [I] Id of the object to test.
2045  *
2046  * RETURNS
2047  *  Success: S_OK, if the object is expandable, S_FALSE otherwise.
2048  *  Failure: E_INVALIDARG, if any argument is invalid.
2049  *
2050  * NOTES
2051  *  If the object to be tested does not expose the IQueryInfo() interface it
2052  *  will not be identified as an expandable folder.
2053  */
2054 HRESULT WINAPI SHIsExpandableFolder(LPSHELLFOLDER lpFolder, LPCITEMIDLIST pidl)
2055 {
2056   HRESULT hRet = E_INVALIDARG;
2057   IQueryInfo *lpInfo;
2058
2059   if (lpFolder && pidl)
2060   {
2061     hRet = IShellFolder_GetUIObjectOf(lpFolder, NULL, 1, &pidl, &IID_IQueryInfo,
2062                                       NULL, (void**)&lpInfo);
2063     if (FAILED(hRet))
2064       hRet = S_FALSE; /* Doesn't expose IQueryInfo */
2065     else
2066     {
2067       DWORD dwFlags = 0;
2068
2069       /* MSDN states of IQueryInfo_GetInfoFlags() that "This method is not
2070        * currently used". Really? You wouldn't be holding out on me would you?
2071        */
2072       hRet = IQueryInfo_GetInfoFlags(lpInfo, &dwFlags);
2073
2074       if (SUCCEEDED(hRet))
2075       {
2076         /* 0x2 is an undocumented flag apparently indicating expandability */
2077         hRet = dwFlags & 0x2 ? S_OK : S_FALSE;
2078       }
2079
2080       IQueryInfo_Release(lpInfo);
2081     }
2082   }
2083   return hRet;
2084 }
2085
2086 /*************************************************************************
2087  *      @       [SHLWAPI.197]
2088  *
2089  * Blank out a region of text by drawing the background only.
2090  *
2091  * PARAMS
2092  *  hDC   [I] Device context to draw in
2093  *  pRect [I] Area to draw in
2094  *  cRef  [I] Color to draw in
2095  *
2096  * RETURNS
2097  *  Nothing.
2098  */
2099 DWORD WINAPI SHFillRectClr(HDC hDC, LPCRECT pRect, COLORREF cRef)
2100 {
2101     COLORREF cOldColor = SetBkColor(hDC, cRef);
2102     ExtTextOutA(hDC, 0, 0, ETO_OPAQUE, pRect, 0, 0, 0);
2103     SetBkColor(hDC, cOldColor);
2104     return 0;
2105 }
2106
2107 /*************************************************************************
2108  *      @       [SHLWAPI.198]
2109  *
2110  * Return the value associated with a key in a map.
2111  *
2112  * PARAMS
2113  *  lpKeys   [I] A list of keys of length iLen
2114  *  lpValues [I] A list of values associated with lpKeys, of length iLen
2115  *  iLen     [I] Length of both lpKeys and lpValues
2116  *  iKey     [I] The key value to look up in lpKeys
2117  *
2118  * RETURNS
2119  *  The value in lpValues associated with iKey, or -1 if iKey is not
2120  *  found in lpKeys.
2121  *
2122  * NOTES
2123  *  - If two elements in the map share the same key, this function returns
2124  *    the value closest to the start of the map
2125  *  - The native version of this function crashes if lpKeys or lpValues is NULL.
2126  */
2127 int WINAPI SHSearchMapInt(const int *lpKeys, const int *lpValues, int iLen, int iKey)
2128 {
2129   if (lpKeys && lpValues)
2130   {
2131     int i = 0;
2132
2133     while (i < iLen)
2134     {
2135       if (lpKeys[i] == iKey)
2136         return lpValues[i]; /* Found */
2137       i++;
2138     }
2139   }
2140   return -1; /* Not found */
2141 }
2142
2143
2144 /*************************************************************************
2145  *      @       [SHLWAPI.199]
2146  *
2147  * Copy an interface pointer
2148  *
2149  * PARAMS
2150  *   lppDest   [O] Destination for copy
2151  *   lpUnknown [I] Source for copy
2152  *
2153  * RETURNS
2154  *  Nothing.
2155  */
2156 VOID WINAPI IUnknown_Set(IUnknown **lppDest, IUnknown *lpUnknown)
2157 {
2158   TRACE("(%p,%p)\n", lppDest, lpUnknown);
2159
2160   IUnknown_AtomicRelease(lppDest);
2161
2162   if (lpUnknown)
2163   {
2164     IUnknown_AddRef(lpUnknown);
2165     *lppDest = lpUnknown;
2166   }
2167 }
2168
2169 /*************************************************************************
2170  *      @       [SHLWAPI.200]
2171  *
2172  */
2173 HRESULT WINAPI MayQSForward(IUnknown* lpUnknown, PVOID lpReserved,
2174                             REFGUID riidCmdGrp, ULONG cCmds,
2175                             OLECMD *prgCmds, OLECMDTEXT* pCmdText)
2176 {
2177   FIXME("(%p,%p,%p,%d,%p,%p) - stub\n",
2178         lpUnknown, lpReserved, riidCmdGrp, cCmds, prgCmds, pCmdText);
2179
2180   /* FIXME: Calls IsQSForward & IUnknown_QueryStatus */
2181   return DRAGDROP_E_NOTREGISTERED;
2182 }
2183
2184 /*************************************************************************
2185  *      @       [SHLWAPI.201]
2186  *
2187  */
2188 HRESULT WINAPI MayExecForward(IUnknown* lpUnknown, INT iUnk, REFGUID pguidCmdGroup,
2189                            DWORD nCmdID, DWORD nCmdexecopt, VARIANT* pvaIn,
2190                            VARIANT* pvaOut)
2191 {
2192   FIXME("(%p,%d,%p,%d,%d,%p,%p) - stub!\n", lpUnknown, iUnk, pguidCmdGroup,
2193         nCmdID, nCmdexecopt, pvaIn, pvaOut);
2194   return DRAGDROP_E_NOTREGISTERED;
2195 }
2196
2197 /*************************************************************************
2198  *      @       [SHLWAPI.202]
2199  *
2200  */
2201 HRESULT WINAPI IsQSForward(REFGUID pguidCmdGroup,ULONG cCmds, OLECMD *prgCmds)
2202 {
2203   FIXME("(%p,%d,%p) - stub!\n", pguidCmdGroup, cCmds, prgCmds);
2204   return DRAGDROP_E_NOTREGISTERED;
2205 }
2206
2207 /*************************************************************************
2208  * @    [SHLWAPI.204]
2209  *
2210  * Determine if a window is not a child of another window.
2211  *
2212  * PARAMS
2213  * hParent [I] Suspected parent window
2214  * hChild  [I] Suspected child window
2215  *
2216  * RETURNS
2217  * TRUE:  If hChild is a child window of hParent
2218  * FALSE: If hChild is not a child window of hParent, or they are equal
2219  */
2220 BOOL WINAPI SHIsChildOrSelf(HWND hParent, HWND hChild)
2221 {
2222   TRACE("(%p,%p)\n", hParent, hChild);
2223
2224   if (!hParent || !hChild)
2225     return TRUE;
2226   else if(hParent == hChild)
2227     return FALSE;
2228   return !IsChild(hParent, hChild);
2229 }
2230
2231 /*************************************************************************
2232  *    FDSA functions.  Manage a dynamic array of fixed size memory blocks.
2233  */
2234
2235 typedef struct
2236 {
2237     DWORD num_items;       /* Number of elements inserted */
2238     void *mem;             /* Ptr to array */
2239     DWORD blocks_alloced;  /* Number of elements allocated */
2240     BYTE inc;              /* Number of elements to grow by when we need to expand */
2241     BYTE block_size;       /* Size in bytes of an element */
2242     BYTE flags;            /* Flags */
2243 } FDSA_info;
2244
2245 #define FDSA_FLAG_INTERNAL_ALLOC 0x01 /* When set we have allocated mem internally */
2246
2247 /*************************************************************************
2248  *      @       [SHLWAPI.208]
2249  *
2250  * Initialize an FDSA array.
2251  */
2252 BOOL WINAPI FDSA_Initialize(DWORD block_size, DWORD inc, FDSA_info *info, void *mem,
2253                             DWORD init_blocks)
2254 {
2255     TRACE("(0x%08x 0x%08x %p %p 0x%08x)\n", block_size, inc, info, mem, init_blocks);
2256
2257     if(inc == 0)
2258         inc = 1;
2259
2260     if(mem)
2261         memset(mem, 0, block_size * init_blocks);
2262     
2263     info->num_items = 0;
2264     info->inc = inc;
2265     info->mem = mem;
2266     info->blocks_alloced = init_blocks;
2267     info->block_size = block_size;
2268     info->flags = 0;
2269
2270     return TRUE;
2271 }
2272
2273 /*************************************************************************
2274  *      @       [SHLWAPI.209]
2275  *
2276  * Destroy an FDSA array
2277  */
2278 BOOL WINAPI FDSA_Destroy(FDSA_info *info)
2279 {
2280     TRACE("(%p)\n", info);
2281
2282     if(info->flags & FDSA_FLAG_INTERNAL_ALLOC)
2283     {
2284         HeapFree(GetProcessHeap(), 0, info->mem);
2285         return FALSE;
2286     }
2287
2288     return TRUE;
2289 }
2290
2291 /*************************************************************************
2292  *      @       [SHLWAPI.210]
2293  *
2294  * Insert element into an FDSA array
2295  */
2296 DWORD WINAPI FDSA_InsertItem(FDSA_info *info, DWORD where, const void *block)
2297 {
2298     TRACE("(%p 0x%08x %p)\n", info, where, block);
2299     if(where > info->num_items)
2300         where = info->num_items;
2301
2302     if(info->num_items >= info->blocks_alloced)
2303     {
2304         DWORD size = (info->blocks_alloced + info->inc) * info->block_size;
2305         if(info->flags & 0x1)
2306             info->mem = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, info->mem, size);
2307         else
2308         {
2309             void *old_mem = info->mem;
2310             info->mem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2311             memcpy(info->mem, old_mem, info->blocks_alloced * info->block_size);
2312         }
2313         info->blocks_alloced += info->inc;
2314         info->flags |= 0x1;
2315     }
2316
2317     if(where < info->num_items)
2318     {
2319         memmove((char*)info->mem + (where + 1) * info->block_size,
2320                 (char*)info->mem + where * info->block_size,
2321                 (info->num_items - where) * info->block_size);
2322     }
2323     memcpy((char*)info->mem + where * info->block_size, block, info->block_size);
2324
2325     info->num_items++;
2326     return where;
2327 }
2328
2329 /*************************************************************************
2330  *      @       [SHLWAPI.211]
2331  *
2332  * Delete an element from an FDSA array.
2333  */
2334 BOOL WINAPI FDSA_DeleteItem(FDSA_info *info, DWORD where)
2335 {
2336     TRACE("(%p 0x%08x)\n", info, where);
2337
2338     if(where >= info->num_items)
2339         return FALSE;
2340
2341     if(where < info->num_items - 1)
2342     {
2343         memmove((char*)info->mem + where * info->block_size,
2344                 (char*)info->mem + (where + 1) * info->block_size,
2345                 (info->num_items - where - 1) * info->block_size);
2346     }
2347     memset((char*)info->mem + (info->num_items - 1) * info->block_size,
2348            0, info->block_size);
2349     info->num_items--;
2350     return TRUE;
2351 }
2352
2353 /*************************************************************************
2354  *      @       [SHLWAPI.219]
2355  *
2356  * Call IUnknown_QueryInterface() on a table of objects.
2357  *
2358  * RETURNS
2359  *  Success: S_OK.
2360  *  Failure: E_POINTER or E_NOINTERFACE.
2361  */
2362 HRESULT WINAPI QISearch(
2363         void *base,         /* [in]   Table of interfaces */
2364         const QITAB *table, /* [in]   Array of REFIIDs and indexes into the table */
2365         REFIID riid,        /* [in]   REFIID to get interface for */
2366         void **ppv)         /* [out]  Destination for interface pointer */
2367 {
2368         HRESULT ret;
2369         IUnknown *a_vtbl;
2370         const QITAB *xmove;
2371
2372         TRACE("(%p %p %s %p)\n", base, table, debugstr_guid(riid), ppv);
2373         if (ppv) {
2374             xmove = table;
2375             while (xmove->piid) {
2376                 TRACE("trying (offset %d) %s\n", xmove->dwOffset, debugstr_guid(xmove->piid));
2377                 if (IsEqualIID(riid, xmove->piid)) {
2378                     a_vtbl = (IUnknown*)(xmove->dwOffset + (LPBYTE)base);
2379                     TRACE("matched, returning (%p)\n", a_vtbl);
2380                     *ppv = a_vtbl;
2381                     IUnknown_AddRef(a_vtbl);
2382                     return S_OK;
2383                 }
2384                 xmove++;
2385             }
2386
2387             if (IsEqualIID(riid, &IID_IUnknown)) {
2388                 a_vtbl = (IUnknown*)(table->dwOffset + (LPBYTE)base);
2389                 TRACE("returning first for IUnknown (%p)\n", a_vtbl);
2390                 *ppv = a_vtbl;
2391                 IUnknown_AddRef(a_vtbl);
2392                 return S_OK;
2393             }
2394             *ppv = 0;
2395             ret = E_NOINTERFACE;
2396         } else
2397             ret = E_POINTER;
2398
2399         TRACE("-- 0x%08x\n", ret);
2400         return ret;
2401 }
2402
2403 /*************************************************************************
2404  * @ [SHLWAPI.220]
2405  *
2406  * Set the Font for a window and the "PropDlgFont" property of the parent window.
2407  *
2408  * PARAMS
2409  *  hWnd [I] Parent Window to set the property
2410  *  id   [I] Index of child Window to set the Font
2411  *
2412  * RETURNS
2413  *  Success: S_OK
2414  *
2415  */
2416 HRESULT WINAPI SHSetDefaultDialogFont(HWND hWnd, INT id)
2417 {
2418     FIXME("(%p, %d) stub\n", hWnd, id);
2419     return S_OK;
2420 }
2421
2422 /*************************************************************************
2423  *      @       [SHLWAPI.221]
2424  *
2425  * Remove the "PropDlgFont" property from a window.
2426  *
2427  * PARAMS
2428  *  hWnd [I] Window to remove the property from
2429  *
2430  * RETURNS
2431  *  A handle to the removed property, or NULL if it did not exist.
2432  */
2433 HANDLE WINAPI SHRemoveDefaultDialogFont(HWND hWnd)
2434 {
2435   HANDLE hProp;
2436
2437   TRACE("(%p)\n", hWnd);
2438
2439   hProp = GetPropA(hWnd, "PropDlgFont");
2440
2441   if(hProp)
2442   {
2443     DeleteObject(hProp);
2444     hProp = RemovePropA(hWnd, "PropDlgFont");
2445   }
2446   return hProp;
2447 }
2448
2449 /*************************************************************************
2450  *      @       [SHLWAPI.236]
2451  *
2452  * Load the in-process server of a given GUID.
2453  *
2454  * PARAMS
2455  *  refiid [I] GUID of the server to load.
2456  *
2457  * RETURNS
2458  *  Success: A handle to the loaded server dll.
2459  *  Failure: A NULL handle.
2460  */
2461 HMODULE WINAPI SHPinDllOfCLSID(REFIID refiid)
2462 {
2463     HKEY newkey;
2464     DWORD type, count;
2465     CHAR value[MAX_PATH], string[MAX_PATH];
2466
2467     strcpy(string, "CLSID\\");
2468     SHStringFromGUIDA(refiid, string + 6, sizeof(string)/sizeof(char) - 6);
2469     strcat(string, "\\InProcServer32");
2470
2471     count = MAX_PATH;
2472     RegOpenKeyExA(HKEY_CLASSES_ROOT, string, 0, 1, &newkey);
2473     RegQueryValueExA(newkey, 0, 0, &type, (PBYTE)value, &count);
2474     RegCloseKey(newkey);
2475     return LoadLibraryExA(value, 0, 0);
2476 }
2477
2478 /*************************************************************************
2479  *      @       [SHLWAPI.237]
2480  *
2481  * Unicode version of SHLWAPI_183.
2482  */
2483 DWORD WINAPI SHRegisterClassW(WNDCLASSW * lpWndClass)
2484 {
2485         WNDCLASSW WndClass;
2486
2487         TRACE("(%p %s)\n",lpWndClass->hInstance, debugstr_w(lpWndClass->lpszClassName));
2488
2489         if (GetClassInfoW(lpWndClass->hInstance, lpWndClass->lpszClassName, &WndClass))
2490                 return TRUE;
2491         return RegisterClassW(lpWndClass);
2492 }
2493
2494 /*************************************************************************
2495  *      @       [SHLWAPI.238]
2496  *
2497  * Unregister a list of classes.
2498  *
2499  * PARAMS
2500  *  hInst      [I] Application instance that registered the classes
2501  *  lppClasses [I] List of class names
2502  *  iCount     [I] Number of names in lppClasses
2503  *
2504  * RETURNS
2505  *  Nothing.
2506  */
2507 void WINAPI SHUnregisterClassesA(HINSTANCE hInst, LPCSTR *lppClasses, INT iCount)
2508 {
2509   WNDCLASSA WndClass;
2510
2511   TRACE("(%p,%p,%d)\n", hInst, lppClasses, iCount);
2512
2513   while (iCount > 0)
2514   {
2515     if (GetClassInfoA(hInst, *lppClasses, &WndClass))
2516       UnregisterClassA(*lppClasses, hInst);
2517     lppClasses++;
2518     iCount--;
2519   }
2520 }
2521
2522 /*************************************************************************
2523  *      @       [SHLWAPI.239]
2524  *
2525  * Unicode version of SHUnregisterClassesA.
2526  */
2527 void WINAPI SHUnregisterClassesW(HINSTANCE hInst, LPCWSTR *lppClasses, INT iCount)
2528 {
2529   WNDCLASSW WndClass;
2530
2531   TRACE("(%p,%p,%d)\n", hInst, lppClasses, iCount);
2532
2533   while (iCount > 0)
2534   {
2535     if (GetClassInfoW(hInst, *lppClasses, &WndClass))
2536       UnregisterClassW(*lppClasses, hInst);
2537     lppClasses++;
2538     iCount--;
2539   }
2540 }
2541
2542 /*************************************************************************
2543  *      @       [SHLWAPI.240]
2544  *
2545  * Call The correct (Ascii/Unicode) default window procedure for a window.
2546  *
2547  * PARAMS
2548  *  hWnd     [I] Window to call the default procedure for
2549  *  uMessage [I] Message ID
2550  *  wParam   [I] WPARAM of message
2551  *  lParam   [I] LPARAM of message
2552  *
2553  * RETURNS
2554  *  The result of calling DefWindowProcA() or DefWindowProcW().
2555  */
2556 LRESULT CALLBACK SHDefWindowProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
2557 {
2558         if (IsWindowUnicode(hWnd))
2559                 return DefWindowProcW(hWnd, uMessage, wParam, lParam);
2560         return DefWindowProcA(hWnd, uMessage, wParam, lParam);
2561 }
2562
2563 /*************************************************************************
2564  *      @       [SHLWAPI.256]
2565  */
2566 HRESULT WINAPI IUnknown_GetSite(LPUNKNOWN lpUnknown, REFIID iid, PVOID *lppSite)
2567 {
2568   HRESULT hRet = E_INVALIDARG;
2569   LPOBJECTWITHSITE lpSite = NULL;
2570
2571   TRACE("(%p,%s,%p)\n", lpUnknown, debugstr_guid(iid), lppSite);
2572
2573   if (lpUnknown && iid && lppSite)
2574   {
2575     hRet = IUnknown_QueryInterface(lpUnknown, &IID_IObjectWithSite,
2576                                    (void**)&lpSite);
2577     if (SUCCEEDED(hRet) && lpSite)
2578     {
2579       hRet = IObjectWithSite_GetSite(lpSite, iid, lppSite);
2580       IObjectWithSite_Release(lpSite);
2581     }
2582   }
2583   return hRet;
2584 }
2585
2586 /*************************************************************************
2587  *      @       [SHLWAPI.257]
2588  *
2589  * Create a worker window using CreateWindowExA().
2590  *
2591  * PARAMS
2592  *  wndProc    [I] Window procedure
2593  *  hWndParent [I] Parent window
2594  *  dwExStyle  [I] Extra style flags
2595  *  dwStyle    [I] Style flags
2596  *  hMenu      [I] Window menu
2597  *  wnd_extra  [I] Window extra bytes value
2598  *
2599  * RETURNS
2600  *  Success: The window handle of the newly created window.
2601  *  Failure: 0.
2602  */
2603 HWND WINAPI SHCreateWorkerWindowA(LONG wndProc, HWND hWndParent, DWORD dwExStyle,
2604                                   DWORD dwStyle, HMENU hMenu, LONG_PTR wnd_extra)
2605 {
2606   static const char szClass[] = "WorkerA";
2607   WNDCLASSA wc;
2608   HWND hWnd;
2609
2610   TRACE("(0x%08x, %p, 0x%08x, 0x%08x, %p, 0x%08lx)\n",
2611          wndProc, hWndParent, dwExStyle, dwStyle, hMenu, wnd_extra);
2612
2613   /* Create Window class */
2614   wc.style         = 0;
2615   wc.lpfnWndProc   = DefWindowProcA;
2616   wc.cbClsExtra    = 0;
2617   wc.cbWndExtra    = sizeof(LONG_PTR);
2618   wc.hInstance     = shlwapi_hInstance;
2619   wc.hIcon         = NULL;
2620   wc.hCursor       = LoadCursorA(NULL, (LPSTR)IDC_ARROW);
2621   wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
2622   wc.lpszMenuName  = NULL;
2623   wc.lpszClassName = szClass;
2624
2625   SHRegisterClassA(&wc);
2626
2627   hWnd = CreateWindowExA(dwExStyle, szClass, 0, dwStyle, 0, 0, 0, 0,
2628                          hWndParent, hMenu, shlwapi_hInstance, 0);
2629   if (hWnd)
2630   {
2631     SetWindowLongPtrW(hWnd, 0, wnd_extra);
2632
2633     if (wndProc) SetWindowLongPtrA(hWnd, GWLP_WNDPROC, wndProc);
2634   }
2635
2636   return hWnd;
2637 }
2638
2639 typedef struct tagPOLICYDATA
2640 {
2641   DWORD policy;        /* flags value passed to SHRestricted */
2642   LPCWSTR appstr;      /* application str such as "Explorer" */
2643   LPCWSTR keystr;      /* name of the actual registry key / policy */
2644 } POLICYDATA, *LPPOLICYDATA;
2645
2646 #define SHELL_NO_POLICY 0xffffffff
2647
2648 /* default shell policy registry key */
2649 static const WCHAR strRegistryPolicyW[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o',
2650                                       's','o','f','t','\\','W','i','n','d','o','w','s','\\',
2651                                       'C','u','r','r','e','n','t','V','e','r','s','i','o','n',
2652                                       '\\','P','o','l','i','c','i','e','s',0};
2653
2654 /*************************************************************************
2655  * @                          [SHLWAPI.271]
2656  *
2657  * Retrieve a policy value from the registry.
2658  *
2659  * PARAMS
2660  *  lpSubKey   [I]   registry key name
2661  *  lpSubName  [I]   subname of registry key
2662  *  lpValue    [I]   value name of registry value
2663  *
2664  * RETURNS
2665  *  the value associated with the registry key or 0 if not found
2666  */
2667 DWORD WINAPI SHGetRestriction(LPCWSTR lpSubKey, LPCWSTR lpSubName, LPCWSTR lpValue)
2668 {
2669         DWORD retval, datsize = sizeof(retval);
2670         HKEY hKey;
2671
2672         if (!lpSubKey)
2673           lpSubKey = strRegistryPolicyW;
2674
2675         retval = RegOpenKeyW(HKEY_LOCAL_MACHINE, lpSubKey, &hKey);
2676     if (retval != ERROR_SUCCESS)
2677           retval = RegOpenKeyW(HKEY_CURRENT_USER, lpSubKey, &hKey);
2678         if (retval != ERROR_SUCCESS)
2679           return 0;
2680
2681         SHGetValueW(hKey, lpSubName, lpValue, NULL, &retval, &datsize);
2682         RegCloseKey(hKey);
2683         return retval;
2684 }
2685
2686 /*************************************************************************
2687  * @                         [SHLWAPI.266]
2688  *
2689  * Helper function to retrieve the possibly cached value for a specific policy
2690  *
2691  * PARAMS
2692  *  policy     [I]   The policy to look for
2693  *  initial    [I]   Main registry key to open, if NULL use default
2694  *  polTable   [I]   Table of known policies, 0 terminated
2695  *  polArr     [I]   Cache array of policy values
2696  *
2697  * RETURNS
2698  *  The retrieved policy value or 0 if not successful
2699  *
2700  * NOTES
2701  *  This function is used by the native SHRestricted function to search for the
2702  *  policy and cache it once retrieved. The current Wine implementation uses a
2703  *  different POLICYDATA structure and implements a similar algorithm adapted to
2704  *  that structure.
2705  */
2706 DWORD WINAPI SHRestrictionLookup(
2707         DWORD policy,
2708         LPCWSTR initial,
2709         LPPOLICYDATA polTable,
2710         LPDWORD polArr)
2711 {
2712         TRACE("(0x%08x %s %p %p)\n", policy, debugstr_w(initial), polTable, polArr);
2713
2714         if (!polTable || !polArr)
2715           return 0;
2716
2717         for (;polTable->policy; polTable++, polArr++)
2718         {
2719           if (policy == polTable->policy)
2720           {
2721             /* we have a known policy */
2722
2723             /* check if this policy has been cached */
2724                 if (*polArr == SHELL_NO_POLICY)
2725               *polArr = SHGetRestriction(initial, polTable->appstr, polTable->keystr);
2726             return *polArr;
2727           }
2728         }
2729         /* we don't know this policy, return 0 */
2730         TRACE("unknown policy: (%08x)\n", policy);
2731         return 0;
2732 }
2733
2734 /*************************************************************************
2735  *      @       [SHLWAPI.267]
2736  *
2737  * Get an interface from an object.
2738  *
2739  * RETURNS
2740  *  Success: S_OK. ppv contains the requested interface.
2741  *  Failure: An HRESULT error code.
2742  *
2743  * NOTES
2744  *   This QueryInterface asks the inner object for an interface. In case
2745  *   of aggregation this request would be forwarded by the inner to the
2746  *   outer object. This function asks the inner object directly for the
2747  *   interface circumventing the forwarding to the outer object.
2748  */
2749 HRESULT WINAPI SHWeakQueryInterface(
2750         IUnknown * pUnk,   /* [in] Outer object */
2751         IUnknown * pInner, /* [in] Inner object */
2752         IID * riid, /* [in] Interface GUID to query for */
2753         LPVOID* ppv) /* [out] Destination for queried interface */
2754 {
2755         HRESULT hret = E_NOINTERFACE;
2756         TRACE("(pUnk=%p pInner=%p\n\tIID:  %s %p)\n",pUnk,pInner,debugstr_guid(riid), ppv);
2757
2758         *ppv = NULL;
2759         if(pUnk && pInner) {
2760             hret = IUnknown_QueryInterface(pInner, riid, ppv);
2761             if (SUCCEEDED(hret)) IUnknown_Release(pUnk);
2762         }
2763         TRACE("-- 0x%08x\n", hret);
2764         return hret;
2765 }
2766
2767 /*************************************************************************
2768  *      @       [SHLWAPI.268]
2769  *
2770  * Move a reference from one interface to another.
2771  *
2772  * PARAMS
2773  *   lpDest     [O] Destination to receive the reference
2774  *   lppUnknown [O] Source to give up the reference to lpDest
2775  *
2776  * RETURNS
2777  *  Nothing.
2778  */
2779 VOID WINAPI SHWeakReleaseInterface(IUnknown *lpDest, IUnknown **lppUnknown)
2780 {
2781   TRACE("(%p,%p)\n", lpDest, lppUnknown);
2782
2783   if (*lppUnknown)
2784   {
2785     /* Copy Reference*/
2786     IUnknown_AddRef(lpDest);
2787     IUnknown_AtomicRelease(lppUnknown); /* Release existing interface */
2788   }
2789 }
2790
2791 /*************************************************************************
2792  *      @       [SHLWAPI.269]
2793  *
2794  * Convert an ASCII string of a CLSID into a CLSID.
2795  *
2796  * PARAMS
2797  *  idstr [I] String representing a CLSID in registry format
2798  *  id    [O] Destination for the converted CLSID
2799  *
2800  * RETURNS
2801  *  Success: TRUE. id contains the converted CLSID.
2802  *  Failure: FALSE.
2803  */
2804 BOOL WINAPI GUIDFromStringA(LPCSTR idstr, CLSID *id)
2805 {
2806   WCHAR wClsid[40];
2807   MultiByteToWideChar(CP_ACP, 0, idstr, -1, wClsid, sizeof(wClsid)/sizeof(WCHAR));
2808   return SUCCEEDED(CLSIDFromString(wClsid, id));
2809 }
2810
2811 /*************************************************************************
2812  *      @       [SHLWAPI.270]
2813  *
2814  * Unicode version of GUIDFromStringA.
2815  */
2816 BOOL WINAPI GUIDFromStringW(LPCWSTR idstr, CLSID *id)
2817 {
2818     return SUCCEEDED(CLSIDFromString((LPCOLESTR)idstr, id));
2819 }
2820
2821 /*************************************************************************
2822  *      @       [SHLWAPI.276]
2823  *
2824  * Determine if the browser is integrated into the shell, and set a registry
2825  * key accordingly.
2826  *
2827  * PARAMS
2828  *  None.
2829  *
2830  * RETURNS
2831  *  1, If the browser is not integrated.
2832  *  2, If the browser is integrated.
2833  *
2834  * NOTES
2835  *  The key "HKLM\Software\Microsoft\Internet Explorer\IntegratedBrowser" is
2836  *  either set to TRUE, or removed depending on whether the browser is deemed
2837  *  to be integrated.
2838  */
2839 DWORD WINAPI WhichPlatform(void)
2840 {
2841   static const char szIntegratedBrowser[] = "IntegratedBrowser";
2842   static DWORD dwState = 0;
2843   HKEY hKey;
2844   DWORD dwRet, dwData, dwSize;
2845   HMODULE hshell32;
2846
2847   if (dwState)
2848     return dwState;
2849
2850   /* If shell32 exports DllGetVersion(), the browser is integrated */
2851   dwState = 1;
2852   hshell32 = LoadLibraryA("shell32.dll");
2853   if (hshell32)
2854   {
2855     FARPROC pDllGetVersion;
2856     pDllGetVersion = GetProcAddress(hshell32, "DllGetVersion");
2857     dwState = pDllGetVersion ? 2 : 1;
2858     FreeLibrary(hshell32);
2859   }
2860
2861   /* Set or delete the key accordingly */
2862   dwRet = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
2863                         "Software\\Microsoft\\Internet Explorer", 0,
2864                          KEY_ALL_ACCESS, &hKey);
2865   if (!dwRet)
2866   {
2867     dwRet = RegQueryValueExA(hKey, szIntegratedBrowser, 0, 0,
2868                              (LPBYTE)&dwData, &dwSize);
2869
2870     if (!dwRet && dwState == 1)
2871     {
2872       /* Value exists but browser is not integrated */
2873       RegDeleteValueA(hKey, szIntegratedBrowser);
2874     }
2875     else if (dwRet && dwState == 2)
2876     {
2877       /* Browser is integrated but value does not exist */
2878       dwData = TRUE;
2879       RegSetValueExA(hKey, szIntegratedBrowser, 0, REG_DWORD,
2880                      (LPBYTE)&dwData, sizeof(dwData));
2881     }
2882     RegCloseKey(hKey);
2883   }
2884   return dwState;
2885 }
2886
2887 /*************************************************************************
2888  *      @       [SHLWAPI.278]
2889  *
2890  * Unicode version of SHCreateWorkerWindowA.
2891  */
2892 HWND WINAPI SHCreateWorkerWindowW(LONG wndProc, HWND hWndParent, DWORD dwExStyle,
2893                         DWORD dwStyle, HMENU hMenu, LONG msg_result)
2894 {
2895   static const WCHAR szClass[] = { 'W', 'o', 'r', 'k', 'e', 'r', 'W', 0 };
2896   WNDCLASSW wc;
2897   HWND hWnd;
2898
2899   TRACE("(0x%08x, %p, 0x%08x, 0x%08x, %p, 0x%08x)\n",
2900          wndProc, hWndParent, dwExStyle, dwStyle, hMenu, msg_result);
2901
2902   /* If our OS is natively ANSI, use the ANSI version */
2903   if (GetVersion() & 0x80000000)  /* not NT */
2904   {
2905     TRACE("fallback to ANSI, ver 0x%08x\n", GetVersion());
2906     return SHCreateWorkerWindowA(wndProc, hWndParent, dwExStyle, dwStyle, hMenu, msg_result);
2907   }
2908
2909   /* Create Window class */
2910   wc.style         = 0;
2911   wc.lpfnWndProc   = DefWindowProcW;
2912   wc.cbClsExtra    = 0;
2913   wc.cbWndExtra    = 4;
2914   wc.hInstance     = shlwapi_hInstance;
2915   wc.hIcon         = NULL;
2916   wc.hCursor       = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
2917   wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
2918   wc.lpszMenuName  = NULL;
2919   wc.lpszClassName = szClass;
2920
2921   SHRegisterClassW(&wc);
2922
2923   hWnd = CreateWindowExW(dwExStyle, szClass, 0, dwStyle, 0, 0, 0, 0,
2924                          hWndParent, hMenu, shlwapi_hInstance, 0);
2925   if (hWnd)
2926   {
2927     SetWindowLongPtrW(hWnd, DWLP_MSGRESULT, msg_result);
2928
2929     if (wndProc) SetWindowLongPtrW(hWnd, GWLP_WNDPROC, wndProc);
2930   }
2931
2932   return hWnd;
2933 }
2934
2935 /*************************************************************************
2936  *      @       [SHLWAPI.279]
2937  *
2938  * Get and show a context menu from a shell folder.
2939  *
2940  * PARAMS
2941  *  hWnd           [I] Window displaying the shell folder
2942  *  lpFolder       [I] IShellFolder interface
2943  *  lpApidl        [I] Id for the particular folder desired
2944  *
2945  * RETURNS
2946  *  Success: S_OK.
2947  *  Failure: An HRESULT error code indicating the error.
2948  */
2949 HRESULT WINAPI SHInvokeDefaultCommand(HWND hWnd, IShellFolder* lpFolder, LPCITEMIDLIST lpApidl)
2950 {
2951     TRACE("%p %p %p\n", hWnd, lpFolder, lpApidl);
2952     return SHInvokeCommand(hWnd, lpFolder, lpApidl, FALSE);
2953 }
2954
2955 /*************************************************************************
2956  *      @       [SHLWAPI.281]
2957  *
2958  * _SHPackDispParamsV
2959  */
2960 HRESULT WINAPI SHPackDispParamsV(DISPPARAMS *params, VARIANTARG *args, UINT cnt, __ms_va_list valist)
2961 {
2962   VARIANTARG *iter;
2963
2964   TRACE("(%p %p %u ...)\n", params, args, cnt);
2965
2966   params->rgvarg = args;
2967   params->rgdispidNamedArgs = NULL;
2968   params->cArgs = cnt;
2969   params->cNamedArgs = 0;
2970
2971   iter = args+cnt;
2972
2973   while(iter-- > args) {
2974     V_VT(iter) = va_arg(valist, enum VARENUM);
2975
2976     TRACE("vt=%d\n", V_VT(iter));
2977
2978     if(V_VT(iter) & VT_BYREF) {
2979       V_BYREF(iter) = va_arg(valist, LPVOID);
2980     } else {
2981       switch(V_VT(iter)) {
2982       case VT_I4:
2983         V_I4(iter) = va_arg(valist, LONG);
2984         break;
2985       case VT_BSTR:
2986         V_BSTR(iter) = va_arg(valist, BSTR);
2987         break;
2988       case VT_DISPATCH:
2989         V_DISPATCH(iter) = va_arg(valist, IDispatch*);
2990         break;
2991       case VT_BOOL:
2992         V_BOOL(iter) = va_arg(valist, int);
2993         break;
2994       case VT_UNKNOWN:
2995         V_UNKNOWN(iter) = va_arg(valist, IUnknown*);
2996         break;
2997       default:
2998         V_VT(iter) = VT_I4;
2999         V_I4(iter) = va_arg(valist, LONG);
3000       }
3001     }
3002   }
3003
3004   return S_OK;
3005 }
3006
3007 /*************************************************************************
3008  *      @       [SHLWAPI.282]
3009  *
3010  * SHPackDispParams
3011  */
3012 HRESULT WINAPIV SHPackDispParams(DISPPARAMS *params, VARIANTARG *args, UINT cnt, ...)
3013 {
3014   __ms_va_list valist;
3015   HRESULT hres;
3016
3017   __ms_va_start(valist, cnt);
3018   hres = SHPackDispParamsV(params, args, cnt, valist);
3019   __ms_va_end(valist);
3020   return hres;
3021 }
3022
3023 /*************************************************************************
3024  *      SHLWAPI_InvokeByIID
3025  *
3026  *   This helper function calls IDispatch::Invoke for each sink
3027  * which implements given iid or IDispatch.
3028  *
3029  */
3030 static HRESULT SHLWAPI_InvokeByIID(
3031         IConnectionPoint* iCP,
3032         REFIID iid,
3033         DISPID dispId,
3034         DISPPARAMS* dispParams)
3035 {
3036   IEnumConnections *enumerator;
3037   CONNECTDATA rgcd;
3038   static DISPPARAMS empty = {NULL, NULL, 0, 0};
3039   DISPPARAMS* params = dispParams;
3040
3041   HRESULT result = IConnectionPoint_EnumConnections(iCP, &enumerator);
3042   if (FAILED(result))
3043     return result;
3044
3045   /* Invoke is never happening with an NULL dispParams */
3046   if (!params)
3047     params = &empty;
3048
3049   while(IEnumConnections_Next(enumerator, 1, &rgcd, NULL)==S_OK)
3050   {
3051     IDispatch *dispIface;
3052     if ((iid && SUCCEEDED(IUnknown_QueryInterface(rgcd.pUnk, iid, (LPVOID*)&dispIface))) ||
3053         SUCCEEDED(IUnknown_QueryInterface(rgcd.pUnk, &IID_IDispatch, (LPVOID*)&dispIface)))
3054     {
3055       IDispatch_Invoke(dispIface, dispId, &IID_NULL, 0, DISPATCH_METHOD, params, NULL, NULL, NULL);
3056       IDispatch_Release(dispIface);
3057     }
3058     IUnknown_Release(rgcd.pUnk);
3059   }
3060
3061   IEnumConnections_Release(enumerator);
3062
3063   return S_OK;
3064 }
3065
3066 /*************************************************************************
3067  *  IConnectionPoint_InvokeWithCancel   [SHLWAPI.283]
3068  */
3069 HRESULT WINAPI IConnectionPoint_InvokeWithCancel( IConnectionPoint* iCP,
3070                                                   DISPID dispId, DISPPARAMS* dispParams,
3071                                                   DWORD unknown1, DWORD unknown2 )
3072 {
3073     IID iid;
3074     HRESULT result;
3075
3076     FIXME("(%p)->(0x%x %p %x %x) partial stub\n", iCP, dispId, dispParams, unknown1, unknown2);
3077
3078     result = IConnectionPoint_GetConnectionInterface(iCP, &iid);
3079     if (SUCCEEDED(result))
3080         result = SHLWAPI_InvokeByIID(iCP, &iid, dispId, dispParams);
3081     else
3082         result = SHLWAPI_InvokeByIID(iCP, NULL, dispId, dispParams);
3083
3084     return result;
3085 }
3086
3087
3088 /*************************************************************************
3089  *      @       [SHLWAPI.284]
3090  *
3091  *  IConnectionPoint_SimpleInvoke
3092  */
3093 HRESULT WINAPI IConnectionPoint_SimpleInvoke(
3094         IConnectionPoint* iCP,
3095         DISPID dispId,
3096         DISPPARAMS* dispParams)
3097 {
3098   IID iid;
3099   HRESULT result;
3100
3101   TRACE("(%p)->(0x%x %p)\n",iCP,dispId,dispParams);
3102
3103   result = IConnectionPoint_GetConnectionInterface(iCP, &iid);
3104   if (SUCCEEDED(result))
3105     result = SHLWAPI_InvokeByIID(iCP, &iid, dispId, dispParams);
3106   else
3107     result = SHLWAPI_InvokeByIID(iCP, NULL, dispId, dispParams);
3108
3109   return result;
3110 }
3111
3112 /*************************************************************************
3113  *      @       [SHLWAPI.285]
3114  *
3115  * Notify an IConnectionPoint object of changes.
3116  *
3117  * PARAMS
3118  *  lpCP   [I] Object to notify
3119  *  dispID [I]
3120  *
3121  * RETURNS
3122  *  Success: S_OK.
3123  *  Failure: E_NOINTERFACE, if lpCP is NULL or does not support the
3124  *           IConnectionPoint interface.
3125  */
3126 HRESULT WINAPI IConnectionPoint_OnChanged(IConnectionPoint* lpCP, DISPID dispID)
3127 {
3128   IEnumConnections *lpEnum;
3129   HRESULT hRet = E_NOINTERFACE;
3130
3131   TRACE("(%p,0x%8X)\n", lpCP, dispID);
3132
3133   /* Get an enumerator for the connections */
3134   if (lpCP)
3135     hRet = IConnectionPoint_EnumConnections(lpCP, &lpEnum);
3136
3137   if (SUCCEEDED(hRet))
3138   {
3139     IPropertyNotifySink *lpSink;
3140     CONNECTDATA connData;
3141     ULONG ulFetched;
3142
3143     /* Call OnChanged() for every notify sink in the connection point */
3144     while (IEnumConnections_Next(lpEnum, 1, &connData, &ulFetched) == S_OK)
3145     {
3146       if (SUCCEEDED(IUnknown_QueryInterface(connData.pUnk, &IID_IPropertyNotifySink, (void**)&lpSink)) &&
3147           lpSink)
3148       {
3149         IPropertyNotifySink_OnChanged(lpSink, dispID);
3150         IPropertyNotifySink_Release(lpSink);
3151       }
3152       IUnknown_Release(connData.pUnk);
3153     }
3154
3155     IEnumConnections_Release(lpEnum);
3156   }
3157   return hRet;
3158 }
3159
3160 /*************************************************************************
3161  *      @       [SHLWAPI.286]
3162  *
3163  *  IUnknown_CPContainerInvokeParam
3164  */
3165 HRESULT WINAPIV IUnknown_CPContainerInvokeParam(
3166         IUnknown *container,
3167         REFIID riid,
3168         DISPID dispId,
3169         VARIANTARG* buffer,
3170         DWORD cParams, ...)
3171 {
3172   HRESULT result;
3173   IConnectionPoint *iCP;
3174   IConnectionPointContainer *iCPC;
3175   DISPPARAMS dispParams = {buffer, NULL, cParams, 0};
3176   __ms_va_list valist;
3177
3178   if (!container)
3179     return E_NOINTERFACE;
3180
3181   result = IUnknown_QueryInterface(container, &IID_IConnectionPointContainer,(LPVOID*) &iCPC);
3182   if (FAILED(result))
3183       return result;
3184
3185   result = IConnectionPointContainer_FindConnectionPoint(iCPC, riid, &iCP);
3186   IConnectionPointContainer_Release(iCPC);
3187   if(FAILED(result))
3188       return result;
3189
3190   __ms_va_start(valist, cParams);
3191   SHPackDispParamsV(&dispParams, buffer, cParams, valist);
3192   __ms_va_end(valist);
3193
3194   result = SHLWAPI_InvokeByIID(iCP, riid, dispId, &dispParams);
3195   IConnectionPoint_Release(iCP);
3196
3197   return result;
3198 }
3199
3200 /*************************************************************************
3201  *      @       [SHLWAPI.287]
3202  *
3203  * Notify an IConnectionPointContainer object of changes.
3204  *
3205  * PARAMS
3206  *  lpUnknown [I] Object to notify
3207  *  dispID    [I]
3208  *
3209  * RETURNS
3210  *  Success: S_OK.
3211  *  Failure: E_NOINTERFACE, if lpUnknown is NULL or does not support the
3212  *           IConnectionPointContainer interface.
3213  */
3214 HRESULT WINAPI IUnknown_CPContainerOnChanged(IUnknown *lpUnknown, DISPID dispID)
3215 {
3216   IConnectionPointContainer* lpCPC = NULL;
3217   HRESULT hRet = E_NOINTERFACE;
3218
3219   TRACE("(%p,0x%8X)\n", lpUnknown, dispID);
3220
3221   if (lpUnknown)
3222     hRet = IUnknown_QueryInterface(lpUnknown, &IID_IConnectionPointContainer, (void**)&lpCPC);
3223
3224   if (SUCCEEDED(hRet))
3225   {
3226     IConnectionPoint* lpCP;
3227
3228     hRet = IConnectionPointContainer_FindConnectionPoint(lpCPC, &IID_IPropertyNotifySink, &lpCP);
3229     IConnectionPointContainer_Release(lpCPC);
3230
3231     hRet = IConnectionPoint_OnChanged(lpCP, dispID);
3232     IConnectionPoint_Release(lpCP);
3233   }
3234   return hRet;
3235 }
3236
3237 /*************************************************************************
3238  *      @       [SHLWAPI.289]
3239  *
3240  * See PlaySoundW.
3241  */
3242 BOOL WINAPI PlaySoundWrapW(LPCWSTR pszSound, HMODULE hmod, DWORD fdwSound)
3243 {
3244     return PlaySoundW(pszSound, hmod, fdwSound);
3245 }
3246
3247 /*************************************************************************
3248  *      @       [SHLWAPI.294]
3249  *
3250  * Retrieve a key value from an INI file.  See GetPrivateProfileString for
3251  * more information.
3252  *
3253  * PARAMS
3254  *  appName   [I] The section in the INI file that contains the key
3255  *  keyName   [I] The key to be retrieved
3256  *  out       [O] The buffer into which the key's value will be copied
3257  *  outLen    [I] The length of the `out' buffer
3258  *  filename  [I] The location of the INI file
3259  *
3260  * RETURNS
3261  *  Length of string copied into `out'.
3262  */
3263 DWORD WINAPI SHGetIniStringW(LPCWSTR appName, LPCWSTR keyName, LPWSTR out,
3264         DWORD outLen, LPCWSTR filename)
3265 {
3266     INT ret;
3267     WCHAR *buf;
3268
3269     TRACE("(%s,%s,%p,%08x,%s)\n", debugstr_w(appName), debugstr_w(keyName),
3270         out, outLen, debugstr_w(filename));
3271
3272     if(outLen == 0)
3273         return 0;
3274
3275     buf = HeapAlloc(GetProcessHeap(), 0, outLen * sizeof(WCHAR));
3276     if(!buf){
3277         *out = 0;
3278         return 0;
3279     }
3280
3281     ret = GetPrivateProfileStringW(appName, keyName, NULL, buf, outLen, filename);
3282     if(ret)
3283         strcpyW(out, buf);
3284     else
3285         *out = 0;
3286
3287     HeapFree(GetProcessHeap(), 0, buf);
3288
3289     return strlenW(out);
3290 }
3291
3292 /*************************************************************************
3293  *      @       [SHLWAPI.295]
3294  *
3295  * Set a key value in an INI file.  See WritePrivateProfileString for
3296  * more information.
3297  *
3298  * PARAMS
3299  *  appName   [I] The section in the INI file that contains the key
3300  *  keyName   [I] The key to be set
3301  *  str       [O] The value of the key
3302  *  filename  [I] The location of the INI file
3303  *
3304  * RETURNS
3305  *   Success: TRUE
3306  *   Failure: FALSE
3307  */
3308 BOOL WINAPI SHSetIniStringW(LPCWSTR appName, LPCWSTR keyName, LPCWSTR str,
3309         LPCWSTR filename)
3310 {
3311     TRACE("(%s, %p, %s, %s)\n", debugstr_w(appName), keyName, debugstr_w(str),
3312             debugstr_w(filename));
3313
3314     return WritePrivateProfileStringW(appName, keyName, str, filename);
3315 }
3316
3317 /*************************************************************************
3318  *      @       [SHLWAPI.313]
3319  *
3320  * See SHGetFileInfoW.
3321  */
3322 DWORD WINAPI SHGetFileInfoWrapW(LPCWSTR path, DWORD dwFileAttributes,
3323                          SHFILEINFOW *psfi, UINT sizeofpsfi, UINT flags)
3324 {
3325     return SHGetFileInfoW(path, dwFileAttributes, psfi, sizeofpsfi, flags);
3326 }
3327
3328 /*************************************************************************
3329  *      @       [SHLWAPI.318]
3330  *
3331  * See DragQueryFileW.
3332  */
3333 UINT WINAPI DragQueryFileWrapW(HDROP hDrop, UINT lFile, LPWSTR lpszFile, UINT lLength)
3334 {
3335     return DragQueryFileW(hDrop, lFile, lpszFile, lLength);
3336 }
3337
3338 /*************************************************************************
3339  *      @       [SHLWAPI.333]
3340  *
3341  * See SHBrowseForFolderW.
3342  */
3343 LPITEMIDLIST WINAPI SHBrowseForFolderWrapW(LPBROWSEINFOW lpBi)
3344 {
3345     return SHBrowseForFolderW(lpBi);
3346 }
3347
3348 /*************************************************************************
3349  *      @       [SHLWAPI.334]
3350  *
3351  * See SHGetPathFromIDListW.
3352  */
3353 BOOL WINAPI SHGetPathFromIDListWrapW(LPCITEMIDLIST pidl,LPWSTR pszPath)
3354 {
3355     return SHGetPathFromIDListW(pidl, pszPath);
3356 }
3357
3358 /*************************************************************************
3359  *      @       [SHLWAPI.335]
3360  *
3361  * See ShellExecuteExW.
3362  */
3363 BOOL WINAPI ShellExecuteExWrapW(LPSHELLEXECUTEINFOW lpExecInfo)
3364 {
3365     return ShellExecuteExW(lpExecInfo);
3366 }
3367
3368 /*************************************************************************
3369  *      @       [SHLWAPI.336]
3370  *
3371  * See SHFileOperationW.
3372  */
3373 INT WINAPI SHFileOperationWrapW(LPSHFILEOPSTRUCTW lpFileOp)
3374 {
3375     return SHFileOperationW(lpFileOp);
3376 }
3377
3378 /*************************************************************************
3379  *      @       [SHLWAPI.342]
3380  *
3381  */
3382 PVOID WINAPI SHInterlockedCompareExchange( PVOID *dest, PVOID xchg, PVOID compare )
3383 {
3384     return InterlockedCompareExchangePointer( dest, xchg, compare );
3385 }
3386
3387 /*************************************************************************
3388  *      @       [SHLWAPI.350]
3389  *
3390  * See GetFileVersionInfoSizeW.
3391  */
3392 DWORD WINAPI GetFileVersionInfoSizeWrapW( LPCWSTR filename, LPDWORD handle )
3393 {
3394     return GetFileVersionInfoSizeW( filename, handle );
3395 }
3396
3397 /*************************************************************************
3398  *      @       [SHLWAPI.351]
3399  *
3400  * See GetFileVersionInfoW.
3401  */
3402 BOOL  WINAPI GetFileVersionInfoWrapW( LPCWSTR filename, DWORD handle,
3403                                       DWORD datasize, LPVOID data )
3404 {
3405     return GetFileVersionInfoW( filename, handle, datasize, data );
3406 }
3407
3408 /*************************************************************************
3409  *      @       [SHLWAPI.352]
3410  *
3411  * See VerQueryValueW.
3412  */
3413 WORD WINAPI VerQueryValueWrapW( LPVOID pBlock, LPCWSTR lpSubBlock,
3414                                 LPVOID *lplpBuffer, UINT *puLen )
3415 {
3416     return VerQueryValueW( pBlock, lpSubBlock, lplpBuffer, puLen );
3417 }
3418
3419 #define IsIface(type) SUCCEEDED((hRet = IUnknown_QueryInterface(lpUnknown, &IID_##type, (void**)&lpObj)))
3420 #define IShellBrowser_EnableModeless IShellBrowser_EnableModelessSB
3421 #define EnableModeless(type) type##_EnableModeless((type*)lpObj, bModeless)
3422
3423 /*************************************************************************
3424  *      @       [SHLWAPI.355]
3425  *
3426  * Change the modality of a shell object.
3427  *
3428  * PARAMS
3429  *  lpUnknown [I] Object to make modeless
3430  *  bModeless [I] TRUE=Make modeless, FALSE=Make modal
3431  *
3432  * RETURNS
3433  *  Success: S_OK. The modality lpUnknown is changed.
3434  *  Failure: An HRESULT error code indicating the error.
3435  *
3436  * NOTES
3437  *  lpUnknown must support the IOleInPlaceFrame interface, the
3438  *  IInternetSecurityMgrSite interface, the IShellBrowser interface
3439  *  the IDocHostUIHandler interface, or the IOleInPlaceActiveObject interface,
3440  *  or this call will fail.
3441  */
3442 HRESULT WINAPI IUnknown_EnableModeless(IUnknown *lpUnknown, BOOL bModeless)
3443 {
3444   IUnknown *lpObj;
3445   HRESULT hRet;
3446
3447   TRACE("(%p,%d)\n", lpUnknown, bModeless);
3448
3449   if (!lpUnknown)
3450     return E_FAIL;
3451
3452   if (IsIface(IOleInPlaceActiveObject))
3453     EnableModeless(IOleInPlaceActiveObject);
3454   else if (IsIface(IOleInPlaceFrame))
3455     EnableModeless(IOleInPlaceFrame);
3456   else if (IsIface(IShellBrowser))
3457     EnableModeless(IShellBrowser);
3458   else if (IsIface(IInternetSecurityMgrSite))
3459     EnableModeless(IInternetSecurityMgrSite);
3460   else if (IsIface(IDocHostUIHandler))
3461     EnableModeless(IDocHostUIHandler);
3462   else
3463     return hRet;
3464
3465   IUnknown_Release(lpObj);
3466   return S_OK;
3467 }
3468
3469 /*************************************************************************
3470  *      @       [SHLWAPI.357]
3471  *
3472  * See SHGetNewLinkInfoW.
3473  */
3474 BOOL WINAPI SHGetNewLinkInfoWrapW(LPCWSTR pszLinkTo, LPCWSTR pszDir, LPWSTR pszName,
3475                         BOOL *pfMustCopy, UINT uFlags)
3476 {
3477     return SHGetNewLinkInfoW(pszLinkTo, pszDir, pszName, pfMustCopy, uFlags);
3478 }
3479
3480 /*************************************************************************
3481  *      @       [SHLWAPI.358]
3482  *
3483  * See SHDefExtractIconW.
3484  */
3485 UINT WINAPI SHDefExtractIconWrapW(LPCWSTR pszIconFile, int iIndex, UINT uFlags, HICON* phiconLarge,
3486                          HICON* phiconSmall, UINT nIconSize)
3487 {
3488     return SHDefExtractIconW(pszIconFile, iIndex, uFlags, phiconLarge, phiconSmall, nIconSize);
3489 }
3490
3491 /*************************************************************************
3492  *      @       [SHLWAPI.363]
3493  *
3494  * Get and show a context menu from a shell folder.
3495  *
3496  * PARAMS
3497  *  hWnd           [I] Window displaying the shell folder
3498  *  lpFolder       [I] IShellFolder interface
3499  *  lpApidl        [I] Id for the particular folder desired
3500  *  bInvokeDefault [I] Whether to invoke the default menu item
3501  *
3502  * RETURNS
3503  *  Success: S_OK. If bInvokeDefault is TRUE, the default menu action was
3504  *           executed.
3505  *  Failure: An HRESULT error code indicating the error.
3506  */
3507 HRESULT WINAPI SHInvokeCommand(HWND hWnd, IShellFolder* lpFolder, LPCITEMIDLIST lpApidl, BOOL bInvokeDefault)
3508 {
3509   IContextMenu *iContext;
3510   HRESULT hRet;
3511
3512   TRACE("(%p, %p, %p, %d)\n", hWnd, lpFolder, lpApidl, bInvokeDefault);
3513
3514   if (!lpFolder)
3515     return E_FAIL;
3516
3517   /* Get the context menu from the shell folder */
3518   hRet = IShellFolder_GetUIObjectOf(lpFolder, hWnd, 1, &lpApidl,
3519                                     &IID_IContextMenu, 0, (void**)&iContext);
3520   if (SUCCEEDED(hRet))
3521   {
3522     HMENU hMenu;
3523     if ((hMenu = CreatePopupMenu()))
3524     {
3525       HRESULT hQuery;
3526       DWORD dwDefaultId = 0;
3527
3528       /* Add the context menu entries to the popup */
3529       hQuery = IContextMenu_QueryContextMenu(iContext, hMenu, 0, 1, 0x7FFF,
3530                                              bInvokeDefault ? CMF_NORMAL : CMF_DEFAULTONLY);
3531
3532       if (SUCCEEDED(hQuery))
3533       {
3534         if (bInvokeDefault &&
3535             (dwDefaultId = GetMenuDefaultItem(hMenu, 0, 0)) != (UINT)-1)
3536         {
3537           CMINVOKECOMMANDINFO cmIci;
3538           /* Invoke the default item */
3539           memset(&cmIci,0,sizeof(cmIci));
3540           cmIci.cbSize = sizeof(cmIci);
3541           cmIci.fMask = CMIC_MASK_ASYNCOK;
3542           cmIci.hwnd = hWnd;
3543           cmIci.lpVerb = MAKEINTRESOURCEA(dwDefaultId);
3544           cmIci.nShow = SW_SCROLLCHILDREN;
3545
3546           hRet = IContextMenu_InvokeCommand(iContext, &cmIci);
3547         }
3548       }
3549       DestroyMenu(hMenu);
3550     }
3551     IContextMenu_Release(iContext);
3552   }
3553   return hRet;
3554 }
3555
3556 /*************************************************************************
3557  *      @       [SHLWAPI.370]
3558  *
3559  * See ExtractIconW.
3560  */
3561 HICON WINAPI ExtractIconWrapW(HINSTANCE hInstance, LPCWSTR lpszExeFileName,
3562                          UINT nIconIndex)
3563 {
3564     return ExtractIconW(hInstance, lpszExeFileName, nIconIndex);
3565 }
3566
3567 /*************************************************************************
3568  *      @       [SHLWAPI.377]
3569  *
3570  * Load a library from the directory of a particular process.
3571  *
3572  * PARAMS
3573  *  new_mod        [I] Library name
3574  *  inst_hwnd      [I] Module whose directory is to be used
3575  *  dwCrossCodePage [I] Should be FALSE (currently ignored)
3576  *
3577  * RETURNS
3578  *  Success: A handle to the loaded module
3579  *  Failure: A NULL handle.
3580  */
3581 HMODULE WINAPI MLLoadLibraryA(LPCSTR new_mod, HMODULE inst_hwnd, DWORD dwCrossCodePage)
3582 {
3583   /* FIXME: Native appears to do DPA_Create and a DPA_InsertPtr for
3584    *        each call here.
3585    * FIXME: Native shows calls to:
3586    *  SHRegGetUSValue for "Software\Microsoft\Internet Explorer\International"
3587    *                      CheckVersion
3588    *  RegOpenKeyExA for "HKLM\Software\Microsoft\Internet Explorer"
3589    *  RegQueryValueExA for "LPKInstalled"
3590    *  RegCloseKey
3591    *  RegOpenKeyExA for "HKCU\Software\Microsoft\Internet Explorer\International"
3592    *  RegQueryValueExA for "ResourceLocale"
3593    *  RegCloseKey
3594    *  RegOpenKeyExA for "HKLM\Software\Microsoft\Active Setup\Installed Components\{guid}"
3595    *  RegQueryValueExA for "Locale"
3596    *  RegCloseKey
3597    *  and then tests the Locale ("en" for me).
3598    *     code below
3599    *  after the code then a DPA_Create (first time) and DPA_InsertPtr are done.
3600    */
3601     CHAR mod_path[2*MAX_PATH];
3602     LPSTR ptr;
3603     DWORD len;
3604
3605     FIXME("(%s,%p,%d) semi-stub!\n", debugstr_a(new_mod), inst_hwnd, dwCrossCodePage);
3606     len = GetModuleFileNameA(inst_hwnd, mod_path, sizeof(mod_path));
3607     if (!len || len >= sizeof(mod_path)) return NULL;
3608
3609     ptr = strrchr(mod_path, '\\');
3610     if (ptr) {
3611         strcpy(ptr+1, new_mod);
3612         TRACE("loading %s\n", debugstr_a(mod_path));
3613         return LoadLibraryA(mod_path);
3614     }
3615     return NULL;
3616 }
3617
3618 /*************************************************************************
3619  *      @       [SHLWAPI.378]
3620  *
3621  * Unicode version of MLLoadLibraryA.
3622  */
3623 HMODULE WINAPI MLLoadLibraryW(LPCWSTR new_mod, HMODULE inst_hwnd, DWORD dwCrossCodePage)
3624 {
3625     WCHAR mod_path[2*MAX_PATH];
3626     LPWSTR ptr;
3627     DWORD len;
3628
3629     FIXME("(%s,%p,%d) semi-stub!\n", debugstr_w(new_mod), inst_hwnd, dwCrossCodePage);
3630     len = GetModuleFileNameW(inst_hwnd, mod_path, sizeof(mod_path) / sizeof(WCHAR));
3631     if (!len || len >= sizeof(mod_path) / sizeof(WCHAR)) return NULL;
3632
3633     ptr = strrchrW(mod_path, '\\');
3634     if (ptr) {
3635         strcpyW(ptr+1, new_mod);
3636         TRACE("loading %s\n", debugstr_w(mod_path));
3637         return LoadLibraryW(mod_path);
3638     }
3639     return NULL;
3640 }
3641
3642 /*************************************************************************
3643  * ColorAdjustLuma      [SHLWAPI.@]
3644  *
3645  * Adjust the luminosity of a color
3646  *
3647  * PARAMS
3648  *  cRGB         [I] RGB value to convert
3649  *  dwLuma       [I] Luma adjustment
3650  *  bUnknown     [I] Unknown
3651  *
3652  * RETURNS
3653  *  The adjusted RGB color.
3654  */
3655 COLORREF WINAPI ColorAdjustLuma(COLORREF cRGB, int dwLuma, BOOL bUnknown)
3656 {
3657   TRACE("(0x%8x,%d,%d)\n", cRGB, dwLuma, bUnknown);
3658
3659   if (dwLuma)
3660   {
3661     WORD wH, wL, wS;
3662
3663     ColorRGBToHLS(cRGB, &wH, &wL, &wS);
3664
3665     FIXME("Ignoring luma adjustment\n");
3666
3667     /* FIXME: The adjustment is not linear */
3668
3669     cRGB = ColorHLSToRGB(wH, wL, wS);
3670   }
3671   return cRGB;
3672 }
3673
3674 /*************************************************************************
3675  *      @       [SHLWAPI.389]
3676  *
3677  * See GetSaveFileNameW.
3678  */
3679 BOOL WINAPI GetSaveFileNameWrapW(LPOPENFILENAMEW ofn)
3680 {
3681     return GetSaveFileNameW(ofn);
3682 }
3683
3684 /*************************************************************************
3685  *      @       [SHLWAPI.390]
3686  *
3687  * See WNetRestoreConnectionW.
3688  */
3689 DWORD WINAPI WNetRestoreConnectionWrapW(HWND hwndOwner, LPWSTR lpszDevice)
3690 {
3691     return WNetRestoreConnectionW(hwndOwner, lpszDevice);
3692 }
3693
3694 /*************************************************************************
3695  *      @       [SHLWAPI.391]
3696  *
3697  * See WNetGetLastErrorW.
3698  */
3699 DWORD WINAPI WNetGetLastErrorWrapW(LPDWORD lpError, LPWSTR lpErrorBuf, DWORD nErrorBufSize,
3700                          LPWSTR lpNameBuf, DWORD nNameBufSize)
3701 {
3702     return WNetGetLastErrorW(lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize);
3703 }
3704
3705 /*************************************************************************
3706  *      @       [SHLWAPI.401]
3707  *
3708  * See PageSetupDlgW.
3709  */
3710 BOOL WINAPI PageSetupDlgWrapW(LPPAGESETUPDLGW pagedlg)
3711 {
3712     return PageSetupDlgW(pagedlg);
3713 }
3714
3715 /*************************************************************************
3716  *      @       [SHLWAPI.402]
3717  *
3718  * See PrintDlgW.
3719  */
3720 BOOL WINAPI PrintDlgWrapW(LPPRINTDLGW printdlg)
3721 {
3722     return PrintDlgW(printdlg);
3723 }
3724
3725 /*************************************************************************
3726  *      @       [SHLWAPI.403]
3727  *
3728  * See GetOpenFileNameW.
3729  */
3730 BOOL WINAPI GetOpenFileNameWrapW(LPOPENFILENAMEW ofn)
3731 {
3732     return GetOpenFileNameW(ofn);
3733 }
3734
3735 /*************************************************************************
3736  *      @       [SHLWAPI.404]
3737  */
3738 HRESULT WINAPI SHIShellFolder_EnumObjects(LPSHELLFOLDER lpFolder, HWND hwnd, SHCONTF flags, IEnumIDList **ppenum)
3739 {
3740     /* Windows attempts to get an IPersist interface and, if that fails, an
3741      * IPersistFolder interface on the folder passed-in here.  If one of those
3742      * interfaces is available, it then calls GetClassID on the folder... and
3743      * then calls IShellFolder_EnumObjects no matter what, even crashing if
3744      * lpFolder isn't actually an IShellFolder object.  The purpose of getting
3745      * the ClassID is unknown, so we don't do it here.
3746      *
3747      * For discussion and detailed tests, see:
3748      * "shlwapi: Be less strict on which type of IShellFolder can be enumerated"
3749      * wine-devel mailing list, 3 Jun 2010
3750      */
3751
3752     return IShellFolder_EnumObjects(lpFolder, hwnd, flags, ppenum);
3753 }
3754
3755 /* INTERNAL: Map from HLS color space to RGB */
3756 static WORD ConvertHue(int wHue, WORD wMid1, WORD wMid2)
3757 {
3758   wHue = wHue > 240 ? wHue - 240 : wHue < 0 ? wHue + 240 : wHue;
3759
3760   if (wHue > 160)
3761     return wMid1;
3762   else if (wHue > 120)
3763     wHue = 160 - wHue;
3764   else if (wHue > 40)
3765     return wMid2;
3766
3767   return ((wHue * (wMid2 - wMid1) + 20) / 40) + wMid1;
3768 }
3769
3770 /* Convert to RGB and scale into RGB range (0..255) */
3771 #define GET_RGB(h) (ConvertHue(h, wMid1, wMid2) * 255 + 120) / 240
3772
3773 /*************************************************************************
3774  *      ColorHLSToRGB   [SHLWAPI.@]
3775  *
3776  * Convert from hls color space into an rgb COLORREF.
3777  *
3778  * PARAMS
3779  *  wHue        [I] Hue amount
3780  *  wLuminosity [I] Luminosity amount
3781  *  wSaturation [I] Saturation amount
3782  *
3783  * RETURNS
3784  *  A COLORREF representing the converted color.
3785  *
3786  * NOTES
3787  *  Input hls values are constrained to the range (0..240).
3788  */
3789 COLORREF WINAPI ColorHLSToRGB(WORD wHue, WORD wLuminosity, WORD wSaturation)
3790 {
3791   WORD wRed;
3792
3793   if (wSaturation)
3794   {
3795     WORD wGreen, wBlue, wMid1, wMid2;
3796
3797     if (wLuminosity > 120)
3798       wMid2 = wSaturation + wLuminosity - (wSaturation * wLuminosity + 120) / 240;
3799     else
3800       wMid2 = ((wSaturation + 240) * wLuminosity + 120) / 240;
3801
3802     wMid1 = wLuminosity * 2 - wMid2;
3803
3804     wRed   = GET_RGB(wHue + 80);
3805     wGreen = GET_RGB(wHue);
3806     wBlue  = GET_RGB(wHue - 80);
3807
3808     return RGB(wRed, wGreen, wBlue);
3809   }
3810
3811   wRed = wLuminosity * 255 / 240;
3812   return RGB(wRed, wRed, wRed);
3813 }
3814
3815 /*************************************************************************
3816  *      @       [SHLWAPI.413]
3817  *
3818  * Get the current docking status of the system.
3819  *
3820  * PARAMS
3821  *  dwFlags [I] DOCKINFO_ flags from "winbase.h", unused
3822  *
3823  * RETURNS
3824  *  One of DOCKINFO_UNDOCKED, DOCKINFO_UNDOCKED, or 0 if the system is not
3825  *  a notebook.
3826  */
3827 DWORD WINAPI SHGetMachineInfo(DWORD dwFlags)
3828 {
3829   HW_PROFILE_INFOA hwInfo;
3830
3831   TRACE("(0x%08x)\n", dwFlags);
3832
3833   GetCurrentHwProfileA(&hwInfo);
3834   switch (hwInfo.dwDockInfo & (DOCKINFO_DOCKED|DOCKINFO_UNDOCKED))
3835   {
3836   case DOCKINFO_DOCKED:
3837   case DOCKINFO_UNDOCKED:
3838     return hwInfo.dwDockInfo & (DOCKINFO_DOCKED|DOCKINFO_UNDOCKED);
3839   default:
3840     return 0;
3841   }
3842 }
3843
3844 /*************************************************************************
3845  *      @       [SHLWAPI.418]
3846  *
3847  * Function seems to do FreeLibrary plus other things.
3848  *
3849  * FIXME native shows the following calls:
3850  *   RtlEnterCriticalSection
3851  *   LocalFree
3852  *   GetProcAddress(Comctl32??, 150L)
3853  *   DPA_DeletePtr
3854  *   RtlLeaveCriticalSection
3855  *  followed by the FreeLibrary.
3856  *  The above code may be related to .377 above.
3857  */
3858 BOOL WINAPI MLFreeLibrary(HMODULE hModule)
3859 {
3860         FIXME("(%p) semi-stub\n", hModule);
3861         return FreeLibrary(hModule);
3862 }
3863
3864 /*************************************************************************
3865  *      @       [SHLWAPI.419]
3866  */
3867 BOOL WINAPI SHFlushSFCacheWrap(void) {
3868   FIXME(": stub\n");
3869   return TRUE;
3870 }
3871
3872 /*************************************************************************
3873  *      @      [SHLWAPI.429]
3874  * FIXME I have no idea what this function does or what its arguments are.
3875  */
3876 BOOL WINAPI MLIsMLHInstance(HINSTANCE hInst)
3877 {
3878        FIXME("(%p) stub\n", hInst);
3879        return FALSE;
3880 }
3881
3882
3883 /*************************************************************************
3884  *      @       [SHLWAPI.430]
3885  */
3886 DWORD WINAPI MLSetMLHInstance(HINSTANCE hInst, HANDLE hHeap)
3887 {
3888         FIXME("(%p,%p) stub\n", hInst, hHeap);
3889         return E_FAIL;   /* This is what is used if shlwapi not loaded */
3890 }
3891
3892 /*************************************************************************
3893  *      @       [SHLWAPI.431]
3894  */
3895 DWORD WINAPI MLClearMLHInstance(DWORD x)
3896 {
3897         FIXME("(0x%08x)stub\n", x);
3898         return 0xabba1247;
3899 }
3900
3901 /*************************************************************************
3902  * @ [SHLWAPI.432]
3903  *
3904  * See SHSendMessageBroadcastW
3905  *
3906  */
3907 DWORD WINAPI SHSendMessageBroadcastA(UINT uMsg, WPARAM wParam, LPARAM lParam)
3908 {
3909     return SendMessageTimeoutA(HWND_BROADCAST, uMsg, wParam, lParam,
3910                                SMTO_ABORTIFHUNG, 2000, NULL);
3911 }
3912
3913 /*************************************************************************
3914  * @ [SHLWAPI.433]
3915  *
3916  * A wrapper for sending Broadcast Messages to all top level Windows
3917  *
3918  */
3919 DWORD WINAPI SHSendMessageBroadcastW(UINT uMsg, WPARAM wParam, LPARAM lParam)
3920 {
3921     return SendMessageTimeoutW(HWND_BROADCAST, uMsg, wParam, lParam,
3922                                SMTO_ABORTIFHUNG, 2000, NULL);
3923 }
3924
3925 /*************************************************************************
3926  *      @       [SHLWAPI.436]
3927  *
3928  * Convert a Unicode string CLSID into a CLSID.
3929  *
3930  * PARAMS
3931  *  idstr      [I]   string containing a CLSID in text form
3932  *  id         [O]   CLSID extracted from the string
3933  *
3934  * RETURNS
3935  *  S_OK on success or E_INVALIDARG on failure
3936  */
3937 HRESULT WINAPI CLSIDFromStringWrap(LPCWSTR idstr, CLSID *id)
3938 {
3939     return CLSIDFromString((LPCOLESTR)idstr, id);
3940 }
3941
3942 /*************************************************************************
3943  *      @       [SHLWAPI.437]
3944  *
3945  * Determine if the OS supports a given feature.
3946  *
3947  * PARAMS
3948  *  dwFeature [I] Feature requested (undocumented)
3949  *
3950  * RETURNS
3951  *  TRUE  If the feature is available.
3952  *  FALSE If the feature is not available.
3953  */
3954 BOOL WINAPI IsOS(DWORD feature)
3955 {
3956     OSVERSIONINFOA osvi;
3957     DWORD platform, majorv, minorv;
3958
3959     osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
3960     if(!GetVersionExA(&osvi))  {
3961         ERR("GetVersionEx failed\n");
3962         return FALSE;
3963     }
3964
3965     majorv = osvi.dwMajorVersion;
3966     minorv = osvi.dwMinorVersion;
3967     platform = osvi.dwPlatformId;
3968
3969 #define ISOS_RETURN(x) \
3970     TRACE("(0x%x) ret=%d\n",feature,(x)); \
3971     return (x);
3972
3973     switch(feature)  {
3974     case OS_WIN32SORGREATER:
3975         ISOS_RETURN(platform == VER_PLATFORM_WIN32s
3976                  || platform == VER_PLATFORM_WIN32_WINDOWS)
3977     case OS_NT:
3978         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
3979     case OS_WIN95ORGREATER:
3980         ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS)
3981     case OS_NT4ORGREATER:
3982         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 4)
3983     case OS_WIN2000ORGREATER_ALT:
3984     case OS_WIN2000ORGREATER:
3985         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5)
3986     case OS_WIN98ORGREATER:
3987         ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv >= 10)
3988     case OS_WIN98_GOLD:
3989         ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv == 10)
3990     case OS_WIN2000PRO:
3991         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5)
3992     case OS_WIN2000SERVER:
3993         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1))
3994     case OS_WIN2000ADVSERVER:
3995         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1))
3996     case OS_WIN2000DATACENTER:
3997         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1))
3998     case OS_WIN2000TERMINAL:
3999         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1))
4000     case OS_EMBEDDED:
4001         FIXME("(OS_EMBEDDED) What should we return here?\n");
4002         return FALSE;
4003     case OS_TERMINALCLIENT:
4004         FIXME("(OS_TERMINALCLIENT) What should we return here?\n");
4005         return FALSE;
4006     case OS_TERMINALREMOTEADMIN:
4007         FIXME("(OS_TERMINALREMOTEADMIN) What should we return here?\n");
4008         return FALSE;
4009     case OS_WIN95_GOLD:
4010         ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv == 0)
4011     case OS_MEORGREATER:
4012         ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv >= 90)
4013     case OS_XPORGREATER:
4014         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5 && minorv >= 1)
4015     case OS_HOME:
4016         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5 && minorv >= 1)
4017     case OS_PROFESSIONAL:
4018         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
4019     case OS_DATACENTER:
4020         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
4021     case OS_ADVSERVER:
4022         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5)
4023     case OS_SERVER:
4024         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
4025     case OS_TERMINALSERVER:
4026         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
4027     case OS_PERSONALTERMINALSERVER:
4028         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && minorv >= 1 && majorv >= 5)
4029     case OS_FASTUSERSWITCHING:
4030         FIXME("(OS_FASTUSERSWITCHING) What should we return here?\n");
4031         return TRUE;
4032     case OS_WELCOMELOGONUI:
4033         FIXME("(OS_WELCOMELOGONUI) What should we return here?\n");
4034         return FALSE;
4035     case OS_DOMAINMEMBER:
4036         FIXME("(OS_DOMAINMEMBER) What should we return here?\n");
4037         return TRUE;
4038     case OS_ANYSERVER:
4039         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
4040     case OS_WOW6432:
4041         FIXME("(OS_WOW6432) Should we check this?\n");
4042         return FALSE;
4043     case OS_WEBSERVER:
4044         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
4045     case OS_SMALLBUSINESSSERVER:
4046         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
4047     case OS_TABLETPC:
4048         FIXME("(OS_TABLEPC) What should we return here?\n");
4049         return FALSE;
4050     case OS_SERVERADMINUI:
4051         FIXME("(OS_SERVERADMINUI) What should we return here?\n");
4052         return FALSE;
4053     case OS_MEDIACENTER:
4054         FIXME("(OS_MEDIACENTER) What should we return here?\n");
4055         return FALSE;
4056     case OS_APPLIANCE:
4057         FIXME("(OS_APPLIANCE) What should we return here?\n");
4058         return FALSE;
4059     case 0x25: /*OS_VISTAORGREATER*/
4060         ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 6)
4061     }
4062
4063 #undef ISOS_RETURN
4064
4065     WARN("(0x%x) unknown parameter\n",feature);
4066
4067     return FALSE;
4068 }
4069
4070 /*************************************************************************
4071  * @  [SHLWAPI.439]
4072  */
4073 HRESULT WINAPI SHLoadRegUIStringW(HKEY hkey, LPCWSTR value, LPWSTR buf, DWORD size)
4074 {
4075     DWORD type, sz = size;
4076
4077     if(RegQueryValueExW(hkey, value, NULL, &type, (LPBYTE)buf, &sz) != ERROR_SUCCESS)
4078         return E_FAIL;
4079
4080     return SHLoadIndirectString(buf, buf, size, NULL);
4081 }
4082
4083 /*************************************************************************
4084  * @  [SHLWAPI.478]
4085  *
4086  * Call IInputObject_TranslateAcceleratorIO() on an object.
4087  *
4088  * PARAMS
4089  *  lpUnknown [I] Object supporting the IInputObject interface.
4090  *  lpMsg     [I] Key message to be processed.
4091  *
4092  * RETURNS
4093  *  Success: S_OK.
4094  *  Failure: An HRESULT error code, or E_INVALIDARG if lpUnknown is NULL.
4095  */
4096 HRESULT WINAPI IUnknown_TranslateAcceleratorIO(IUnknown *lpUnknown, LPMSG lpMsg)
4097 {
4098   IInputObject* lpInput = NULL;
4099   HRESULT hRet = E_INVALIDARG;
4100
4101   TRACE("(%p,%p)\n", lpUnknown, lpMsg);
4102   if (lpUnknown)
4103   {
4104     hRet = IUnknown_QueryInterface(lpUnknown, &IID_IInputObject,
4105                                    (void**)&lpInput);
4106     if (SUCCEEDED(hRet) && lpInput)
4107     {
4108       hRet = IInputObject_TranslateAcceleratorIO(lpInput, lpMsg);
4109       IInputObject_Release(lpInput);
4110     }
4111   }
4112   return hRet;
4113 }
4114
4115 /*************************************************************************
4116  * @  [SHLWAPI.481]
4117  *
4118  * Call IInputObject_HasFocusIO() on an object.
4119  *
4120  * PARAMS
4121  *  lpUnknown [I] Object supporting the IInputObject interface.
4122  *
4123  * RETURNS
4124  *  Success: S_OK, if lpUnknown is an IInputObject object and has the focus,
4125  *           or S_FALSE otherwise.
4126  *  Failure: An HRESULT error code, or E_INVALIDARG if lpUnknown is NULL.
4127  */
4128 HRESULT WINAPI IUnknown_HasFocusIO(IUnknown *lpUnknown)
4129 {
4130   IInputObject* lpInput = NULL;
4131   HRESULT hRet = E_INVALIDARG;
4132
4133   TRACE("(%p)\n", lpUnknown);
4134   if (lpUnknown)
4135   {
4136     hRet = IUnknown_QueryInterface(lpUnknown, &IID_IInputObject,
4137                                    (void**)&lpInput);
4138     if (SUCCEEDED(hRet) && lpInput)
4139     {
4140       hRet = IInputObject_HasFocusIO(lpInput);
4141       IInputObject_Release(lpInput);
4142     }
4143   }
4144   return hRet;
4145 }
4146
4147 /*************************************************************************
4148  *      ColorRGBToHLS   [SHLWAPI.@]
4149  *
4150  * Convert an rgb COLORREF into the hls color space.
4151  *
4152  * PARAMS
4153  *  cRGB         [I] Source rgb value
4154  *  pwHue        [O] Destination for converted hue
4155  *  pwLuminance  [O] Destination for converted luminance
4156  *  pwSaturation [O] Destination for converted saturation
4157  *
4158  * RETURNS
4159  *  Nothing. pwHue, pwLuminance and pwSaturation are set to the converted
4160  *  values.
4161  *
4162  * NOTES
4163  *  Output HLS values are constrained to the range (0..240).
4164  *  For Achromatic conversions, Hue is set to 160.
4165  */
4166 VOID WINAPI ColorRGBToHLS(COLORREF cRGB, LPWORD pwHue,
4167                           LPWORD pwLuminance, LPWORD pwSaturation)
4168 {
4169   int wR, wG, wB, wMax, wMin, wHue, wLuminosity, wSaturation;
4170
4171   TRACE("(%08x,%p,%p,%p)\n", cRGB, pwHue, pwLuminance, pwSaturation);
4172
4173   wR = GetRValue(cRGB);
4174   wG = GetGValue(cRGB);
4175   wB = GetBValue(cRGB);
4176
4177   wMax = max(wR, max(wG, wB));
4178   wMin = min(wR, min(wG, wB));
4179
4180   /* Luminosity */
4181   wLuminosity = ((wMax + wMin) * 240 + 255) / 510;
4182
4183   if (wMax == wMin)
4184   {
4185     /* Achromatic case */
4186     wSaturation = 0;
4187     /* Hue is now unrepresentable, but this is what native returns... */
4188     wHue = 160;
4189   }
4190   else
4191   {
4192     /* Chromatic case */
4193     int wDelta = wMax - wMin, wRNorm, wGNorm, wBNorm;
4194
4195     /* Saturation */
4196     if (wLuminosity <= 120)
4197       wSaturation = ((wMax + wMin)/2 + wDelta * 240) / (wMax + wMin);
4198     else
4199       wSaturation = ((510 - wMax - wMin)/2 + wDelta * 240) / (510 - wMax - wMin);
4200
4201     /* Hue */
4202     wRNorm = (wDelta/2 + wMax * 40 - wR * 40) / wDelta;
4203     wGNorm = (wDelta/2 + wMax * 40 - wG * 40) / wDelta;
4204     wBNorm = (wDelta/2 + wMax * 40 - wB * 40) / wDelta;
4205
4206     if (wR == wMax)
4207       wHue = wBNorm - wGNorm;
4208     else if (wG == wMax)
4209       wHue = 80 + wRNorm - wBNorm;
4210     else
4211       wHue = 160 + wGNorm - wRNorm;
4212     if (wHue < 0)
4213       wHue += 240;
4214     else if (wHue > 240)
4215       wHue -= 240;
4216   }
4217   if (pwHue)
4218     *pwHue = wHue;
4219   if (pwLuminance)
4220     *pwLuminance = wLuminosity;
4221   if (pwSaturation)
4222     *pwSaturation = wSaturation;
4223 }
4224
4225 /*************************************************************************
4226  *      SHCreateShellPalette    [SHLWAPI.@]
4227  */
4228 HPALETTE WINAPI SHCreateShellPalette(HDC hdc)
4229 {
4230         FIXME("stub\n");
4231         return CreateHalftonePalette(hdc);
4232 }
4233
4234 /*************************************************************************
4235  *      SHGetInverseCMAP (SHLWAPI.@)
4236  *
4237  * Get an inverse color map table.
4238  *
4239  * PARAMS
4240  *  lpCmap  [O] Destination for color map
4241  *  dwSize  [I] Size of memory pointed to by lpCmap
4242  *
4243  * RETURNS
4244  *  Success: S_OK.
4245  *  Failure: E_POINTER,    If lpCmap is invalid.
4246  *           E_INVALIDARG, If dwFlags is invalid
4247  *           E_OUTOFMEMORY, If there is no memory available
4248  *
4249  * NOTES
4250  *  dwSize may only be CMAP_PTR_SIZE (4) or CMAP_SIZE (8192).
4251  *  If dwSize = CMAP_PTR_SIZE, *lpCmap is set to the address of this DLL's
4252  *  internal CMap.
4253  *  If dwSize = CMAP_SIZE, lpCmap is filled with a copy of the data from
4254  *  this DLL's internal CMap.
4255  */
4256 HRESULT WINAPI SHGetInverseCMAP(LPDWORD dest, DWORD dwSize)
4257 {
4258     if (dwSize == 4) {
4259         FIXME(" - returning bogus address for SHGetInverseCMAP\n");
4260         *dest = (DWORD)0xabba1249;
4261         return 0;
4262     }
4263     FIXME("(%p, %#x) stub\n", dest, dwSize);
4264     return 0;
4265 }
4266
4267 /*************************************************************************
4268  *      SHIsLowMemoryMachine    [SHLWAPI.@]
4269  *
4270  * Determine if the current computer has low memory.
4271  *
4272  * PARAMS
4273  *  x [I] FIXME
4274  *
4275  * RETURNS
4276  *  TRUE if the users machine has 16 Megabytes of memory or less,
4277  *  FALSE otherwise.
4278  */
4279 BOOL WINAPI SHIsLowMemoryMachine (DWORD x)
4280 {
4281   FIXME("(0x%08x) stub\n", x);
4282   return FALSE;
4283 }
4284
4285 /*************************************************************************
4286  *      GetMenuPosFromID        [SHLWAPI.@]
4287  *
4288  * Return the position of a menu item from its Id.
4289  *
4290  * PARAMS
4291  *   hMenu [I] Menu containing the item
4292  *   wID   [I] Id of the menu item
4293  *
4294  * RETURNS
4295  *  Success: The index of the menu item in hMenu.
4296  *  Failure: -1, If the item is not found.
4297  */
4298 INT WINAPI GetMenuPosFromID(HMENU hMenu, UINT wID)
4299 {
4300     MENUITEMINFOW mi;
4301     INT nCount = GetMenuItemCount(hMenu), nIter = 0;
4302
4303     TRACE("%p %u\n", hMenu, wID);
4304
4305     while (nIter < nCount)
4306     {
4307         mi.cbSize = sizeof(mi);
4308         mi.fMask = MIIM_ID;
4309         if (GetMenuItemInfoW(hMenu, nIter, TRUE, &mi) && mi.wID == wID)
4310         {
4311             TRACE("ret %d\n", nIter);
4312             return nIter;
4313         }
4314         nIter++;
4315     }
4316
4317     return -1;
4318 }
4319
4320 /*************************************************************************
4321  *      @       [SHLWAPI.179]
4322  *
4323  * Same as SHLWAPI.GetMenuPosFromID
4324  */
4325 DWORD WINAPI SHMenuIndexFromID(HMENU hMenu, UINT uID)
4326 {
4327     TRACE("%p %u\n", hMenu, uID);
4328     return GetMenuPosFromID(hMenu, uID);
4329 }
4330
4331
4332 /*************************************************************************
4333  *      @       [SHLWAPI.448]
4334  */
4335 VOID WINAPI FixSlashesAndColonW(LPWSTR lpwstr)
4336 {
4337     while (*lpwstr)
4338     {
4339         if (*lpwstr == '/')
4340             *lpwstr = '\\';
4341         lpwstr++;
4342     }
4343 }
4344
4345
4346 /*************************************************************************
4347  *      @       [SHLWAPI.461]
4348  */
4349 DWORD WINAPI SHGetAppCompatFlags(DWORD dwUnknown)
4350 {
4351   FIXME("(0x%08x) stub\n", dwUnknown);
4352   return 0;
4353 }
4354
4355
4356 /*************************************************************************
4357  *      @       [SHLWAPI.549]
4358  */
4359 HRESULT WINAPI SHCoCreateInstanceAC(REFCLSID rclsid, LPUNKNOWN pUnkOuter,
4360                                     DWORD dwClsContext, REFIID iid, LPVOID *ppv)
4361 {
4362     return CoCreateInstance(rclsid, pUnkOuter, dwClsContext, iid, ppv);
4363 }
4364
4365 /*************************************************************************
4366  * SHSkipJunction       [SHLWAPI.@]
4367  *
4368  * Determine if a bind context can be bound to an object
4369  *
4370  * PARAMS
4371  *  pbc    [I] Bind context to check
4372  *  pclsid [I] CLSID of object to be bound to
4373  *
4374  * RETURNS
4375  *  TRUE: If it is safe to bind
4376  *  FALSE: If pbc is invalid or binding would not be safe
4377  *
4378  */
4379 BOOL WINAPI SHSkipJunction(IBindCtx *pbc, const CLSID *pclsid)
4380 {
4381   static WCHAR szSkipBinding[] = { 'S','k','i','p',' ',
4382     'B','i','n','d','i','n','g',' ','C','L','S','I','D','\0' };
4383   BOOL bRet = FALSE;
4384
4385   if (pbc)
4386   {
4387     IUnknown* lpUnk;
4388
4389     if (SUCCEEDED(IBindCtx_GetObjectParam(pbc, szSkipBinding, &lpUnk)))
4390     {
4391       CLSID clsid;
4392
4393       if (SUCCEEDED(IUnknown_GetClassID(lpUnk, &clsid)) &&
4394           IsEqualGUID(pclsid, &clsid))
4395         bRet = TRUE;
4396
4397       IUnknown_Release(lpUnk);
4398     }
4399   }
4400   return bRet;
4401 }
4402
4403 /***********************************************************************
4404  *              SHGetShellKey (SHLWAPI.491)
4405  */
4406 HKEY WINAPI SHGetShellKey(DWORD flags, LPCWSTR sub_key, BOOL create)
4407 {
4408     enum _shellkey_flags {
4409         SHKEY_Explorer  = 0x00,
4410         SHKEY_Root_HKCU = 0x01
4411     };
4412
4413     static const WCHAR explorerW[] = {'S','o','f','t','w','a','r','e','\\',
4414         'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
4415         'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4416         'E','x','p','l','o','r','e','r',0};
4417     HKEY hroot, hkey = NULL;
4418
4419     TRACE("(0x%08x, %s, %d)\n", flags, debugstr_w(sub_key), create);
4420
4421     switch (flags)
4422     {
4423     case SHKEY_Explorer | SHKEY_Root_HKCU:
4424         RegOpenKeyExW(HKEY_CURRENT_USER, explorerW, 0, MAXIMUM_ALLOWED, &hroot);
4425         break;
4426     case 0:
4427         return NULL;
4428     default:
4429         FIXME("unsupported flags (0x%08x)\n", flags);
4430         return (HKEY)0xdeadbeef;
4431     }
4432
4433     if (create)
4434         RegCreateKeyExW(hroot, sub_key, 0, NULL, 0, MAXIMUM_ALLOWED, NULL, &hkey, NULL);
4435     else
4436         RegOpenKeyExW(hroot, sub_key, 0, MAXIMUM_ALLOWED, &hkey);
4437
4438     RegCloseKey(hroot);
4439     return hkey;
4440 }
4441
4442 /***********************************************************************
4443  *              SHQueueUserWorkItem (SHLWAPI.@)
4444  */
4445 BOOL WINAPI SHQueueUserWorkItem(LPTHREAD_START_ROUTINE pfnCallback, 
4446         LPVOID pContext, LONG lPriority, DWORD_PTR dwTag,
4447         DWORD_PTR *pdwId, LPCSTR pszModule, DWORD dwFlags)
4448 {
4449     TRACE("(%p, %p, %d, %lx, %p, %s, %08x)\n", pfnCallback, pContext,
4450           lPriority, dwTag, pdwId, debugstr_a(pszModule), dwFlags);
4451
4452     if(lPriority || dwTag || pdwId || pszModule || dwFlags)
4453         FIXME("Unsupported arguments\n");
4454
4455     return QueueUserWorkItem(pfnCallback, pContext, 0);
4456 }
4457
4458 /***********************************************************************
4459  *              SHSetTimerQueueTimer (SHLWAPI.263)
4460  */
4461 HANDLE WINAPI SHSetTimerQueueTimer(HANDLE hQueue,
4462         WAITORTIMERCALLBACK pfnCallback, LPVOID pContext, DWORD dwDueTime,
4463         DWORD dwPeriod, LPCSTR lpszLibrary, DWORD dwFlags)
4464 {
4465     HANDLE hNewTimer;
4466
4467     /* SHSetTimerQueueTimer flags -> CreateTimerQueueTimer flags */
4468     if (dwFlags & TPS_LONGEXECTIME) {
4469         dwFlags &= ~TPS_LONGEXECTIME;
4470         dwFlags |= WT_EXECUTELONGFUNCTION;
4471     }
4472     if (dwFlags & TPS_EXECUTEIO) {
4473         dwFlags &= ~TPS_EXECUTEIO;
4474         dwFlags |= WT_EXECUTEINIOTHREAD;
4475     }
4476
4477     if (!CreateTimerQueueTimer(&hNewTimer, hQueue, pfnCallback, pContext,
4478                                dwDueTime, dwPeriod, dwFlags))
4479         return NULL;
4480
4481     return hNewTimer;
4482 }
4483
4484 /***********************************************************************
4485  *              IUnknown_OnFocusChangeIS (SHLWAPI.@)
4486  */
4487 HRESULT WINAPI IUnknown_OnFocusChangeIS(LPUNKNOWN lpUnknown, LPUNKNOWN pFocusObject, BOOL bFocus)
4488 {
4489     IInputObjectSite *pIOS = NULL;
4490     HRESULT hRet = E_INVALIDARG;
4491
4492     TRACE("(%p, %p, %s)\n", lpUnknown, pFocusObject, bFocus ? "TRUE" : "FALSE");
4493
4494     if (lpUnknown)
4495     {
4496         hRet = IUnknown_QueryInterface(lpUnknown, &IID_IInputObjectSite,
4497                                        (void **)&pIOS);
4498         if (SUCCEEDED(hRet) && pIOS)
4499         {
4500             hRet = IInputObjectSite_OnFocusChangeIS(pIOS, pFocusObject, bFocus);
4501             IInputObjectSite_Release(pIOS);
4502         }
4503     }
4504     return hRet;
4505 }
4506
4507 /***********************************************************************
4508  *              SKGetValueW (SHLWAPI.516)
4509  */
4510 HRESULT WINAPI SKGetValueW(DWORD flags, LPCWSTR subkey, LPCWSTR value, DWORD *type,
4511     void *data, DWORD *count)
4512 {
4513     DWORD ret;
4514     HKEY hkey;
4515
4516     TRACE("(0x%x, %s, %s, %p, %p, %p)\n", flags, debugstr_w(subkey),
4517         debugstr_w(value), type, data, count);
4518
4519     hkey = SHGetShellKey(flags, subkey, FALSE);
4520     ret = SHQueryValueExW(hkey, value, NULL, type, data, count);
4521     RegCloseKey(hkey);
4522
4523     return HRESULT_FROM_WIN32(ret);
4524 }
4525
4526 typedef HRESULT (WINAPI *DllGetVersion_func)(DLLVERSIONINFO *);
4527
4528 /***********************************************************************
4529  *              GetUIVersion (SHLWAPI.452)
4530  */
4531 DWORD WINAPI GetUIVersion(void)
4532 {
4533     static DWORD version;
4534
4535     if (!version)
4536     {
4537         DllGetVersion_func pDllGetVersion;
4538         HMODULE dll = LoadLibraryA("shell32.dll");
4539         if (!dll) return 0;
4540
4541         pDllGetVersion = (DllGetVersion_func)GetProcAddress(dll, "DllGetVersion");
4542         if (pDllGetVersion)
4543         {
4544             DLLVERSIONINFO dvi;
4545             dvi.cbSize = sizeof(DLLVERSIONINFO);
4546             if (pDllGetVersion(&dvi) == S_OK) version = dvi.dwMajorVersion;
4547         }
4548         FreeLibrary( dll );
4549         if (!version) version = 3;  /* old shell dlls don't have DllGetVersion */
4550     }
4551     return version;
4552 }
4553
4554 /***********************************************************************
4555  *              ShellMessageBoxWrapW [SHLWAPI.388]
4556  *
4557  * See shell32.ShellMessageBoxW
4558  *
4559  * NOTE:
4560  * shlwapi.ShellMessageBoxWrapW is a duplicate of shell32.ShellMessageBoxW
4561  * because we can't forward to it in the .spec file since it's exported by
4562  * ordinal. If you change the implementation here please update the code in
4563  * shell32 as well.
4564  */
4565 INT WINAPIV ShellMessageBoxWrapW(HINSTANCE hInstance, HWND hWnd, LPCWSTR lpText,
4566                                  LPCWSTR lpCaption, UINT uType, ...)
4567 {
4568     WCHAR *szText = NULL, szTitle[100];
4569     LPCWSTR pszText, pszTitle = szTitle;
4570     LPWSTR pszTemp;
4571     __ms_va_list args;
4572     int ret;
4573
4574     __ms_va_start(args, uType);
4575
4576     TRACE("(%p,%p,%p,%p,%08x)\n", hInstance, hWnd, lpText, lpCaption, uType);
4577
4578     if (IS_INTRESOURCE(lpCaption))
4579         LoadStringW(hInstance, LOWORD(lpCaption), szTitle, sizeof(szTitle)/sizeof(szTitle[0]));
4580     else
4581         pszTitle = lpCaption;
4582
4583     if (IS_INTRESOURCE(lpText))
4584     {
4585         const WCHAR *ptr;
4586         UINT len = LoadStringW(hInstance, LOWORD(lpText), (LPWSTR)&ptr, 0);
4587
4588         if (len)
4589         {
4590             szText = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
4591             if (szText) LoadStringW(hInstance, LOWORD(lpText), szText, len + 1);
4592         }
4593         pszText = szText;
4594         if (!pszText) {
4595             WARN("Failed to load id %d\n", LOWORD(lpText));
4596             __ms_va_end(args);
4597             return 0;
4598         }
4599     }
4600     else
4601         pszText = lpText;
4602
4603     FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
4604                    pszText, 0, 0, (LPWSTR)&pszTemp, 0, &args);
4605
4606     __ms_va_end(args);
4607
4608     ret = MessageBoxW(hWnd, pszTemp, pszTitle, uType);
4609
4610     HeapFree(GetProcessHeap(), 0, szText);
4611     LocalFree(pszTemp);
4612     return ret;
4613 }
4614
4615 /***********************************************************************
4616  *              ZoneComputePaneSize [SHLWAPI.382]
4617  */
4618 UINT WINAPI ZoneComputePaneSize(HWND hwnd)
4619 {
4620     FIXME("\n");
4621     return 0x95;
4622 }
4623
4624 /***********************************************************************
4625  *              SHChangeNotifyWrap [SHLWAPI.394]
4626  */
4627 void WINAPI SHChangeNotifyWrap(LONG wEventId, UINT uFlags, LPCVOID dwItem1, LPCVOID dwItem2)
4628 {
4629     SHChangeNotify(wEventId, uFlags, dwItem1, dwItem2);
4630 }
4631
4632 typedef struct SHELL_USER_SID {   /* according to MSDN this should be in shlobj.h... */
4633     SID_IDENTIFIER_AUTHORITY sidAuthority;
4634     DWORD                    dwUserGroupID;
4635     DWORD                    dwUserID;
4636 } SHELL_USER_SID, *PSHELL_USER_SID;
4637
4638 typedef struct SHELL_USER_PERMISSION { /* ...and this should be in shlwapi.h */
4639     SHELL_USER_SID susID;
4640     DWORD          dwAccessType;
4641     BOOL           fInherit;
4642     DWORD          dwAccessMask;
4643     DWORD          dwInheritMask;
4644     DWORD          dwInheritAccessMask;
4645 } SHELL_USER_PERMISSION, *PSHELL_USER_PERMISSION;
4646
4647 /***********************************************************************
4648  *             GetShellSecurityDescriptor [SHLWAPI.475]
4649  *
4650  * prepares SECURITY_DESCRIPTOR from a set of ACEs
4651  *
4652  * PARAMS
4653  *  apUserPerm [I] array of pointers to SHELL_USER_PERMISSION structures,
4654  *                 each of which describes permissions to apply
4655  *  cUserPerm  [I] number of entries in apUserPerm array
4656  *
4657  * RETURNS
4658  *  success: pointer to SECURITY_DESCRIPTOR
4659  *  failure: NULL
4660  *
4661  * NOTES
4662  *  Call should free returned descriptor with LocalFree
4663  */
4664 PSECURITY_DESCRIPTOR WINAPI GetShellSecurityDescriptor(PSHELL_USER_PERMISSION *apUserPerm, int cUserPerm)
4665 {
4666     PSID *sidlist;
4667     PSID  cur_user = NULL;
4668     BYTE  tuUser[2000];
4669     DWORD acl_size;
4670     int   sid_count, i;
4671     PSECURITY_DESCRIPTOR psd = NULL;
4672
4673     TRACE("%p %d\n", apUserPerm, cUserPerm);
4674
4675     if (apUserPerm == NULL || cUserPerm <= 0)
4676         return NULL;
4677
4678     sidlist = HeapAlloc(GetProcessHeap(), 0, cUserPerm * sizeof(PSID));
4679     if (!sidlist)
4680         return NULL;
4681
4682     acl_size = sizeof(ACL);
4683
4684     for(sid_count = 0; sid_count < cUserPerm; sid_count++)
4685     {
4686         static SHELL_USER_SID null_sid = {{SECURITY_NULL_SID_AUTHORITY}, 0, 0};
4687         PSHELL_USER_PERMISSION perm = apUserPerm[sid_count];
4688         PSHELL_USER_SID sid = &perm->susID;
4689         PSID pSid;
4690         BOOL ret = TRUE;
4691
4692         if (!memcmp((void*)sid, (void*)&null_sid, sizeof(SHELL_USER_SID)))
4693         {  /* current user's SID */ 
4694             if (!cur_user)
4695             {
4696                 HANDLE Token;
4697                 DWORD bufsize = sizeof(tuUser);
4698
4699                 ret = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &Token);
4700                 if (ret)
4701                 {
4702                     ret = GetTokenInformation(Token, TokenUser, (void*)tuUser, bufsize, &bufsize );
4703                     if (ret)
4704                         cur_user = ((PTOKEN_USER)tuUser)->User.Sid;
4705                     CloseHandle(Token);
4706                 }
4707             }
4708             pSid = cur_user;
4709         } else if (sid->dwUserID==0) /* one sub-authority */
4710             ret = AllocateAndInitializeSid(&sid->sidAuthority, 1, sid->dwUserGroupID, 0,
4711                     0, 0, 0, 0, 0, 0, &pSid);
4712         else
4713             ret = AllocateAndInitializeSid(&sid->sidAuthority, 2, sid->dwUserGroupID, sid->dwUserID,
4714                     0, 0, 0, 0, 0, 0, &pSid);
4715         if (!ret)
4716             goto free_sids;
4717
4718         sidlist[sid_count] = pSid;
4719         /* increment acl_size (1 ACE for non-inheritable and 2 ACEs for inheritable records */
4720         acl_size += (sizeof(ACCESS_ALLOWED_ACE)-sizeof(DWORD) + GetLengthSid(pSid)) * (perm->fInherit ? 2 : 1);
4721     }
4722
4723     psd = LocalAlloc(0, sizeof(SECURITY_DESCRIPTOR) + acl_size);
4724
4725     if (psd != NULL)
4726     {
4727         PACL pAcl = (PACL)(((BYTE*)psd)+sizeof(SECURITY_DESCRIPTOR));
4728
4729         if (!InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION))
4730             goto error;
4731
4732         if (!InitializeAcl(pAcl, acl_size, ACL_REVISION))
4733             goto error;
4734
4735         for(i = 0; i < sid_count; i++)
4736         {
4737             PSHELL_USER_PERMISSION sup = apUserPerm[i];
4738             PSID sid = sidlist[i];
4739
4740             switch(sup->dwAccessType)
4741             {
4742                 case ACCESS_ALLOWED_ACE_TYPE:
4743                     if (!AddAccessAllowedAce(pAcl, ACL_REVISION, sup->dwAccessMask, sid))
4744                         goto error;
4745                     if (sup->fInherit && !AddAccessAllowedAceEx(pAcl, ACL_REVISION, 
4746                                 (BYTE)sup->dwInheritMask, sup->dwInheritAccessMask, sid))
4747                         goto error;
4748                     break;
4749                 case ACCESS_DENIED_ACE_TYPE:
4750                     if (!AddAccessDeniedAce(pAcl, ACL_REVISION, sup->dwAccessMask, sid))
4751                         goto error;
4752                     if (sup->fInherit && !AddAccessDeniedAceEx(pAcl, ACL_REVISION, 
4753                                 (BYTE)sup->dwInheritMask, sup->dwInheritAccessMask, sid))
4754                         goto error;
4755                     break;
4756                 default:
4757                     goto error;
4758             }
4759         }
4760
4761         if (!SetSecurityDescriptorDacl(psd, TRUE, pAcl, FALSE))
4762             goto error;
4763     }
4764     goto free_sids;
4765
4766 error:
4767     LocalFree(psd);
4768     psd = NULL;
4769 free_sids:
4770     for(i = 0; i < sid_count; i++)
4771     {
4772         if (!cur_user || sidlist[i] != cur_user)
4773             FreeSid(sidlist[i]);
4774     }
4775     HeapFree(GetProcessHeap(), 0, sidlist);
4776
4777     return psd;
4778 }
4779
4780 /***********************************************************************
4781  *             SHCreatePropertyBagOnRegKey [SHLWAPI.471]
4782  *
4783  * Creates a property bag from a registry key
4784  *
4785  * PARAMS
4786  *  hKey       [I] Handle to the desired registry key
4787  *  subkey     [I] Name of desired subkey, or NULL to open hKey directly
4788  *  grfMode    [I] Optional flags
4789  *  riid       [I] IID of requested property bag interface
4790  *  ppv        [O] Address to receive pointer to the new interface
4791  *
4792  * RETURNS
4793  *  success: 0
4794  *  failure: error code
4795  *
4796  */
4797 HRESULT WINAPI SHCreatePropertyBagOnRegKey (HKEY hKey, LPCWSTR subkey,
4798     DWORD grfMode, REFIID riid, void **ppv)
4799 {
4800     FIXME("%p %s %d %s %p STUB\n", hKey, debugstr_w(subkey), grfMode,
4801           debugstr_guid(riid), ppv);
4802
4803     return E_NOTIMPL;
4804 }
4805
4806 /***********************************************************************
4807  *             SHGetViewStatePropertyBag [SHLWAPI.515]
4808  *
4809  * Retrieves a property bag in which the view state information of a folder
4810  * can be stored.
4811  *
4812  * PARAMS
4813  *  pidl        [I] PIDL of the folder requested
4814  *  bag_name    [I] Name of the property bag requested
4815  *  flags       [I] Optional flags
4816  *  riid        [I] IID of requested property bag interface
4817  *  ppv         [O] Address to receive pointer to the new interface
4818  *
4819  * RETURNS
4820  *  success: S_OK
4821  *  failure: error code
4822  *
4823  */
4824 HRESULT WINAPI SHGetViewStatePropertyBag(LPCITEMIDLIST pidl, LPWSTR bag_name,
4825     DWORD flags, REFIID riid, void **ppv)
4826 {
4827     FIXME("%p %s %d %s %p STUB\n", pidl, debugstr_w(bag_name), flags,
4828           debugstr_guid(riid), ppv);
4829
4830     return E_NOTIMPL;
4831 }
4832
4833 /***********************************************************************
4834  *             SHFormatDateTimeW [SHLWAPI.354]
4835  *
4836  * Produces a string representation of a time.
4837  *
4838  * PARAMS
4839  *  fileTime   [I] Pointer to FILETIME structure specifying the time
4840  *  flags      [I] Flags specifying the desired output
4841  *  buf        [O] Pointer to buffer for output
4842  *  size       [I] Number of characters that can be contained in buffer
4843  *
4844  * RETURNS
4845  *  success: number of characters written to the buffer
4846  *  failure: 0
4847  *
4848  */
4849 INT WINAPI SHFormatDateTimeW(const FILETIME UNALIGNED *fileTime, DWORD *flags,
4850     LPWSTR buf, UINT size)
4851 {
4852 #define SHFORMATDT_UNSUPPORTED_FLAGS (FDTF_RELATIVE | FDTF_LTRDATE | FDTF_RTLDATE | FDTF_NOAUTOREADINGORDER)
4853     DWORD fmt_flags = flags ? *flags : FDTF_DEFAULT;
4854     SYSTEMTIME st;
4855     FILETIME ft;
4856     INT ret = 0;
4857
4858     TRACE("%p %p %p %u\n", fileTime, flags, buf, size);
4859
4860     if (!buf || !size)
4861         return 0;
4862
4863     if (fmt_flags & SHFORMATDT_UNSUPPORTED_FLAGS)
4864         FIXME("ignoring some flags - 0x%08x\n", fmt_flags & SHFORMATDT_UNSUPPORTED_FLAGS);
4865
4866     FileTimeToLocalFileTime(fileTime, &ft);
4867     FileTimeToSystemTime(&ft, &st);
4868
4869     /* first of all date */
4870     if (fmt_flags & (FDTF_LONGDATE | FDTF_SHORTDATE))
4871     {
4872         static const WCHAR sep1[] = {',',' ',0};
4873         static const WCHAR sep2[] = {' ',0};
4874
4875         DWORD date = fmt_flags & FDTF_LONGDATE ? DATE_LONGDATE : DATE_SHORTDATE;
4876         ret = GetDateFormatW(LOCALE_USER_DEFAULT, date, &st, NULL, buf, size);
4877         if (ret >= size) return ret;
4878
4879         /* add separator */
4880         if (ret < size && (fmt_flags & (FDTF_LONGTIME | FDTF_SHORTTIME)))
4881         {
4882             if ((fmt_flags & FDTF_LONGDATE) && (ret < size + 2))
4883             {
4884                 if (ret < size + 2)
4885                 {
4886                    lstrcatW(&buf[ret-1], sep1);
4887                    ret += 2;
4888                 }
4889             }
4890             else
4891             {
4892                 lstrcatW(&buf[ret-1], sep2);
4893                 ret++;
4894             }
4895         }
4896     }
4897     /* time part */
4898     if (fmt_flags & (FDTF_LONGTIME | FDTF_SHORTTIME))
4899     {
4900         DWORD time = fmt_flags & FDTF_LONGTIME ? 0 : TIME_NOSECONDS;
4901
4902         if (ret) ret--;
4903         ret += GetTimeFormatW(LOCALE_USER_DEFAULT, time, &st, NULL, &buf[ret], size - ret);
4904     }
4905
4906     return ret;
4907
4908 #undef SHFORMATDT_UNSUPPORTED_FLAGS
4909 }
4910
4911 /***********************************************************************
4912  *             SHFormatDateTimeA [SHLWAPI.353]
4913  *
4914  * See SHFormatDateTimeW.
4915  *
4916  */
4917 INT WINAPI SHFormatDateTimeA(const FILETIME UNALIGNED *fileTime, DWORD *flags,
4918     LPSTR buf, UINT size)
4919 {
4920     WCHAR *bufW;
4921     INT retval;
4922
4923     if (!buf || !size)
4924         return 0;
4925
4926     bufW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * size);
4927     retval = SHFormatDateTimeW(fileTime, flags, bufW, size);
4928
4929     if (retval != 0)
4930         WideCharToMultiByte(CP_ACP, 0, bufW, -1, buf, size, NULL, NULL);
4931
4932     HeapFree(GetProcessHeap(), 0, bufW);
4933     return retval;
4934 }
4935
4936 /***********************************************************************
4937  *             ZoneCheckUrlExW [SHLWAPI.231]
4938  *
4939  * Checks the details of the security zone for the supplied site. (?)
4940  *
4941  * PARAMS
4942  *
4943  *  szURL   [I] Pointer to the URL to check
4944  *
4945  *  Other parameters currently unknown.
4946  *
4947  * RETURNS
4948  *  unknown
4949  */
4950
4951 INT WINAPI ZoneCheckUrlExW(LPWSTR szURL, PVOID pUnknown, DWORD dwUnknown2,
4952     DWORD dwUnknown3, DWORD dwUnknown4, DWORD dwUnknown5, DWORD dwUnknown6,
4953     DWORD dwUnknown7)
4954 {
4955     FIXME("(%s,%p,%x,%x,%x,%x,%x,%x) STUB\n", debugstr_w(szURL), pUnknown, dwUnknown2,
4956         dwUnknown3, dwUnknown4, dwUnknown5, dwUnknown6, dwUnknown7);
4957
4958     return 0;
4959 }
4960
4961 /***********************************************************************
4962  *             SHVerbExistsNA [SHLWAPI.196]
4963  *
4964  *
4965  * PARAMS
4966  *
4967  *  verb [I] a string, often appears to be an extension.
4968  *
4969  *  Other parameters currently unknown.
4970  *
4971  * RETURNS
4972  *  unknown
4973  */
4974 INT WINAPI SHVerbExistsNA(LPSTR verb, PVOID pUnknown, PVOID pUnknown2, DWORD dwUnknown3)
4975 {
4976     FIXME("(%s, %p, %p, %i) STUB\n",verb, pUnknown, pUnknown2, dwUnknown3);
4977     return 0;
4978 }
4979
4980 /*************************************************************************
4981  *      @       [SHLWAPI.538]
4982  *
4983  *  Undocumented:  Implementation guessed at via Name and behavior
4984  *
4985  * PARAMS
4986  *  lpUnknown [I] Object to get an IServiceProvider interface from
4987  *  riid      [I] Function requested for QueryService call
4988  *  lppOut    [O] Destination for the service interface pointer
4989  *
4990  * RETURNS
4991  *  Success: S_OK. lppOut contains an object providing the requested service
4992  *  Failure: An HRESULT error code
4993  *
4994  * NOTES
4995  *  lpUnknown is expected to support the IServiceProvider interface.
4996  */
4997 HRESULT WINAPI IUnknown_QueryServiceForWebBrowserApp(IUnknown* lpUnknown,
4998         REFGUID riid, LPVOID *lppOut)
4999 {
5000     FIXME("%p %s %p semi-STUB\n", lpUnknown, debugstr_guid(riid), lppOut);
5001     return IUnknown_QueryService(lpUnknown,&IID_IWebBrowserApp,riid,lppOut);
5002 }
5003
5004 /**************************************************************************
5005  *  SHPropertyBag_ReadLONG (SHLWAPI.496)
5006  *
5007  * This function asks a property bag to read a named property as a LONG.
5008  *
5009  * PARAMS
5010  *  ppb: a IPropertyBag interface
5011  *  pszPropName:  Unicode string that names the property
5012  *  pValue: address to receive the property value as a 32-bit signed integer
5013  *
5014  * RETURNS
5015  *  0 for Success
5016  */
5017 BOOL WINAPI SHPropertyBag_ReadLONG(IPropertyBag *ppb, LPCWSTR pszPropName, LPLONG pValue)
5018 {
5019     VARIANT var;
5020     HRESULT hr;
5021     TRACE("%p %s %p\n", ppb,debugstr_w(pszPropName),pValue);
5022     if (!pszPropName || !ppb || !pValue)
5023         return E_INVALIDARG;
5024     V_VT(&var) = VT_I4;
5025     hr = IPropertyBag_Read(ppb, pszPropName, &var, NULL);
5026     if (SUCCEEDED(hr))
5027     {
5028         if (V_VT(&var) == VT_I4)
5029             *pValue = V_I4(&var);
5030         else
5031             hr = DISP_E_BADVARTYPE;
5032     }
5033     return hr;
5034 }
5035
5036 /* return flags for SHGetObjectCompatFlags, names derived from registry value names */
5037 #define OBJCOMPAT_OTNEEDSSFCACHE           0x00000001
5038 #define OBJCOMPAT_NO_WEBVIEW               0x00000002
5039 #define OBJCOMPAT_UNBINDABLE               0x00000004
5040 #define OBJCOMPAT_PINDLL                   0x00000008
5041 #define OBJCOMPAT_NEEDSFILESYSANCESTOR     0x00000010
5042 #define OBJCOMPAT_NOTAFILESYSTEM           0x00000020
5043 #define OBJCOMPAT_CTXMENU_NOVERBS          0x00000040
5044 #define OBJCOMPAT_CTXMENU_LIMITEDQI        0x00000080
5045 #define OBJCOMPAT_COCREATESHELLFOLDERONLY  0x00000100
5046 #define OBJCOMPAT_NEEDSSTORAGEANCESTOR     0x00000200
5047 #define OBJCOMPAT_NOLEGACYWEBVIEW          0x00000400
5048 #define OBJCOMPAT_CTXMENU_XPQCMFLAGS       0x00001000
5049 #define OBJCOMPAT_NOIPROPERTYSTORE         0x00002000
5050
5051 /* a search table for compatibility flags */
5052 struct objcompat_entry {
5053     const WCHAR name[30];
5054     DWORD value;
5055 };
5056
5057 /* expected to be sorted by name */
5058 static const struct objcompat_entry objcompat_table[] = {
5059     { {'C','O','C','R','E','A','T','E','S','H','E','L','L','F','O','L','D','E','R','O','N','L','Y',0},
5060       OBJCOMPAT_COCREATESHELLFOLDERONLY },
5061     { {'C','T','X','M','E','N','U','_','L','I','M','I','T','E','D','Q','I',0},
5062       OBJCOMPAT_CTXMENU_LIMITEDQI },
5063     { {'C','T','X','M','E','N','U','_','N','O','V','E','R','B','S',0},
5064       OBJCOMPAT_CTXMENU_LIMITEDQI },
5065     { {'C','T','X','M','E','N','U','_','X','P','Q','C','M','F','L','A','G','S',0},
5066       OBJCOMPAT_CTXMENU_XPQCMFLAGS },
5067     { {'N','E','E','D','S','F','I','L','E','S','Y','S','A','N','C','E','S','T','O','R',0},
5068       OBJCOMPAT_NEEDSFILESYSANCESTOR },
5069     { {'N','E','E','D','S','S','T','O','R','A','G','E','A','N','C','E','S','T','O','R',0},
5070       OBJCOMPAT_NEEDSSTORAGEANCESTOR },
5071     { {'N','O','I','P','R','O','P','E','R','T','Y','S','T','O','R','E',0},
5072       OBJCOMPAT_NOIPROPERTYSTORE },
5073     { {'N','O','L','E','G','A','C','Y','W','E','B','V','I','E','W',0},
5074       OBJCOMPAT_NOLEGACYWEBVIEW },
5075     { {'N','O','T','A','F','I','L','E','S','Y','S','T','E','M',0},
5076       OBJCOMPAT_NOTAFILESYSTEM },
5077     { {'N','O','_','W','E','B','V','I','E','W',0},
5078       OBJCOMPAT_NO_WEBVIEW },
5079     { {'O','T','N','E','E','D','S','S','F','C','A','C','H','E',0},
5080       OBJCOMPAT_OTNEEDSSFCACHE },
5081     { {'P','I','N','D','L','L',0},
5082       OBJCOMPAT_PINDLL },
5083     { {'U','N','B','I','N','D','A','B','L','E',0},
5084       OBJCOMPAT_UNBINDABLE }
5085 };
5086
5087 /**************************************************************************
5088  *  SHGetObjectCompatFlags (SHLWAPI.476)
5089  *
5090  * Function returns an integer representation of compatibility flags stored
5091  * in registry for CLSID under ShellCompatibility subkey.
5092  *
5093  * PARAMS
5094  *  pUnk:  pointer to object IUnknown interface, idetifies CLSID
5095  *  clsid: pointer to CLSID to retrieve data for
5096  *
5097  * RETURNS
5098  *  0 on failure, flags set on success
5099  */
5100 DWORD WINAPI SHGetObjectCompatFlags(IUnknown *pUnk, const CLSID *clsid)
5101 {
5102     static const WCHAR compatpathW[] =
5103         {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
5104          'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5105          'S','h','e','l','l','C','o','m','p','a','t','i','b','i','l','i','t','y','\\',
5106          'O','b','j','e','c','t','s','\\','%','s',0};
5107     WCHAR strW[sizeof(compatpathW)/sizeof(WCHAR) + 38 /* { CLSID } */];
5108     DWORD ret, length = sizeof(strW)/sizeof(WCHAR);
5109     OLECHAR *clsid_str;
5110     HKEY key;
5111     INT i;
5112
5113     TRACE("%p %s\n", pUnk, debugstr_guid(clsid));
5114
5115     if (!pUnk && !clsid) return 0;
5116
5117     if (pUnk && !clsid)
5118     {
5119         FIXME("iface not handled\n");
5120         return 0;
5121     }
5122
5123     StringFromCLSID(clsid, &clsid_str);
5124     sprintfW(strW, compatpathW, clsid_str);
5125     CoTaskMemFree(clsid_str);
5126
5127     ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, strW, &key);
5128     if (ret != ERROR_SUCCESS) return 0;
5129
5130     /* now collect flag values */
5131     ret = 0;
5132     for (i = 0; RegEnumValueW(key, i, strW, &length, NULL, NULL, NULL, NULL) == ERROR_SUCCESS; i++)
5133     {
5134         INT left, right, res, x;
5135
5136         /* search in table */
5137         left  = 0;
5138         right = sizeof(objcompat_table) / sizeof(struct objcompat_entry) - 1;
5139
5140         while (right >= left) {
5141             x = (left + right) / 2;
5142             res = strcmpW(strW, objcompat_table[x].name);
5143             if (res == 0)
5144             {
5145                 ret |= objcompat_table[x].value;
5146                 break;
5147             }
5148             else if (res < 0)
5149                 right = x - 1;
5150             else
5151                 left = x + 1;
5152         }
5153
5154         length = sizeof(strW)/sizeof(WCHAR);
5155     }
5156
5157     return ret;
5158 }