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