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