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