db2c57125644a1cdb65d94e31084d5ab76499959
[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 "precomp.h"
24
25 #include <stdio.h>
26
27 #include <winver.h>
28 #include <winnetwk.h>
29 #include <mmsystem.h>
30 #include <shdeprecated.h>
31 #include <shellapi.h>
32 #include <commdlg.h>
33 #include <mlang.h>
34 #include <mshtmhst.h>
35
36 /* DLL handles for late bound calls */
37 extern HINSTANCE shlwapi_hInstance;
38 extern DWORD SHLWAPI_ThreadRef_index;
39
40 HRESULT WINAPI IUnknown_QueryService(IUnknown*,REFGUID,REFIID,LPVOID*);
41 HRESULT WINAPI SHInvokeCommand(HWND,IShellFolder*,LPCITEMIDLIST,DWORD);
42 BOOL WINAPI SHAboutInfoW(LPWSTR,DWORD);
43
44 /*
45 NOTES: Most functions exported by ordinal seem to be superfluous.
46 The reason for these functions to be there is to provide a wrapper
47 for unicode functions to provide these functions on systems without
48 unicode functions eg. win95/win98. Since we have such functions we just
49 call these. If running Wine with native DLLs, some late bound calls may
50 fail. However, it is better to implement the functions in the forward DLL
51 and recommend the builtin rather than reimplementing the calls here!
52 */
53
54 /*************************************************************************
55 * SHLWAPI_DupSharedHandle
56 *
57 * Internal implementation of SHLWAPI_11.
58 */
59 static HANDLE SHLWAPI_DupSharedHandle(HANDLE hShared, DWORD dwDstProcId,
60 DWORD dwSrcProcId, DWORD dwAccess,
61 DWORD dwOptions)
62 {
63 HANDLE hDst, hSrc;
64 DWORD dwMyProcId = GetCurrentProcessId();
65 HANDLE hRet = NULL;
66
67 TRACE("(%p,%d,%d,%08x,%08x)\n", hShared, dwDstProcId, dwSrcProcId,
68 dwAccess, dwOptions);
69
70 /* Get dest process handle */
71 if (dwDstProcId == dwMyProcId)
72 hDst = GetCurrentProcess();
73 else
74 hDst = OpenProcess(PROCESS_DUP_HANDLE, 0, dwDstProcId);
75
76 if (hDst)
77 {
78 /* Get src process handle */
79 if (dwSrcProcId == dwMyProcId)
80 hSrc = GetCurrentProcess();
81 else
82 hSrc = OpenProcess(PROCESS_DUP_HANDLE, 0, dwSrcProcId);
83
84 if (hSrc)
85 {
86 /* Make handle available to dest process */
87 if (!DuplicateHandle(hDst, hShared, hSrc, &hRet,
88 dwAccess, 0, dwOptions | DUPLICATE_SAME_ACCESS))
89 hRet = NULL;
90
91 if (dwSrcProcId != dwMyProcId)
92 CloseHandle(hSrc);
93 }
94
95 if (dwDstProcId != dwMyProcId)
96 CloseHandle(hDst);
97 }
98
99 TRACE("Returning handle %p\n", hRet);
100 return hRet;
101 }
102
103 /*************************************************************************
104 * @ [SHLWAPI.7]
105 *
106 * Create a block of sharable memory and initialise it with data.
107 *
108 * PARAMS
109 * lpvData [I] Pointer to data to write
110 * dwSize [I] Size of data
111 * dwProcId [I] ID of process owning data
112 *
113 * RETURNS
114 * Success: A shared memory handle
115 * Failure: NULL
116 *
117 * NOTES
118 * Ordinals 7-11 provide a set of calls to create shared memory between a
119 * group of processes. The shared memory is treated opaquely in that its size
120 * is not exposed to clients who map it. This is accomplished by storing
121 * the size of the map as the first DWORD of mapped data, and then offsetting
122 * the view pointer returned by this size.
123 *
124 */
125 HANDLE WINAPI SHAllocShared(LPCVOID lpvData, DWORD dwSize, DWORD dwProcId)
126 {
127 HANDLE hMap;
128 LPVOID pMapped;
129 HANDLE hRet = NULL;
130
131 TRACE("(%p,%d,%d)\n", lpvData, dwSize, dwProcId);
132
133 /* Create file mapping of the correct length */
134 hMap = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, FILE_MAP_READ, 0,
135 dwSize + sizeof(dwSize), NULL);
136 if (!hMap)
137 return hRet;
138
139 /* Get a view in our process address space */
140 pMapped = MapViewOfFile(hMap, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
141
142 if (pMapped)
143 {
144 /* Write size of data, followed by the data, to the view */
145 *((DWORD*)pMapped) = dwSize;
146 if (lpvData)
147 memcpy((char *) pMapped + sizeof(dwSize), lpvData, dwSize);
148
149 /* Release view. All further views mapped will be opaque */
150 UnmapViewOfFile(pMapped);
151 hRet = SHLWAPI_DupSharedHandle(hMap, dwProcId,
152 GetCurrentProcessId(), FILE_MAP_ALL_ACCESS,
153 DUPLICATE_SAME_ACCESS);
154 }
155
156 CloseHandle(hMap);
157 return hRet;
158 }
159
160 /*************************************************************************
161 * @ [SHLWAPI.8]
162 *
163 * Get a pointer to a block of shared memory from a shared memory handle.
164 *
165 * PARAMS
166 * hShared [I] Shared memory handle
167 * dwProcId [I] ID of process owning hShared
168 *
169 * RETURNS
170 * Success: A pointer to the shared memory
171 * Failure: NULL
172 *
173 */
174 PVOID WINAPI SHLockShared(HANDLE hShared, DWORD dwProcId)
175 {
176 HANDLE hDup;
177 LPVOID pMapped;
178
179 TRACE("(%p %d)\n", hShared, dwProcId);
180
181 /* Get handle to shared memory for current process */
182 hDup = SHLWAPI_DupSharedHandle(hShared, dwProcId, GetCurrentProcessId(),
183 FILE_MAP_ALL_ACCESS, 0);
184 /* Get View */
185 pMapped = MapViewOfFile(hDup, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
186 CloseHandle(hDup);
187
188 if (pMapped)
189 return (char *) pMapped + sizeof(DWORD); /* Hide size */
190 return NULL;
191 }
192
193 /*************************************************************************
194 * @ [SHLWAPI.9]
195 *
196 * Release a pointer to a block of shared memory.
197 *
198 * PARAMS
199 * lpView [I] Shared memory pointer
200 *
201 * RETURNS
202 * Success: TRUE
203 * Failure: FALSE
204 *
205 */
206 BOOL WINAPI SHUnlockShared(LPVOID lpView)
207 {
208 TRACE("(%p)\n", lpView);
209 return UnmapViewOfFile((char *) lpView - sizeof(DWORD)); /* Include size */
210 }
211
212 /*************************************************************************
213 * @ [SHLWAPI.10]
214 *
215 * Destroy a block of sharable memory.
216 *
217 * PARAMS
218 * hShared [I] Shared memory handle
219 * dwProcId [I] ID of process owning hShared
220 *
221 * RETURNS
222 * Success: TRUE
223 * Failure: FALSE
224 *
225 */
226 BOOL WINAPI SHFreeShared(HANDLE hShared, DWORD dwProcId)
227 {
228 HANDLE hClose;
229
230 TRACE("(%p %d)\n", hShared, dwProcId);
231
232 /* Get a copy of the handle for our process, closing the source handle */
233 hClose = SHLWAPI_DupSharedHandle(hShared, dwProcId, GetCurrentProcessId(),
234 FILE_MAP_ALL_ACCESS,DUPLICATE_CLOSE_SOURCE);
235 /* Close local copy */
236 return CloseHandle(hClose);
237 }
238
239 /*************************************************************************
240 * @ [SHLWAPI.11]
241 *
242 * Copy a sharable memory handle from one process to another.
243 *
244 * PARAMS
245 * hShared [I] Shared memory handle to duplicate
246 * dwDstProcId [I] ID of the process wanting the duplicated handle
247 * dwSrcProcId [I] ID of the process owning hShared
248 * dwAccess [I] Desired DuplicateHandle() access
249 * dwOptions [I] Desired DuplicateHandle() options
250 *
251 * RETURNS
252 * Success: A handle suitable for use by the dwDstProcId process.
253 * Failure: A NULL handle.
254 *
255 */
256 HANDLE WINAPI SHMapHandle(HANDLE hShared, DWORD dwDstProcId, DWORD dwSrcProcId,
257 DWORD dwAccess, DWORD dwOptions)
258 {
259 HANDLE hRet;
260
261 hRet = SHLWAPI_DupSharedHandle(hShared, dwDstProcId, dwSrcProcId,
262 dwAccess, dwOptions);
263 return hRet;
264 }
265
266 /*************************************************************************
267 * @ [SHLWAPI.13]
268 *
269 * Create and register a clipboard enumerator for a web browser.
270 *
271 * PARAMS
272 * lpBC [I] Binding context
273 * lpUnknown [I] An object exposing the IWebBrowserApp interface
274 *
275 * RETURNS
276 * Success: S_OK.
277 * Failure: An HRESULT error code.
278 *
279 * NOTES
280 * The enumerator is stored as a property of the web browser. If it does not
281 * yet exist, it is created and set before being registered.
282 */
283 HRESULT WINAPI RegisterDefaultAcceptHeaders(LPBC lpBC, IUnknown *lpUnknown)
284 {
285 static const WCHAR szProperty[] = { '{','D','0','F','C','A','4','2','0',
286 '-','D','3','F','5','-','1','1','C','F', '-','B','2','1','1','-','0',
287 '0','A','A','0','0','4','A','E','8','3','7','}','\0' };
288 BSTR property;
289 IEnumFORMATETC* pIEnumFormatEtc = NULL;
290 VARIANTARG var;
291 HRESULT hr;
292 IWebBrowserApp* pBrowser;
293
294 TRACE("(%p, %p)\n", lpBC, lpUnknown);
295
296 hr = IUnknown_QueryService(lpUnknown, &IID_IWebBrowserApp, &IID_IWebBrowserApp, (void**)&pBrowser);
297 if (FAILED(hr))
298 return hr;
299
300 V_VT(&var) = VT_EMPTY;
301
302 /* The property we get is the browsers clipboard enumerator */
303 property = SysAllocString(szProperty);
304 hr = IWebBrowserApp_GetProperty(pBrowser, property, &var);
305 SysFreeString(property);
306 if (FAILED(hr)) goto exit;
307
308 if (V_VT(&var) == VT_EMPTY)
309 {
310 /* Iterate through accepted documents and RegisterClipBoardFormatA() them */
311 char szKeyBuff[128], szValueBuff[128];
312 DWORD dwKeySize, dwValueSize, dwRet = 0, dwCount = 0, dwNumValues, dwType;
313 FORMATETC* formatList, *format;
314 HKEY hDocs;
315
316 TRACE("Registering formats and creating IEnumFORMATETC instance\n");
317
318 if (!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\Current"
319 "Version\\Internet Settings\\Accepted Documents", &hDocs))
320 {
321 hr = E_FAIL;
322 goto exit;
323 }
324
325 /* Get count of values in key */
326 while (!dwRet)
327 {
328 dwKeySize = sizeof(szKeyBuff);
329 dwRet = RegEnumValueA(hDocs,dwCount,szKeyBuff,&dwKeySize,0,&dwType,0,0);
330 dwCount++;
331 }
332
333 dwNumValues = dwCount;
334
335 /* Note: dwCount = number of items + 1; The extra item is the end node */
336 format = formatList = HeapAlloc(GetProcessHeap(), 0, dwCount * sizeof(FORMATETC));
337 if (!formatList)
338 {
339 RegCloseKey(hDocs);
340 hr = E_OUTOFMEMORY;
341 goto exit;
342 }
343
344 if (dwNumValues > 1)
345 {
346 dwRet = 0;
347 dwCount = 0;
348
349 dwNumValues--;
350
351 /* Register clipboard formats for the values and populate format list */
352 while(!dwRet && dwCount < dwNumValues)
353 {
354 dwKeySize = sizeof(szKeyBuff);
355 dwValueSize = sizeof(szValueBuff);
356 dwRet = RegEnumValueA(hDocs, dwCount, szKeyBuff, &dwKeySize, 0, &dwType,
357 (PBYTE)szValueBuff, &dwValueSize);
358 if (!dwRet)
359 {
360 HeapFree(GetProcessHeap(), 0, formatList);
361 RegCloseKey(hDocs);
362 hr = E_FAIL;
363 goto exit;
364 }
365
366 format->cfFormat = RegisterClipboardFormatA(szValueBuff);
367 format->ptd = NULL;
368 format->dwAspect = 1;
369 format->lindex = 4;
370 format->tymed = -1;
371
372 format++;
373 dwCount++;
374 }
375 }
376
377 RegCloseKey(hDocs);
378
379 /* Terminate the (maybe empty) list, last entry has a cfFormat of 0 */
380 format->cfFormat = 0;
381 format->ptd = NULL;
382 format->dwAspect = 1;
383 format->lindex = 4;
384 format->tymed = -1;
385
386 /* Create a clipboard enumerator */
387 hr = CreateFormatEnumerator(dwNumValues, formatList, &pIEnumFormatEtc);
388 HeapFree(GetProcessHeap(), 0, formatList);
389 if (FAILED(hr)) goto exit;
390
391 /* Set our enumerator as the browsers property */
392 V_VT(&var) = VT_UNKNOWN;
393 V_UNKNOWN(&var) = (IUnknown*)pIEnumFormatEtc;
394
395 property = SysAllocString(szProperty);
396 hr = IWebBrowserApp_PutProperty(pBrowser, property, var);
397 SysFreeString(property);
398 if (FAILED(hr))
399 {
400 IEnumFORMATETC_Release(pIEnumFormatEtc);
401 goto exit;
402 }
403 }
404
405 if (V_VT(&var) == VT_UNKNOWN)
406 {
407 /* Our variant is holding the clipboard enumerator */
408 IUnknown* pIUnknown = V_UNKNOWN(&var);
409 IEnumFORMATETC* pClone = NULL;
410
411 TRACE("Retrieved IEnumFORMATETC property\n");
412
413 /* Get an IEnumFormatEtc interface from the variants value */
414 pIEnumFormatEtc = NULL;
415 hr = IUnknown_QueryInterface(pIUnknown, &IID_IEnumFORMATETC, (void**)&pIEnumFormatEtc);
416 if (hr == S_OK && pIEnumFormatEtc)
417 {
418 /* Clone and register the enumerator */
419 hr = IEnumFORMATETC_Clone(pIEnumFormatEtc, &pClone);
420 if (hr == S_OK && pClone)
421 {
422 RegisterFormatEnumerator(lpBC, pClone, 0);
423
424 IEnumFORMATETC_Release(pClone);
425 }
426
427 IUnknown_Release(pIUnknown);
428 }
429 IUnknown_Release(V_UNKNOWN(&var));
430 }
431
432 exit:
433 IWebBrowserApp_Release(pBrowser);
434 return hr;
435 }
436
437 /*************************************************************************
438 * @ [SHLWAPI.15]
439 *
440 * Get Explorers "AcceptLanguage" setting.
441 *
442 * PARAMS
443 * langbuf [O] Destination for language string
444 * buflen [I] Length of langbuf in characters
445 * [0] Success: used length of langbuf
446 *
447 * RETURNS
448 * Success: S_OK. langbuf is set to the language string found.
449 * Failure: E_FAIL, If any arguments are invalid, error occurred, or Explorer
450 * does not contain the setting.
451 * HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), If the buffer is not big enough
452 */
453 HRESULT WINAPI GetAcceptLanguagesW( LPWSTR langbuf, LPDWORD buflen)
454 {
455 static const WCHAR szkeyW[] = {
456 'S','o','f','t','w','a','r','e','\\',
457 'M','i','c','r','o','s','o','f','t','\\',
458 'I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r','\\',
459 'I','n','t','e','r','n','a','t','i','o','n','a','l',0};
460 static const WCHAR valueW[] = {
461 'A','c','c','e','p','t','L','a','n','g','u','a','g','e',0};
462 DWORD mystrlen, mytype;
463 DWORD len;
464 HKEY mykey;
465 LCID mylcid;
466 WCHAR *mystr;
467 LONG lres;
468
469 TRACE("(%p, %p) *%p: %d\n", langbuf, buflen, buflen, buflen ? *buflen : -1);
470
471 if(!langbuf || !buflen || !*buflen)
472 return E_FAIL;
473
474 mystrlen = (*buflen > 20) ? *buflen : 20 ;
475 len = mystrlen * sizeof(WCHAR);
476 mystr = HeapAlloc(GetProcessHeap(), 0, len);
477 mystr[0] = 0;
478 RegOpenKeyW(HKEY_CURRENT_USER, szkeyW, &mykey);
479 lres = RegQueryValueExW(mykey, valueW, 0, &mytype, (PBYTE)mystr, &len);
480 RegCloseKey(mykey);
481 len = lstrlenW(mystr);
482
483 if (!lres && (*buflen > len)) {
484 lstrcpyW(langbuf, mystr);
485 *buflen = len;
486 HeapFree(GetProcessHeap(), 0, mystr);
487 return S_OK;
488 }
489
490 /* Did not find a value in the registry or the user buffer is too small */
491 mylcid = GetUserDefaultLCID();
492 LcidToRfc1766W(mylcid, mystr, mystrlen);
493 len = lstrlenW(mystr);
494
495 memcpy( langbuf, mystr, min(*buflen, len+1)*sizeof(WCHAR) );
496 HeapFree(GetProcessHeap(), 0, mystr);
497
498 if (*buflen > len) {
499 *buflen = len;
500 return S_OK;
501 }
502
503 *buflen = 0;
504 return __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
505 }
506
507 /*************************************************************************
508 * @ [SHLWAPI.14]
509 *
510 * Ascii version of GetAcceptLanguagesW.
511 */
512 HRESULT WINAPI GetAcceptLanguagesA( LPSTR langbuf, LPDWORD buflen)
513 {
514 WCHAR *langbufW;
515 DWORD buflenW, convlen;
516 HRESULT retval;
517
518 TRACE("(%p, %p) *%p: %d\n", langbuf, buflen, buflen, buflen ? *buflen : -1);
519
520 if(!langbuf || !buflen || !*buflen) return E_FAIL;
521
522 buflenW = *buflen;
523 langbufW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * buflenW);
524 retval = GetAcceptLanguagesW(langbufW, &buflenW);
525
526 if (retval == S_OK)
527 {
528 convlen = WideCharToMultiByte(CP_ACP, 0, langbufW, -1, langbuf, *buflen, NULL, NULL);
529 convlen--; /* do not count the terminating 0 */
530 }
531 else /* copy partial string anyway */
532 {
533 convlen = WideCharToMultiByte(CP_ACP, 0, langbufW, *buflen, langbuf, *buflen, NULL, NULL);
534 if (convlen < *buflen)
535 {
536 langbuf[convlen] = 0;
537 convlen--; /* do not count the terminating 0 */
538 }
539 else
540 {
541 convlen = *buflen;
542 }
543 }
544 *buflen = buflenW ? convlen : 0;
545
546 HeapFree(GetProcessHeap(), 0, langbufW);
547 return retval;
548 }
549
550 /*************************************************************************
551 * @ [SHLWAPI.23]
552 *
553 * Convert a GUID to a string.
554 *
555 * PARAMS
556 * guid [I] GUID to convert
557 * lpszDest [O] Destination for string
558 * cchMax [I] Length of output buffer
559 *
560 * RETURNS
561 * The length of the string created.
562 */
563 INT WINAPI SHStringFromGUIDA(REFGUID guid, LPSTR lpszDest, INT cchMax)
564 {
565 char xguid[40];
566 INT iLen;
567
568 TRACE("(%s,%p,%d)\n", debugstr_guid(guid), lpszDest, cchMax);
569
570 sprintf(xguid, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
571 guid->Data1, guid->Data2, guid->Data3,
572 guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
573 guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
574
575 iLen = strlen(xguid) + 1;
576
577 if (iLen > cchMax)
578 return 0;
579 memcpy(lpszDest, xguid, iLen);
580 return iLen;
581 }
582
583 /*************************************************************************
584 * @ [SHLWAPI.24]
585 *
586 * Convert a GUID to a string.
587 *
588 * PARAMS
589 * guid [I] GUID to convert
590 * str [O] Destination for string
591 * cmax [I] Length of output buffer
592 *
593 * RETURNS
594 * The length of the string created.
595 */
596 INT WINAPI SHStringFromGUIDW(REFGUID guid, LPWSTR lpszDest, INT cchMax)
597 {
598 WCHAR xguid[40];
599 INT iLen;
600 static const WCHAR wszFormat[] = {'{','%','0','8','l','X','-','%','0','4','X','-','%','0','4','X','-',
601 '%','0','2','X','%','0','2','X','-','%','0','2','X','%','0','2','X','%','0','2','X','%','0','2',
602 'X','%','0','2','X','%','0','2','X','}',0};
603
604 TRACE("(%s,%p,%d)\n", debugstr_guid(guid), lpszDest, cchMax);
605
606 sprintfW(xguid, wszFormat, guid->Data1, guid->Data2, guid->Data3,
607 guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
608 guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
609
610 iLen = strlenW(xguid) + 1;
611
612 if (iLen > cchMax)
613 return 0;
614 memcpy(lpszDest, xguid, iLen*sizeof(WCHAR));
615 return iLen;
616 }
617
618 /*************************************************************************
619 * @ [SHLWAPI.30]
620 *
621 * Determine if a Unicode character is a blank.
622 *
623 * PARAMS
624 * wc [I] Character to check.
625 *
626 * RETURNS
627 * TRUE, if wc is a blank,
628 * FALSE otherwise.
629 *
630 */
631 BOOL WINAPI IsCharBlankW(WCHAR wc)
632 {
633 WORD CharType;
634
635 return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_BLANK);
636 }
637
638 /*************************************************************************
639 * @ [SHLWAPI.31]
640 *
641 * Determine if a Unicode character is punctuation.
642 *
643 * PARAMS
644 * wc [I] Character to check.
645 *
646 * RETURNS
647 * TRUE, if wc is punctuation,
648 * FALSE otherwise.
649 */
650 BOOL WINAPI IsCharPunctW(WCHAR wc)
651 {
652 WORD CharType;
653
654 return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_PUNCT);
655 }
656
657 /*************************************************************************
658 * @ [SHLWAPI.32]
659 *
660 * Determine if a Unicode character is a control character.
661 *
662 * PARAMS
663 * wc [I] Character to check.
664 *
665 * RETURNS
666 * TRUE, if wc is a control character,
667 * FALSE otherwise.
668 */
669 BOOL WINAPI IsCharCntrlW(WCHAR wc)
670 {
671 WORD CharType;
672
673 return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_CNTRL);
674 }
675
676 /*************************************************************************
677 * @ [SHLWAPI.33]
678 *
679 * Determine if a Unicode character is a digit.
680 *
681 * PARAMS
682 * wc [I] Character to check.
683 *
684 * RETURNS
685 * TRUE, if wc is a digit,
686 * FALSE otherwise.
687 */
688 BOOL WINAPI IsCharDigitW(WCHAR wc)
689 {
690 WORD CharType;
691
692 return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_DIGIT);
693 }
694
695 /*************************************************************************
696 * @ [SHLWAPI.34]
697 *
698 * Determine if a Unicode character is a hex digit.
699 *
700 * PARAMS
701 * wc [I] Character to check.
702 *
703 * RETURNS
704 * TRUE, if wc is a hex digit,
705 * FALSE otherwise.
706 */
707 BOOL WINAPI IsCharXDigitW(WCHAR wc)
708 {
709 WORD CharType;
710
711 return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_XDIGIT);
712 }
713
714 /*************************************************************************
715 * @ [SHLWAPI.35]
716 *
717 */
718 BOOL WINAPI GetStringType3ExW(LPWSTR src, INT count, LPWORD type)
719 {
720 return GetStringTypeW(CT_CTYPE3, src, count, type);
721 }
722
723 /*************************************************************************
724 * @ [SHLWAPI.151]
725 *
726 * Compare two Ascii strings up to a given length.
727 *
728 * PARAMS
729 * lpszSrc [I] Source string
730 * lpszCmp [I] String to compare to lpszSrc
731 * len [I] Maximum length
732 *
733 * RETURNS
734 * A number greater than, less than or equal to 0 depending on whether
735 * lpszSrc is greater than, less than or equal to lpszCmp.
736 */
737 DWORD WINAPI StrCmpNCA(LPCSTR lpszSrc, LPCSTR lpszCmp, INT len)
738 {
739 return StrCmpNA(lpszSrc, lpszCmp, len);
740 }
741
742 /*************************************************************************
743 * @ [SHLWAPI.152]
744 *
745 * Unicode version of StrCmpNCA.
746 */
747 DWORD WINAPI StrCmpNCW(LPCWSTR lpszSrc, LPCWSTR lpszCmp, INT len)
748 {
749 return StrCmpNW(lpszSrc, lpszCmp, len);
750 }
751
752 /*************************************************************************
753 * @ [SHLWAPI.153]
754 *
755 * Compare two Ascii strings up to a given length, ignoring case.
756 *
757 * PARAMS
758 * lpszSrc [I] Source string
759 * lpszCmp [I] String to compare to lpszSrc
760 * len [I] Maximum length
761 *
762 * RETURNS
763 * A number greater than, less than or equal to 0 depending on whether
764 * lpszSrc is greater than, less than or equal to lpszCmp.
765 */
766 DWORD WINAPI StrCmpNICA(LPCSTR lpszSrc, LPCSTR lpszCmp, DWORD len)
767 {
768 return StrCmpNIA(lpszSrc, lpszCmp, len);
769 }
770
771 /*************************************************************************
772 * @ [SHLWAPI.154]
773 *
774 * Unicode version of StrCmpNICA.
775 */
776 DWORD WINAPI StrCmpNICW(LPCWSTR lpszSrc, LPCWSTR lpszCmp, DWORD len)
777 {
778 return StrCmpNIW(lpszSrc, lpszCmp, len);
779 }
780
781 /*************************************************************************
782 * @ [SHLWAPI.155]
783 *
784 * Compare two Ascii strings.
785 *
786 * PARAMS
787 * lpszSrc [I] Source string
788 * lpszCmp [I] String to compare to lpszSrc
789 *
790 * RETURNS
791 * A number greater than, less than or equal to 0 depending on whether
792 * lpszSrc is greater than, less than or equal to lpszCmp.
793 */
794 DWORD WINAPI StrCmpCA(LPCSTR lpszSrc, LPCSTR lpszCmp)
795 {
796 return lstrcmpA(lpszSrc, lpszCmp);
797 }
798
799 /*************************************************************************
800 * @ [SHLWAPI.156]
801 *
802 * Unicode version of StrCmpCA.
803 */
804 DWORD WINAPI StrCmpCW(LPCWSTR lpszSrc, LPCWSTR lpszCmp)
805 {
806 return lstrcmpW(lpszSrc, lpszCmp);
807 }
808
809 /*************************************************************************
810 * @ [SHLWAPI.157]
811 *
812 * Compare two Ascii strings, ignoring case.
813 *
814 * PARAMS
815 * lpszSrc [I] Source string
816 * lpszCmp [I] String to compare to lpszSrc
817 *
818 * RETURNS
819 * A number greater than, less than or equal to 0 depending on whether
820 * lpszSrc is greater than, less than or equal to lpszCmp.
821 */
822 DWORD WINAPI StrCmpICA(LPCSTR lpszSrc, LPCSTR lpszCmp)
823 {
824 return lstrcmpiA(lpszSrc, lpszCmp);
825 }
826
827 /*************************************************************************
828 * @ [SHLWAPI.158]
829 *
830 * Unicode version of StrCmpICA.
831 */
832 DWORD WINAPI StrCmpICW(LPCWSTR lpszSrc, LPCWSTR lpszCmp)
833 {
834 return lstrcmpiW(lpszSrc, lpszCmp);
835 }
836
837 /*************************************************************************
838 * @ [SHLWAPI.160]
839 *
840 * Get an identification string for the OS and explorer.
841 *
842 * PARAMS
843 * lpszDest [O] Destination for Id string
844 * dwDestLen [I] Length of lpszDest
845 *
846 * RETURNS
847 * TRUE, If the string was created successfully
848 * FALSE, Otherwise
849 */
850 BOOL WINAPI SHAboutInfoA(LPSTR lpszDest, DWORD dwDestLen)
851 {
852 WCHAR buff[2084];
853
854 TRACE("(%p,%d)\n", lpszDest, dwDestLen);
855
856 if (lpszDest && SHAboutInfoW(buff, dwDestLen))
857 {
858 WideCharToMultiByte(CP_ACP, 0, buff, -1, lpszDest, dwDestLen, NULL, NULL);
859 return TRUE;
860 }
861 return FALSE;
862 }
863
864 /*************************************************************************
865 * @ [SHLWAPI.161]
866 *
867 * Unicode version of SHAboutInfoA.
868 */
869 BOOL WINAPI SHAboutInfoW(LPWSTR lpszDest, DWORD dwDestLen)
870 {
871 static const WCHAR szIEKey[] = { 'S','O','F','T','W','A','R','E','\\',
872 'M','i','c','r','o','s','o','f','t','\\','I','n','t','e','r','n','e','t',
873 ' ','E','x','p','l','o','r','e','r','\0' };
874 static const WCHAR szWinNtKey[] = { 'S','O','F','T','W','A','R','E','\\',
875 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s',' ',
876 'N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\0' };
877 static const WCHAR szWinKey[] = { 'S','O','F','T','W','A','R','E','\\',
878 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
879 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\0' };
880 static const WCHAR szRegKey[] = { 'S','O','F','T','W','A','R','E','\\',
881 'M','i','c','r','o','s','o','f','t','\\','I','n','t','e','r','n','e','t',
882 ' ','E','x','p','l','o','r','e','r','\\',
883 'R','e','g','i','s','t','r','a','t','i','o','n','\0' };
884 static const WCHAR szVersion[] = { 'V','e','r','s','i','o','n','\0' };
885 static const WCHAR szCustomized[] = { 'C','u','s','t','o','m','i','z','e','d',
886 'V','e','r','s','i','o','n','\0' };
887 static const WCHAR szOwner[] = { 'R','e','g','i','s','t','e','r','e','d',
888 'O','w','n','e','r','\0' };
889 static const WCHAR szOrg[] = { 'R','e','g','i','s','t','e','r','e','d',
890 'O','r','g','a','n','i','z','a','t','i','o','n','\0' };
891 static const WCHAR szProduct[] = { 'P','r','o','d','u','c','t','I','d','\0' };
892 static const WCHAR szUpdate[] = { 'I','E','A','K',
893 'U','p','d','a','t','e','U','r','l','\0' };
894 static const WCHAR szHelp[] = { 'I','E','A','K',
895 'H','e','l','p','S','t','r','i','n','g','\0' };
896 WCHAR buff[2084];
897 HKEY hReg;
898 DWORD dwType, dwLen;
899
900 TRACE("(%p,%d)\n", lpszDest, dwDestLen);
901
902 if (!lpszDest)
903 return FALSE;
904
905 *lpszDest = '\0';
906
907 /* Try the NT key first, followed by 95/98 key */
908 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szWinNtKey, 0, KEY_READ, &hReg) &&
909 RegOpenKeyExW(HKEY_LOCAL_MACHINE, szWinKey, 0, KEY_READ, &hReg))
910 return FALSE;
911
912 /* OS Version */
913 buff[0] = '\0';
914 dwLen = 30;
915 if (!SHGetValueW(HKEY_LOCAL_MACHINE, szIEKey, szVersion, &dwType, buff, &dwLen))
916 {
917 DWORD dwStrLen = strlenW(buff);
918 dwLen = 30 - dwStrLen;
919 SHGetValueW(HKEY_LOCAL_MACHINE, szIEKey,
920 szCustomized, &dwType, buff+dwStrLen, &dwLen);
921 }
922 StrCatBuffW(lpszDest, buff, dwDestLen);
923
924 /* ~Registered Owner */
925 buff[0] = '~';
926 dwLen = 256;
927 if (SHGetValueW(hReg, szOwner, 0, &dwType, buff+1, &dwLen))
928 buff[1] = '\0';
929 StrCatBuffW(lpszDest, buff, dwDestLen);
930
931 /* ~Registered Organization */
932 dwLen = 256;
933 if (SHGetValueW(hReg, szOrg, 0, &dwType, buff+1, &dwLen))
934 buff[1] = '\0';
935 StrCatBuffW(lpszDest, buff, dwDestLen);
936
937 /* FIXME: Not sure where this number comes from */
938 buff[0] = '~';
939 buff[1] = '0';
940 buff[2] = '\0';
941 StrCatBuffW(lpszDest, buff, dwDestLen);
942
943 /* ~Product Id */
944 dwLen = 256;
945 if (SHGetValueW(HKEY_LOCAL_MACHINE, szRegKey, szProduct, &dwType, buff+1, &dwLen))
946 buff[1] = '\0';
947 StrCatBuffW(lpszDest, buff, dwDestLen);
948
949 /* ~IE Update Url */
950 dwLen = 2048;
951 if(SHGetValueW(HKEY_LOCAL_MACHINE, szWinKey, szUpdate, &dwType, buff+1, &dwLen))
952 buff[1] = '\0';
953 StrCatBuffW(lpszDest, buff, dwDestLen);
954
955 /* ~IE Help String */
956 dwLen = 256;
957 if(SHGetValueW(hReg, szHelp, 0, &dwType, buff+1, &dwLen))
958 buff[1] = '\0';
959 StrCatBuffW(lpszDest, buff, dwDestLen);
960
961 RegCloseKey(hReg);
962 return TRUE;
963 }
964
965 /*************************************************************************
966 * @ [SHLWAPI.163]
967 *
968 * Call IOleCommandTarget_QueryStatus() on an object.
969 *
970 * PARAMS
971 * lpUnknown [I] Object supporting the IOleCommandTarget interface
972 * pguidCmdGroup [I] GUID for the command group
973 * cCmds [I]
974 * prgCmds [O] Commands
975 * pCmdText [O] Command text
976 *
977 * RETURNS
978 * Success: S_OK.
979 * Failure: E_FAIL, if lpUnknown is NULL.
980 * E_NOINTERFACE, if lpUnknown does not support IOleCommandTarget.
981 * Otherwise, an error code from IOleCommandTarget_QueryStatus().
982 */
983 HRESULT WINAPI IUnknown_QueryStatus(IUnknown* lpUnknown, REFGUID pguidCmdGroup,
984 ULONG cCmds, OLECMD *prgCmds, OLECMDTEXT* pCmdText)
985 {
986 HRESULT hRet = E_FAIL;
987
988 TRACE("(%p,%p,%d,%p,%p)\n",lpUnknown, pguidCmdGroup, cCmds, prgCmds, pCmdText);
989
990 if (lpUnknown)
991 {
992 IOleCommandTarget* lpOle;
993
994 hRet = IUnknown_QueryInterface(lpUnknown, &IID_IOleCommandTarget,
995 (void**)&lpOle);
996
997 if (SUCCEEDED(hRet) && lpOle)
998 {
999 hRet = IOleCommandTarget_QueryStatus(lpOle, pguidCmdGroup, cCmds,
1000 prgCmds, pCmdText);
1001 IOleCommandTarget_Release(lpOle);
1002 }
1003 }
1004 return hRet;
1005 }
1006
1007 /*************************************************************************
1008 * @ [SHLWAPI.164]
1009 *
1010 * Call IOleCommandTarget_Exec() on an object.
1011 *
1012 * PARAMS
1013 * lpUnknown [I] Object supporting the IOleCommandTarget interface
1014 * pguidCmdGroup [I] GUID for the command group
1015 *
1016 * RETURNS
1017 * Success: S_OK.
1018 * Failure: E_FAIL, if lpUnknown is NULL.
1019 * E_NOINTERFACE, if lpUnknown does not support IOleCommandTarget.
1020 * Otherwise, an error code from IOleCommandTarget_Exec().
1021 */
1022 HRESULT WINAPI IUnknown_Exec(IUnknown* lpUnknown, REFGUID pguidCmdGroup,
1023 DWORD nCmdID, DWORD nCmdexecopt, VARIANT* pvaIn,
1024 VARIANT* pvaOut)
1025 {
1026 HRESULT hRet = E_FAIL;
1027
1028 TRACE("(%p,%p,%d,%d,%p,%p)\n",lpUnknown, pguidCmdGroup, nCmdID,
1029 nCmdexecopt, pvaIn, pvaOut);
1030
1031 if (lpUnknown)
1032 {
1033 IOleCommandTarget* lpOle;
1034
1035 hRet = IUnknown_QueryInterface(lpUnknown, &IID_IOleCommandTarget,
1036 (void**)&lpOle);
1037 if (SUCCEEDED(hRet) && lpOle)
1038 {
1039 hRet = IOleCommandTarget_Exec(lpOle, pguidCmdGroup, nCmdID,
1040 nCmdexecopt, pvaIn, pvaOut);
1041 IOleCommandTarget_Release(lpOle);
1042 }
1043 }
1044 return hRet;
1045 }
1046
1047 /*************************************************************************
1048 * @ [SHLWAPI.165]
1049 *
1050 * Retrieve, modify, and re-set a value from a window.
1051 *
1052 * PARAMS
1053 * hWnd [I] Window to get value from
1054 * offset [I] Offset of value
1055 * mask [I] Mask for flags
1056 * flags [I] Bits to set in window value
1057 *
1058 * RETURNS
1059 * The new value as it was set, or 0 if any parameter is invalid.
1060 *
1061 * NOTES
1062 * Only bits specified in mask are affected - set if present in flags and
1063 * reset otherwise.
1064 */
1065 LONG WINAPI SHSetWindowBits(HWND hwnd, INT offset, UINT mask, UINT flags)
1066 {
1067 LONG ret = GetWindowLongW(hwnd, offset);
1068 LONG new_flags = (flags & mask) | (ret & ~mask);
1069
1070 TRACE("%p %d %x %x\n", hwnd, offset, mask, flags);
1071
1072 if (new_flags != ret)
1073 ret = SetWindowLongW(hwnd, offset, new_flags);
1074 return ret;
1075 }
1076
1077 /*************************************************************************
1078 * @ [SHLWAPI.167]
1079 *
1080 * Change a window's parent.
1081 *
1082 * PARAMS
1083 * hWnd [I] Window to change parent of
1084 * hWndParent [I] New parent window
1085 *
1086 * RETURNS
1087 * The old parent of hWnd.
1088 *
1089 * NOTES
1090 * If hWndParent is NULL (desktop), the window style is changed to WS_POPUP.
1091 * If hWndParent is NOT NULL then we set the WS_CHILD style.
1092 */
1093 HWND WINAPI SHSetParentHwnd(HWND hWnd, HWND hWndParent)
1094 {
1095 TRACE("%p, %p\n", hWnd, hWndParent);
1096
1097 if(GetParent(hWnd) == hWndParent)
1098 return NULL;
1099
1100 if(hWndParent)
1101 SHSetWindowBits(hWnd, GWL_STYLE, WS_CHILD | WS_POPUP, WS_CHILD);
1102 else
1103 SHSetWindowBits(hWnd, GWL_STYLE, WS_CHILD | WS_POPUP, WS_POPUP);
1104
1105 return hWndParent ? SetParent(hWnd, hWndParent) : NULL;
1106 }
1107
1108 /*************************************************************************
1109 * @ [SHLWAPI.168]
1110 *
1111 * Locate and advise a connection point in an IConnectionPointContainer object.
1112 *
1113 * PARAMS
1114 * lpUnkSink [I] Sink for the connection point advise call
1115 * riid [I] REFIID of connection point to advise
1116 * fConnect [I] TRUE = Connection being establisted, FALSE = broken
1117 * lpUnknown [I] Object supporting the IConnectionPointContainer interface
1118 * lpCookie [O] Pointer to connection point cookie
1119 * lppCP [O] Destination for the IConnectionPoint found
1120 *
1121 * RETURNS
1122 * Success: S_OK. If lppCP is non-NULL, it is filled with the IConnectionPoint
1123 * that was advised. The caller is responsible for releasing it.
1124 * Failure: E_FAIL, if any arguments are invalid.
1125 * E_NOINTERFACE, if lpUnknown isn't an IConnectionPointContainer,
1126 * Or an HRESULT error code if any call fails.
1127 */
1128 HRESULT WINAPI ConnectToConnectionPoint(IUnknown* lpUnkSink, REFIID riid, BOOL fConnect,
1129 IUnknown* lpUnknown, LPDWORD lpCookie,
1130 IConnectionPoint **lppCP)
1131 {
1132 HRESULT hRet;
1133 IConnectionPointContainer* lpContainer;
1134 IConnectionPoint *lpCP;
1135
1136 if(!lpUnknown || (fConnect && !lpUnkSink))
1137 return E_FAIL;
1138
1139 if(lppCP)
1140 *lppCP = NULL;
1141
1142 hRet = IUnknown_QueryInterface(lpUnknown, &IID_IConnectionPointContainer,
1143 (void**)&lpContainer);
1144 if (SUCCEEDED(hRet))
1145 {
1146 hRet = IConnectionPointContainer_FindConnectionPoint(lpContainer, riid, &lpCP);
1147
1148 if (SUCCEEDED(hRet))
1149 {
1150 if(!fConnect)
1151 hRet = IConnectionPoint_Unadvise(lpCP, *lpCookie);
1152 else
1153 hRet = IConnectionPoint_Advise(lpCP, lpUnkSink, lpCookie);
1154
1155 if (FAILED(hRet))
1156 *lpCookie = 0;
1157
1158 if (lppCP && SUCCEEDED(hRet))
1159 *lppCP = lpCP; /* Caller keeps the interface */
1160 else
1161 IConnectionPoint_Release(lpCP); /* Release it */
1162 }
1163
1164 IConnectionPointContainer_Release(lpContainer);
1165 }
1166 return hRet;
1167 }
1168
1169 /*************************************************************************
1170 * @ [SHLWAPI.169]
1171 *
1172 * Release an interface and zero a supplied pointer.
1173 *
1174 * PARAMS
1175 * lpUnknown [I] Object to release
1176 *
1177 * RETURNS
1178 * Nothing.
1179 */
1180 void WINAPI IUnknown_AtomicRelease(IUnknown ** lpUnknown)
1181 {
1182 TRACE("(%p)\n", lpUnknown);
1183
1184 if(!lpUnknown || !*lpUnknown) return;
1185
1186 TRACE("doing Release\n");
1187
1188 IUnknown_Release(*lpUnknown);
1189 *lpUnknown = NULL;
1190 }
1191
1192 /*************************************************************************
1193 * @ [SHLWAPI.170]
1194 *
1195 * Skip '//' if present in a string.
1196 *
1197 * PARAMS
1198 * lpszSrc [I] String to check for '//'
1199 *
1200 * RETURNS
1201 * Success: The next character after the '//' or the string if not present
1202 * Failure: NULL, if lpszStr is NULL.
1203 */
1204 LPCSTR WINAPI PathSkipLeadingSlashesA(LPCSTR lpszSrc)
1205 {
1206 if (lpszSrc && lpszSrc[0] == '/' && lpszSrc[1] == '/')
1207 lpszSrc += 2;
1208 return lpszSrc;
1209 }
1210
1211 /*************************************************************************
1212 * @ [SHLWAPI.171]
1213 *
1214 * Check if two interfaces come from the same object.
1215 *
1216 * PARAMS
1217 * lpInt1 [I] Interface to check against lpInt2.
1218 * lpInt2 [I] Interface to check against lpInt1.
1219 *
1220 * RETURNS
1221 * TRUE, If the interfaces come from the same object.
1222 * FALSE Otherwise.
1223 */
1224 BOOL WINAPI SHIsSameObject(IUnknown* lpInt1, IUnknown* lpInt2)
1225 {
1226 IUnknown *lpUnknown1, *lpUnknown2;
1227 BOOL ret;
1228
1229 TRACE("(%p %p)\n", lpInt1, lpInt2);
1230
1231 if (!lpInt1 || !lpInt2)
1232 return FALSE;
1233
1234 if (lpInt1 == lpInt2)
1235 return TRUE;
1236
1237 if (IUnknown_QueryInterface(lpInt1, &IID_IUnknown, (void**)&lpUnknown1) != S_OK)
1238 return FALSE;
1239
1240 if (IUnknown_QueryInterface(lpInt2, &IID_IUnknown, (void**)&lpUnknown2) != S_OK)
1241 {
1242 IUnknown_Release(lpUnknown1);
1243 return FALSE;
1244 }
1245
1246 ret = lpUnknown1 == lpUnknown2;
1247
1248 IUnknown_Release(lpUnknown1);
1249 IUnknown_Release(lpUnknown2);
1250
1251 return ret;
1252 }
1253
1254 /*************************************************************************
1255 * @ [SHLWAPI.172]
1256 *
1257 * Get the window handle of an object.
1258 *
1259 * PARAMS
1260 * lpUnknown [I] Object to get the window handle of
1261 * lphWnd [O] Destination for window handle
1262 *
1263 * RETURNS
1264 * Success: S_OK. lphWnd contains the objects window handle.
1265 * Failure: An HRESULT error code.
1266 *
1267 * NOTES
1268 * lpUnknown is expected to support one of the following interfaces:
1269 * IOleWindow(), IInternetSecurityMgrSite(), or IShellView().
1270 */
1271 HRESULT WINAPI IUnknown_GetWindow(IUnknown *lpUnknown, HWND *lphWnd)
1272 {
1273 IUnknown *lpOle;
1274 HRESULT hRet = E_FAIL;
1275
1276 TRACE("(%p,%p)\n", lpUnknown, lphWnd);
1277
1278 if (!lpUnknown)
1279 return hRet;
1280
1281 hRet = IUnknown_QueryInterface(lpUnknown, &IID_IOleWindow, (void**)&lpOle);
1282
1283 if (FAILED(hRet))
1284 {
1285 hRet = IUnknown_QueryInterface(lpUnknown,&IID_IShellView, (void**)&lpOle);
1286
1287 if (FAILED(hRet))
1288 {
1289 hRet = IUnknown_QueryInterface(lpUnknown, &IID_IInternetSecurityMgrSite,
1290 (void**)&lpOle);
1291 }
1292 }
1293
1294 if (SUCCEEDED(hRet))
1295 {
1296 /* Laziness here - Since GetWindow() is the first method for the above 3
1297 * interfaces, we use the same call for them all.
1298 */
1299 hRet = IOleWindow_GetWindow((IOleWindow*)lpOle, lphWnd);
1300 IUnknown_Release(lpOle);
1301 if (lphWnd)
1302 TRACE("Returning HWND=%p\n", *lphWnd);
1303 }
1304
1305 return hRet;
1306 }
1307
1308 /*************************************************************************
1309 * @ [SHLWAPI.173]
1310 *
1311 * Call a SetOwner method of IShellService from specified object.
1312 *
1313 * PARAMS
1314 * iface [I] Object that supports IShellService
1315 * pUnk [I] Argument for the SetOwner call
1316 *
1317 * RETURNS
1318 * Corresponding return value from last call or E_FAIL for null input
1319 */
1320 HRESULT WINAPI IUnknown_SetOwner(IUnknown *iface, IUnknown *pUnk)
1321 {
1322 IShellService *service;
1323 HRESULT hr;
1324
1325 TRACE("(%p, %p)\n", iface, pUnk);
1326
1327 if (!iface) return E_FAIL;
1328
1329 hr = IUnknown_QueryInterface(iface, &IID_IShellService, (void**)&service);
1330 if (hr == S_OK)
1331 {
1332 hr = IShellService_SetOwner(service, pUnk);
1333 IShellService_Release(service);
1334 }
1335
1336 return hr;
1337 }
1338
1339 /*************************************************************************
1340 * @ [SHLWAPI.174]
1341 *
1342 * Call either IObjectWithSite_SetSite() or IInternetSecurityManager_SetSecuritySite() on
1343 * an object.
1344 *
1345 */
1346 HRESULT WINAPI IUnknown_SetSite(
1347 IUnknown *obj, /* [in] OLE object */
1348 IUnknown *site) /* [in] Site interface */
1349 {
1350 HRESULT hr;
1351 IObjectWithSite *iobjwithsite;
1352 IInternetSecurityManager *isecmgr;
1353
1354 if (!obj) return E_FAIL;
1355
1356 hr = IUnknown_QueryInterface(obj, &IID_IObjectWithSite, (LPVOID *)&iobjwithsite);
1357 TRACE("IID_IObjectWithSite QI ret=%08x, %p\n", hr, iobjwithsite);
1358 if (SUCCEEDED(hr))
1359 {
1360 hr = IObjectWithSite_SetSite(iobjwithsite, site);
1361 TRACE("done IObjectWithSite_SetSite ret=%08x\n", hr);
1362 IObjectWithSite_Release(iobjwithsite);
1363 }
1364 else
1365 {
1366 hr = IUnknown_QueryInterface(obj, &IID_IInternetSecurityManager, (LPVOID *)&isecmgr);
1367 TRACE("IID_IInternetSecurityManager QI ret=%08x, %p\n", hr, isecmgr);
1368 if (FAILED(hr)) return hr;
1369
1370 hr = IInternetSecurityManager_SetSecuritySite(isecmgr, (IInternetSecurityMgrSite *)site);
1371 TRACE("done IInternetSecurityManager_SetSecuritySite ret=%08x\n", hr);
1372 IInternetSecurityManager_Release(isecmgr);
1373 }
1374 return hr;
1375 }
1376
1377 /*************************************************************************
1378 * @ [SHLWAPI.175]
1379 *
1380 * Call IPersist_GetClassID() on an object.
1381 *
1382 * PARAMS
1383 * lpUnknown [I] Object supporting the IPersist interface
1384 * lpClassId [O] Destination for Class Id
1385 *
1386 * RETURNS
1387 * Success: S_OK. lpClassId contains the Class Id requested.
1388 * Failure: E_FAIL, If lpUnknown is NULL,
1389 * E_NOINTERFACE If lpUnknown does not support IPersist,
1390 * Or an HRESULT error code.
1391 */
1392 HRESULT WINAPI IUnknown_GetClassID(IUnknown *lpUnknown, CLSID* lpClassId)
1393 {
1394 IPersist* lpPersist;
1395 HRESULT hRet = E_FAIL;
1396
1397 TRACE("(%p,%s)\n", lpUnknown, debugstr_guid(lpClassId));
1398
1399 if (lpUnknown)
1400 {
1401 hRet = IUnknown_QueryInterface(lpUnknown,&IID_IPersist,(void**)&lpPersist);
1402 if (SUCCEEDED(hRet))
1403 {
1404 IPersist_GetClassID(lpPersist, lpClassId);
1405 IPersist_Release(lpPersist);
1406 }
1407 }
1408 return hRet;
1409 }
1410
1411 /*************************************************************************
1412 * @ [SHLWAPI.176]
1413 *
1414 * Retrieve a Service Interface from an object.
1415 *
1416 * PARAMS
1417 * lpUnknown [I] Object to get an IServiceProvider interface from
1418 * sid [I] Service ID for IServiceProvider_QueryService() call
1419 * riid [I] Function requested for QueryService call
1420 * lppOut [O] Destination for the service interface pointer
1421 *
1422 * RETURNS
1423 * Success: S_OK. lppOut contains an object providing the requested service
1424 * Failure: An HRESULT error code
1425 *
1426 * NOTES
1427 * lpUnknown is expected to support the IServiceProvider interface.
1428 */
1429 HRESULT WINAPI IUnknown_QueryService(IUnknown* lpUnknown, REFGUID sid, REFIID riid,
1430 LPVOID *lppOut)
1431 {
1432 IServiceProvider* pService = NULL;
1433 HRESULT hRet;
1434
1435 if (!lppOut)
1436 return E_FAIL;
1437
1438 *lppOut = NULL;
1439
1440 if (!lpUnknown)
1441 return E_FAIL;
1442
1443 hRet = IUnknown_QueryInterface(lpUnknown, &IID_IServiceProvider,
1444 (LPVOID*)&pService);
1445
1446 if (hRet == S_OK && pService)
1447 {
1448 TRACE("QueryInterface returned (IServiceProvider*)%p\n", pService);
1449
1450 /* Get a Service interface from the object */
1451 hRet = IServiceProvider_QueryService(pService, sid, riid, lppOut);
1452
1453 TRACE("(IServiceProvider*)%p returned (IUnknown*)%p\n", pService, *lppOut);
1454
1455 IServiceProvider_Release(pService);
1456 }
1457 return hRet;
1458 }
1459
1460 /*************************************************************************
1461 * @ [SHLWAPI.484]
1462 *
1463 * Calls IOleCommandTarget::Exec() for specified service object.
1464 *
1465 * PARAMS
1466 * lpUnknown [I] Object to get an IServiceProvider interface from
1467 * service [I] Service ID for IServiceProvider_QueryService() call
1468 * group [I] Group ID for IOleCommandTarget::Exec() call
1469 * cmdId [I] Command ID for IOleCommandTarget::Exec() call
1470 * cmdOpt [I] Options flags for command
1471 * pIn [I] Input arguments for command
1472 * pOut [O] Output arguments for command
1473 *
1474 * RETURNS
1475 * Success: S_OK. lppOut contains an object providing the requested service
1476 * Failure: An HRESULT error code
1477 *
1478 * NOTES
1479 * lpUnknown is expected to support the IServiceProvider interface.
1480 */
1481 HRESULT WINAPI IUnknown_QueryServiceExec(IUnknown *lpUnknown, REFIID service,
1482 const GUID *group, DWORD cmdId, DWORD cmdOpt, VARIANT *pIn, VARIANT *pOut)
1483 {
1484 IOleCommandTarget *target;
1485 HRESULT hr;
1486
1487 TRACE("%p %s %s %d %08x %p %p\n", lpUnknown, debugstr_guid(service),
1488 debugstr_guid(group), cmdId, cmdOpt, pIn, pOut);
1489
1490 hr = IUnknown_QueryService(lpUnknown, service, &IID_IOleCommandTarget, (void**)&target);
1491 if (hr == S_OK)
1492 {
1493 hr = IOleCommandTarget_Exec(target, group, cmdId, cmdOpt, pIn, pOut);
1494 IOleCommandTarget_Release(target);
1495 }
1496
1497 TRACE("<-- hr=0x%08x\n", hr);
1498
1499 return hr;
1500 }
1501
1502 /*************************************************************************
1503 * @ [SHLWAPI.514]
1504 *
1505 * Calls IProfferService methods to proffer/revoke specified service.
1506 *
1507 * PARAMS
1508 * lpUnknown [I] Object to get an IServiceProvider interface from
1509 * service [I] Service ID for IProfferService::Proffer/Revoke calls
1510 * pService [I] Service to proffer. If NULL ::Revoke is called
1511 * pCookie [IO] Group ID for IOleCommandTarget::Exec() call
1512 *
1513 * RETURNS
1514 * Success: S_OK. IProffer method returns S_OK
1515 * Failure: An HRESULT error code
1516 *
1517 * NOTES
1518 * lpUnknown is expected to support the IServiceProvider interface.
1519 */
1520 HRESULT WINAPI IUnknown_ProfferService(IUnknown *lpUnknown, REFGUID service, IServiceProvider *pService, DWORD *pCookie)
1521 {
1522 IProfferService *proffer;
1523 HRESULT hr;
1524
1525 TRACE("%p %s %p %p\n", lpUnknown, debugstr_guid(service), pService, pCookie);
1526
1527 hr = IUnknown_QueryService(lpUnknown, &IID_IProfferService, &IID_IProfferService, (void**)&proffer);
1528 if (hr == S_OK)
1529 {
1530 if (pService)
1531 hr = IProfferService_ProfferService(proffer, service, pService, pCookie);
1532 else
1533 {
1534 hr = IProfferService_RevokeService(proffer, *pCookie);
1535 *pCookie = 0;
1536 }
1537
1538 IProfferService_Release(proffer);
1539 }
1540
1541 return hr;
1542 }
1543
1544 /*************************************************************************
1545 * @ [SHLWAPI.479]
1546 *
1547 * Call an object's UIActivateIO method.
1548 *
1549 * PARAMS
1550 * unknown [I] Object to call the UIActivateIO method on
1551 * activate [I] Parameter for UIActivateIO call
1552 * msg [I] Parameter for UIActivateIO call
1553 *
1554 * RETURNS
1555 * Success: Value of UI_ActivateIO call
1556 * Failure: An HRESULT error code
1557 *
1558 * NOTES
1559 * unknown is expected to support the IInputObject interface.
1560 */
1561 HRESULT WINAPI IUnknown_UIActivateIO(IUnknown *unknown, BOOL activate, LPMSG msg)
1562 {
1563 IInputObject* object = NULL;
1564 HRESULT ret;
1565
1566 if (!unknown)
1567 return E_FAIL;
1568
1569 /* Get an IInputObject interface from the object */
1570 ret = IUnknown_QueryInterface(unknown, &IID_IInputObject, (LPVOID*) &object);
1571
1572 if (ret == S_OK)
1573 {
1574 ret = IInputObject_UIActivateIO(object, activate, msg);
1575 IInputObject_Release(object);
1576 }
1577
1578 return ret;
1579 }
1580
1581 /*************************************************************************
1582 * @ [SHLWAPI.177]
1583 *
1584 * Loads a popup menu.
1585 *
1586 * PARAMS
1587 * hInst [I] Instance handle
1588 * szName [I] Menu name
1589 *
1590 * RETURNS
1591 * Success: TRUE.
1592 * Failure: FALSE.
1593 */
1594 BOOL WINAPI SHLoadMenuPopup(HINSTANCE hInst, LPCWSTR szName)
1595 {
1596 HMENU hMenu;
1597
1598 TRACE("%p %s\n", hInst, debugstr_w(szName));
1599
1600 if ((hMenu = LoadMenuW(hInst, szName)))
1601 {
1602 if (GetSubMenu(hMenu, 0))
1603 RemoveMenu(hMenu, 0, MF_BYPOSITION);
1604
1605 DestroyMenu(hMenu);
1606 return TRUE;
1607 }
1608 return FALSE;
1609 }
1610
1611 typedef struct _enumWndData
1612 {
1613 UINT uiMsgId;
1614 WPARAM wParam;
1615 LPARAM lParam;
1616 LRESULT (WINAPI *pfnPost)(HWND,UINT,WPARAM,LPARAM);
1617 } enumWndData;
1618
1619 /* Callback for SHLWAPI_178 */
1620 static BOOL CALLBACK SHLWAPI_EnumChildProc(HWND hWnd, LPARAM lParam)
1621 {
1622 enumWndData *data = (enumWndData *)lParam;
1623
1624 TRACE("(%p,%p)\n", hWnd, data);
1625 data->pfnPost(hWnd, data->uiMsgId, data->wParam, data->lParam);
1626 return TRUE;
1627 }
1628
1629 /*************************************************************************
1630 * @ [SHLWAPI.178]
1631 *
1632 * Send or post a message to every child of a window.
1633 *
1634 * PARAMS
1635 * hWnd [I] Window whose children will get the messages
1636 * uiMsgId [I] Message Id
1637 * wParam [I] WPARAM of message
1638 * lParam [I] LPARAM of message
1639 * bSend [I] TRUE = Use SendMessageA(), FALSE = Use PostMessageA()
1640 *
1641 * RETURNS
1642 * Nothing.
1643 *
1644 * NOTES
1645 * The appropriate ASCII or Unicode function is called for the window.
1646 */
1647 void WINAPI SHPropagateMessage(HWND hWnd, UINT uiMsgId, WPARAM wParam, LPARAM lParam, BOOL bSend)
1648 {
1649 enumWndData data;
1650
1651 TRACE("(%p,%u,%ld,%ld,%d)\n", hWnd, uiMsgId, wParam, lParam, bSend);
1652
1653 if(hWnd)
1654 {
1655 data.uiMsgId = uiMsgId;
1656 data.wParam = wParam;
1657 data.lParam = lParam;
1658
1659 if (bSend)
1660 data.pfnPost = IsWindowUnicode(hWnd) ? (void*)SendMessageW : (void*)SendMessageA;
1661 else
1662 data.pfnPost = IsWindowUnicode(hWnd) ? (void*)PostMessageW : (void*)PostMessageA;
1663
1664 EnumChildWindows(hWnd, SHLWAPI_EnumChildProc, (LPARAM)&data);
1665 }
1666 }
1667
1668 /*************************************************************************
1669 * @ [SHLWAPI.180]
1670 *
1671 * Remove all sub-menus from a menu.
1672 *
1673 * PARAMS
1674 * hMenu [I] Menu to remove sub-menus from
1675 *
1676 * RETURNS
1677 * Success: 0. All sub-menus under hMenu are removed
1678 * Failure: -1, if any parameter is invalid
1679 */
1680 DWORD WINAPI SHRemoveAllSubMenus(HMENU hMenu)
1681 {
1682 int iItemCount = GetMenuItemCount(hMenu) - 1;
1683
1684 TRACE("%p\n", hMenu);
1685
1686 while (iItemCount >= 0)
1687 {
1688 HMENU hSubMenu = GetSubMenu(hMenu, iItemCount);
1689 if (hSubMenu)
1690 RemoveMenu(hMenu, iItemCount, MF_BYPOSITION);
1691 iItemCount--;
1692 }
1693 return iItemCount;
1694 }
1695
1696 /*************************************************************************
1697 * @ [SHLWAPI.181]
1698 *
1699 * Enable or disable a menu item.
1700 *
1701 * PARAMS
1702 * hMenu [I] Menu holding menu item
1703 * uID [I] ID of menu item to enable/disable
1704 * bEnable [I] Whether to enable (TRUE) or disable (FALSE) the item.
1705 *
1706 * RETURNS
1707 * The return code from EnableMenuItem.
1708 */
1709 UINT WINAPI SHEnableMenuItem(HMENU hMenu, UINT wItemID, BOOL bEnable)
1710 {
1711 TRACE("%p, %u, %d\n", hMenu, wItemID, bEnable);
1712 return EnableMenuItem(hMenu, wItemID, bEnable ? MF_ENABLED : MF_GRAYED);
1713 }
1714
1715 /*************************************************************************
1716 * @ [SHLWAPI.182]
1717 *
1718 * Check or uncheck a menu item.
1719 *
1720 * PARAMS
1721 * hMenu [I] Menu holding menu item
1722 * uID [I] ID of menu item to check/uncheck
1723 * bCheck [I] Whether to check (TRUE) or uncheck (FALSE) the item.
1724 *
1725 * RETURNS
1726 * The return code from CheckMenuItem.
1727 */
1728 DWORD WINAPI SHCheckMenuItem(HMENU hMenu, UINT uID, BOOL bCheck)
1729 {
1730 TRACE("%p, %u, %d\n", hMenu, uID, bCheck);
1731 return CheckMenuItem(hMenu, uID, bCheck ? MF_CHECKED : MF_UNCHECKED);
1732 }
1733
1734 /*************************************************************************
1735 * @ [SHLWAPI.183]
1736 *
1737 * Register a window class if it isn't already.
1738 *
1739 * PARAMS
1740 * lpWndClass [I] Window class to register
1741 *
1742 * RETURNS
1743 * The result of the RegisterClassA call.
1744 */
1745 DWORD WINAPI SHRegisterClassA(WNDCLASSA *wndclass)
1746 {
1747 WNDCLASSA wca;
1748 if (GetClassInfoA(wndclass->hInstance, wndclass->lpszClassName, &wca))
1749 return TRUE;
1750 return (DWORD)RegisterClassA(wndclass);
1751 }
1752
1753 /*************************************************************************
1754 * @ [SHLWAPI.186]
1755 */
1756 BOOL WINAPI SHSimulateDrop(IDropTarget *pDrop, IDataObject *pDataObj,
1757 DWORD grfKeyState, PPOINTL lpPt, DWORD* pdwEffect)
1758 {
1759 DWORD dwEffect = DROPEFFECT_LINK | DROPEFFECT_MOVE | DROPEFFECT_COPY;
1760 POINTL pt = { 0, 0 };
1761
1762 TRACE("%p %p 0x%08x %p %p\n", pDrop, pDataObj, grfKeyState, lpPt, pdwEffect);
1763
1764 if (!lpPt)
1765 lpPt = &pt;
1766
1767 if (!pdwEffect)
1768 pdwEffect = &dwEffect;
1769
1770 IDropTarget_DragEnter(pDrop, pDataObj, grfKeyState, *lpPt, pdwEffect);
1771
1772 if (*pdwEffect != DROPEFFECT_NONE)
1773 return IDropTarget_Drop(pDrop, pDataObj, grfKeyState, *lpPt, pdwEffect);
1774
1775 IDropTarget_DragLeave(pDrop);
1776 return TRUE;
1777 }
1778
1779 /*************************************************************************
1780 * @ [SHLWAPI.187]
1781 *
1782 * Call IPersistPropertyBag_Load() on an object.
1783 *
1784 * PARAMS
1785 * lpUnknown [I] Object supporting the IPersistPropertyBag interface
1786 * lpPropBag [O] Destination for loaded IPropertyBag
1787 *
1788 * RETURNS
1789 * Success: S_OK.
1790 * Failure: An HRESULT error code, or E_FAIL if lpUnknown is NULL.
1791 */
1792 DWORD WINAPI SHLoadFromPropertyBag(IUnknown *lpUnknown, IPropertyBag* lpPropBag)
1793 {
1794 IPersistPropertyBag* lpPPBag;
1795 HRESULT hRet = E_FAIL;
1796
1797 TRACE("(%p,%p)\n", lpUnknown, lpPropBag);
1798
1799 if (lpUnknown)
1800 {
1801 hRet = IUnknown_QueryInterface(lpUnknown, &IID_IPersistPropertyBag,
1802 (void**)&lpPPBag);
1803 if (SUCCEEDED(hRet) && lpPPBag)
1804 {
1805 hRet = IPersistPropertyBag_Load(lpPPBag, lpPropBag, NULL);
1806 IPersistPropertyBag_Release(lpPPBag);
1807 }
1808 }
1809 return hRet;
1810 }
1811
1812 /*************************************************************************
1813 * @ [SHLWAPI.188]
1814 *
1815 * Call IOleControlSite_TranslateAccelerator() on an object.
1816 *
1817 * PARAMS
1818 * lpUnknown [I] Object supporting the IOleControlSite interface.
1819 * lpMsg [I] Key message to be processed.
1820 * dwModifiers [I] Flags containing the state of the modifier keys.
1821 *
1822 * RETURNS
1823 * Success: S_OK.
1824 * Failure: An HRESULT error code, or E_INVALIDARG if lpUnknown is NULL.
1825 */
1826 HRESULT WINAPI IUnknown_TranslateAcceleratorOCS(IUnknown *lpUnknown, LPMSG lpMsg, DWORD dwModifiers)
1827 {
1828 IOleControlSite* lpCSite = NULL;
1829 HRESULT hRet = E_INVALIDARG;
1830
1831 TRACE("(%p,%p,0x%08x)\n", lpUnknown, lpMsg, dwModifiers);
1832 if (lpUnknown)
1833 {
1834 hRet = IUnknown_QueryInterface(lpUnknown, &IID_IOleControlSite,
1835 (void**)&lpCSite);
1836 if (SUCCEEDED(hRet) && lpCSite)
1837 {
1838 hRet = IOleControlSite_TranslateAccelerator(lpCSite, lpMsg, dwModifiers);
1839 IOleControlSite_Release(lpCSite);
1840 }
1841 }
1842 return hRet;
1843 }
1844
1845
1846 /*************************************************************************
1847 * @ [SHLWAPI.189]
1848 *
1849 * Call IOleControlSite_OnFocus() on an object.
1850 *
1851 * PARAMS
1852 * lpUnknown [I] Object supporting the IOleControlSite interface.
1853 * fGotFocus [I] Whether focus was gained (TRUE) or lost (FALSE).
1854 *
1855 * RETURNS
1856 * Success: S_OK.
1857 * Failure: An HRESULT error code, or E_FAIL if lpUnknown is NULL.
1858 */
1859 HRESULT WINAPI IUnknown_OnFocusOCS(IUnknown *lpUnknown, BOOL fGotFocus)
1860 {
1861 IOleControlSite* lpCSite = NULL;
1862 HRESULT hRet = E_FAIL;
1863
1864 TRACE("(%p, %d)\n", lpUnknown, fGotFocus);
1865 if (lpUnknown)
1866 {
1867 hRet = IUnknown_QueryInterface(lpUnknown, &IID_IOleControlSite,
1868 (void**)&lpCSite);
1869 if (SUCCEEDED(hRet) && lpCSite)
1870 {
1871 hRet = IOleControlSite_OnFocus(lpCSite, fGotFocus);
1872 IOleControlSite_Release(lpCSite);
1873 }
1874 }
1875 return hRet;
1876 }
1877
1878 /*************************************************************************
1879 * @ [SHLWAPI.190]
1880 */
1881 HRESULT WINAPI IUnknown_HandleIRestrict(LPUNKNOWN lpUnknown, PVOID lpArg1,
1882 PVOID lpArg2, PVOID lpArg3, PVOID lpArg4)
1883 {
1884 /* FIXME: {D12F26B2-D90A-11D0-830D-00AA005B4383} - What object does this represent? */
1885 static const DWORD service_id[] = { 0xd12f26b2, 0x11d0d90a, 0xaa000d83, 0x83435b00 };
1886 /* FIXME: {D12F26B1-D90A-11D0-830D-00AA005B4383} - Also Unknown/undocumented */
1887 static const DWORD function_id[] = { 0xd12f26b1, 0x11d0d90a, 0xaa000d83, 0x83435b00 };
1888 HRESULT hRet = E_INVALIDARG;
1889 LPUNKNOWN lpUnkInner = NULL; /* FIXME: Real type is unknown */
1890
1891 TRACE("(%p,%p,%p,%p,%p)\n", lpUnknown, lpArg1, lpArg2, lpArg3, lpArg4);
1892
1893 if (lpUnknown && lpArg4)
1894 {
1895 hRet = IUnknown_QueryService(lpUnknown, (REFGUID)service_id,
1896 (REFGUID)function_id, (void**)&lpUnkInner);
1897
1898 if (SUCCEEDED(hRet) && lpUnkInner)
1899 {
1900 /* FIXME: The type of service object requested is unknown, however
1901 * testing shows that its first method is called with 4 parameters.
1902 * Fake this by using IParseDisplayName_ParseDisplayName since the
1903 * signature and position in the vtable matches our unknown object type.
1904 */
1905 hRet = IParseDisplayName_ParseDisplayName((LPPARSEDISPLAYNAME)lpUnkInner,
1906 lpArg1, lpArg2, lpArg3, lpArg4);
1907 IUnknown_Release(lpUnkInner);
1908 }
1909 }
1910 return hRet;
1911 }
1912
1913 /*************************************************************************
1914 * @ [SHLWAPI.192]
1915 *
1916 * Get a sub-menu from a menu item.
1917 *
1918 * PARAMS
1919 * hMenu [I] Menu to get sub-menu from
1920 * uID [I] ID of menu item containing sub-menu
1921 *
1922 * RETURNS
1923 * The sub-menu of the item, or a NULL handle if any parameters are invalid.
1924 */
1925 HMENU WINAPI SHGetMenuFromID(HMENU hMenu, UINT uID)
1926 {
1927 MENUITEMINFOW mi;
1928
1929 TRACE("(%p,%u)\n", hMenu, uID);
1930
1931 mi.cbSize = sizeof(mi);
1932 mi.fMask = MIIM_SUBMENU;
1933
1934 if (!GetMenuItemInfoW(hMenu, uID, FALSE, &mi))
1935 return NULL;
1936
1937 return mi.hSubMenu;
1938 }
1939
1940 /*************************************************************************
1941 * @ [SHLWAPI.193]
1942 *
1943 * Get the color depth of the primary display.
1944 *
1945 * PARAMS
1946 * None.
1947 *
1948 * RETURNS
1949 * The color depth of the primary display.
1950 */
1951 DWORD WINAPI SHGetCurColorRes(void)
1952 {
1953 HDC hdc;
1954 DWORD ret;
1955
1956 TRACE("()\n");
1957
1958 hdc = GetDC(0);
1959 ret = GetDeviceCaps(hdc, BITSPIXEL) * GetDeviceCaps(hdc, PLANES);
1960 ReleaseDC(0, hdc);
1961 return ret;
1962 }
1963
1964 /*************************************************************************
1965 * @ [SHLWAPI.194]
1966 *
1967 * Wait for a message to arrive, with a timeout.
1968 *
1969 * PARAMS
1970 * hand [I] Handle to query
1971 * dwTimeout [I] Timeout in ticks or INFINITE to never timeout
1972 *
1973 * RETURNS
1974 * STATUS_TIMEOUT if no message is received before dwTimeout ticks passes.
1975 * Otherwise returns the value from MsgWaitForMultipleObjectsEx when a
1976 * message is available.
1977 */
1978 DWORD WINAPI SHWaitForSendMessageThread(HANDLE hand, DWORD dwTimeout)
1979 {
1980 DWORD dwEndTicks = GetTickCount() + dwTimeout;
1981 DWORD dwRet;
1982
1983 while ((dwRet = MsgWaitForMultipleObjectsEx(1, &hand, dwTimeout, QS_SENDMESSAGE, 0)) == 1)
1984 {
1985 MSG msg;
1986
1987 PeekMessageW(&msg, NULL, 0, 0, PM_NOREMOVE);
1988
1989 if (dwTimeout != INFINITE)
1990 {
1991 if ((int)(dwTimeout = dwEndTicks - GetTickCount()) <= 0)
1992 return WAIT_TIMEOUT;
1993 }
1994 }
1995
1996 return dwRet;
1997 }
1998
1999 /*************************************************************************
2000 * @ [SHLWAPI.195]
2001 *
2002 * Determine if a shell folder can be expanded.
2003 *
2004 * PARAMS
2005 * lpFolder [I] Parent folder containing the object to test.
2006 * pidl [I] Id of the object to test.
2007 *
2008 * RETURNS
2009 * Success: S_OK, if the object is expandable, S_FALSE otherwise.
2010 * Failure: E_INVALIDARG, if any argument is invalid.
2011 *
2012 * NOTES
2013 * If the object to be tested does not expose the IQueryInfo() interface it
2014 * will not be identified as an expandable folder.
2015 */
2016 HRESULT WINAPI SHIsExpandableFolder(LPSHELLFOLDER lpFolder, LPCITEMIDLIST pidl)
2017 {
2018 HRESULT hRet = E_INVALIDARG;
2019 IQueryInfo *lpInfo;
2020
2021 if (lpFolder && pidl)
2022 {
2023 hRet = IShellFolder_GetUIObjectOf(lpFolder, NULL, 1, &pidl, &IID_IQueryInfo,
2024 NULL, (void**)&lpInfo);
2025 if (FAILED(hRet))
2026 hRet = S_FALSE; /* Doesn't expose IQueryInfo */
2027 else
2028 {
2029 DWORD dwFlags = 0;
2030
2031 /* MSDN states of IQueryInfo_GetInfoFlags() that "This method is not
2032 * currently used". Really? You wouldn't be holding out on me would you?
2033 */
2034 hRet = IQueryInfo_GetInfoFlags(lpInfo, &dwFlags);
2035
2036 if (SUCCEEDED(hRet))
2037 {
2038 /* 0x2 is an undocumented flag apparently indicating expandability */
2039 hRet = dwFlags & 0x2 ? S_OK : S_FALSE;
2040 }
2041
2042 IQueryInfo_Release(lpInfo);
2043 }
2044 }
2045 return hRet;
2046 }
2047
2048 /*************************************************************************
2049 * @ [SHLWAPI.197]
2050 *
2051 * Blank out a region of text by drawing the background only.
2052 *
2053 * PARAMS
2054 * hDC [I] Device context to draw in
2055 * pRect [I] Area to draw in
2056 * cRef [I] Color to draw in
2057 *
2058 * RETURNS
2059 * Nothing.
2060 */
2061 DWORD WINAPI SHFillRectClr(HDC hDC, LPCRECT pRect, COLORREF cRef)
2062 {
2063 COLORREF cOldColor = SetBkColor(hDC, cRef);
2064 ExtTextOutA(hDC, 0, 0, ETO_OPAQUE, pRect, 0, 0, 0);
2065 SetBkColor(hDC, cOldColor);
2066 return 0;
2067 }
2068
2069 /*************************************************************************
2070 * @ [SHLWAPI.198]
2071 *
2072 * Return the value associated with a key in a map.
2073 *
2074 * PARAMS
2075 * lpKeys [I] A list of keys of length iLen
2076 * lpValues [I] A list of values associated with lpKeys, of length iLen
2077 * iLen [I] Length of both lpKeys and lpValues
2078 * iKey [I] The key value to look up in lpKeys
2079 *
2080 * RETURNS
2081 * The value in lpValues associated with iKey, or -1 if iKey is not
2082 * found in lpKeys.
2083 *
2084 * NOTES
2085 * - If two elements in the map share the same key, this function returns
2086 * the value closest to the start of the map
2087 * - The native version of this function crashes if lpKeys or lpValues is NULL.
2088 */
2089 int WINAPI SHSearchMapInt(const int *lpKeys, const int *lpValues, int iLen, int iKey)
2090 {
2091 if (lpKeys && lpValues)
2092 {
2093 int i = 0;
2094
2095 while (i < iLen)
2096 {
2097 if (lpKeys[i] == iKey)
2098 return lpValues[i]; /* Found */
2099 i++;
2100 }
2101 }
2102 return -1; /* Not found */
2103 }
2104
2105
2106 /*************************************************************************
2107 * @ [SHLWAPI.199]
2108 *
2109 * Copy an interface pointer
2110 *
2111 * PARAMS
2112 * lppDest [O] Destination for copy
2113 * lpUnknown [I] Source for copy
2114 *
2115 * RETURNS
2116 * Nothing.
2117 */
2118 VOID WINAPI IUnknown_Set(IUnknown **lppDest, IUnknown *lpUnknown)
2119 {
2120 TRACE("(%p,%p)\n", lppDest, lpUnknown);
2121
2122 IUnknown_AtomicRelease(lppDest);
2123
2124 if (lpUnknown)
2125 {
2126 IUnknown_AddRef(lpUnknown);
2127 *lppDest = lpUnknown;
2128 }
2129 }
2130
2131 /*************************************************************************
2132 * @ [SHLWAPI.200]
2133 *
2134 */
2135 HRESULT WINAPI MayQSForward(IUnknown* lpUnknown, PVOID lpReserved,
2136 REFGUID riidCmdGrp, ULONG cCmds,
2137 OLECMD *prgCmds, OLECMDTEXT* pCmdText)
2138 {
2139 FIXME("(%p,%p,%p,%d,%p,%p) - stub\n",
2140 lpUnknown, lpReserved, riidCmdGrp, cCmds, prgCmds, pCmdText);
2141
2142 /* FIXME: Calls IsQSForward & IUnknown_QueryStatus */
2143 return DRAGDROP_E_NOTREGISTERED;
2144 }
2145
2146 /*************************************************************************
2147 * @ [SHLWAPI.201]
2148 *
2149 */
2150 HRESULT WINAPI MayExecForward(IUnknown* lpUnknown, INT iUnk, REFGUID pguidCmdGroup,
2151 DWORD nCmdID, DWORD nCmdexecopt, VARIANT* pvaIn,
2152 VARIANT* pvaOut)
2153 {
2154 FIXME("(%p,%d,%p,%d,%d,%p,%p) - stub!\n", lpUnknown, iUnk, pguidCmdGroup,
2155 nCmdID, nCmdexecopt, pvaIn, pvaOut);
2156 return DRAGDROP_E_NOTREGISTERED;
2157 }
2158
2159 /*************************************************************************
2160 * @ [SHLWAPI.202]
2161 *
2162 */
2163 HRESULT WINAPI IsQSForward(REFGUID pguidCmdGroup,ULONG cCmds, OLECMD *prgCmds)
2164 {
2165 FIXME("(%p,%d,%p) - stub!\n", pguidCmdGroup, cCmds, prgCmds);
2166 return DRAGDROP_E_NOTREGISTERED;
2167 }
2168
2169 /*************************************************************************
2170 * @ [SHLWAPI.204]
2171 *
2172 * Determine if a window is not a child of another window.
2173 *
2174 * PARAMS
2175 * hParent [I] Suspected parent window
2176 * hChild [I] Suspected child window
2177 *
2178 * RETURNS
2179 * TRUE: If hChild is a child window of hParent
2180 * FALSE: If hChild is not a child window of hParent, or they are equal
2181 */
2182 BOOL WINAPI SHIsChildOrSelf(HWND hParent, HWND hChild)
2183 {
2184 TRACE("(%p,%p)\n", hParent, hChild);
2185
2186 if (!hParent || !hChild)
2187 return TRUE;
2188 else if(hParent == hChild)
2189 return FALSE;
2190 return !IsChild(hParent, hChild);
2191 }
2192
2193 /*************************************************************************
2194 * FDSA functions. Manage a dynamic array of fixed size memory blocks.
2195 */
2196
2197 typedef struct
2198 {
2199 DWORD num_items; /* Number of elements inserted */
2200 void *mem; /* Ptr to array */
2201 DWORD blocks_alloced; /* Number of elements allocated */
2202 BYTE inc; /* Number of elements to grow by when we need to expand */
2203 BYTE block_size; /* Size in bytes of an element */
2204 BYTE flags; /* Flags */
2205 } FDSA_info;
2206
2207 #define FDSA_FLAG_INTERNAL_ALLOC 0x01 /* When set we have allocated mem internally */
2208
2209 /*************************************************************************
2210 * @ [SHLWAPI.208]
2211 *
2212 * Initialize an FDSA array.
2213 */
2214 BOOL WINAPI FDSA_Initialize(DWORD block_size, DWORD inc, FDSA_info *info, void *mem,
2215 DWORD init_blocks)
2216 {
2217 TRACE("(0x%08x 0x%08x %p %p 0x%08x)\n", block_size, inc, info, mem, init_blocks);
2218
2219 if(inc == 0)
2220 inc = 1;
2221
2222 if(mem)
2223 memset(mem, 0, block_size * init_blocks);
2224
2225 info->num_items = 0;
2226 info->inc = inc;
2227 info->mem = mem;
2228 info->blocks_alloced = init_blocks;
2229 info->block_size = block_size;
2230 info->flags = 0;
2231
2232 return TRUE;
2233 }
2234
2235 /*************************************************************************
2236 * @ [SHLWAPI.209]
2237 *
2238 * Destroy an FDSA array
2239 */
2240 BOOL WINAPI FDSA_Destroy(FDSA_info *info)
2241 {
2242 TRACE("(%p)\n", info);
2243
2244 if(info->flags & FDSA_FLAG_INTERNAL_ALLOC)
2245 {
2246 HeapFree(GetProcessHeap(), 0, info->mem);
2247 return FALSE;
2248 }
2249
2250 return TRUE;
2251 }
2252
2253 /*************************************************************************
2254 * @ [SHLWAPI.210]
2255 *
2256 * Insert element into an FDSA array
2257 */
2258 DWORD WINAPI FDSA_InsertItem(FDSA_info *info, DWORD where, const void *block)
2259 {
2260 TRACE("(%p 0x%08x %p)\n", info, where, block);
2261 if(where > info->num_items)
2262 where = info->num_items;
2263
2264 if(info->num_items >= info->blocks_alloced)
2265 {
2266 DWORD size = (info->blocks_alloced + info->inc) * info->block_size;
2267 if(info->flags & 0x1)
2268 info->mem = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, info->mem, size);
2269 else
2270 {
2271 void *old_mem = info->mem;
2272 info->mem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2273 memcpy(info->mem, old_mem, info->blocks_alloced * info->block_size);
2274 }
2275 info->blocks_alloced += info->inc;
2276 info->flags |= 0x1;
2277 }
2278
2279 if(where < info->num_items)
2280 {
2281 memmove((char*)info->mem + (where + 1) * info->block_size,
2282 (char*)info->mem + where * info->block_size,
2283 (info->num_items - where) * info->block_size);
2284 }
2285 memcpy((char*)info->mem + where * info->block_size, block, info->block_size);
2286
2287 info->num_items++;
2288 return where;
2289 }
2290
2291 /*************************************************************************
2292 * @ [SHLWAPI.211]
2293 *
2294 * Delete an element from an FDSA array.
2295 */
2296 BOOL WINAPI FDSA_DeleteItem(FDSA_info *info, DWORD where)
2297 {
2298 TRACE("(%p 0x%08x)\n", info, where);
2299
2300 if(where >= info->num_items)
2301 return FALSE;
2302
2303 if(where < info->num_items - 1)
2304 {
2305 memmove((char*)info->mem + where * info->block_size,
2306 (char*)info->mem + (where + 1) * info->block_size,
2307 (info->num_items - where - 1) * info->block_size);
2308 }
2309 memset((char*)info->mem + (info->num_items - 1) * info->block_size,
2310 0, info->block_size);
2311 info->num_items--;
2312 return TRUE;
2313 }
2314
2315 /*************************************************************************
2316 * @ [SHLWAPI.219]
2317 *
2318 * Call IUnknown_QueryInterface() on a table of objects.
2319 *
2320 * RETURNS
2321 * Success: S_OK.
2322 * Failure: E_POINTER or E_NOINTERFACE.
2323 */
2324 HRESULT WINAPI QISearch(
2325 void *base, /* [in] Table of interfaces */
2326 const QITAB *table, /* [in] Array of REFIIDs and indexes into the table */
2327 REFIID riid, /* [in] REFIID to get interface for */
2328 void **ppv) /* [out] Destination for interface pointer */
2329 {
2330 HRESULT ret;
2331 IUnknown *a_vtbl;
2332 const QITAB *xmove;
2333
2334 TRACE("(%p %p %s %p)\n", base, table, debugstr_guid(riid), ppv);
2335 if (ppv) {
2336 xmove = table;
2337 while (xmove->piid) {
2338 TRACE("trying (offset %d) %s\n", xmove->dwOffset, debugstr_guid(xmove->piid));
2339 if (IsEqualIID(riid, xmove->piid)) {
2340 a_vtbl = (IUnknown*)(xmove->dwOffset + (LPBYTE)base);
2341 TRACE("matched, returning (%p)\n", a_vtbl);
2342 *ppv = a_vtbl;
2343 IUnknown_AddRef(a_vtbl);
2344 return S_OK;
2345 }
2346 xmove++;
2347 }
2348
2349 if (IsEqualIID(riid, &IID_IUnknown)) {
2350 a_vtbl = (IUnknown*)(table->dwOffset + (LPBYTE)base);
2351 TRACE("returning first for IUnknown (%p)\n", a_vtbl);
2352 *ppv = a_vtbl;
2353 IUnknown_AddRef(a_vtbl);
2354 return S_OK;
2355 }
2356 *ppv = 0;
2357 ret = E_NOINTERFACE;
2358 } else
2359 ret = E_POINTER;
2360
2361 TRACE("-- 0x%08x\n", ret);
2362 return ret;
2363 }
2364
2365 /*************************************************************************
2366 * @ [SHLWAPI.220]
2367 *
2368 * Set the Font for a window and the "PropDlgFont" property of the parent window.
2369 *
2370 * PARAMS
2371 * hWnd [I] Parent Window to set the property
2372 * id [I] Index of child Window to set the Font
2373 *
2374 * RETURNS
2375 * Success: S_OK
2376 *
2377 */
2378 HRESULT WINAPI SHSetDefaultDialogFont(HWND hWnd, INT id)
2379 {
2380 FIXME("(%p, %d) stub\n", hWnd, id);
2381 return S_OK;
2382 }
2383
2384 /*************************************************************************
2385 * @ [SHLWAPI.221]
2386 *
2387 * Remove the "PropDlgFont" property from a window.
2388 *
2389 * PARAMS
2390 * hWnd [I] Window to remove the property from
2391 *
2392 * RETURNS
2393 * A handle to the removed property, or NULL if it did not exist.
2394 */
2395 HANDLE WINAPI SHRemoveDefaultDialogFont(HWND hWnd)
2396 {
2397 HANDLE hProp;
2398
2399 TRACE("(%p)\n", hWnd);
2400
2401 hProp = GetPropA(hWnd, "PropDlgFont");
2402
2403 if(hProp)
2404 {
2405 DeleteObject(hProp);
2406 hProp = RemovePropA(hWnd, "PropDlgFont");
2407 }
2408 return hProp;
2409 }
2410
2411 /*************************************************************************
2412 * @ [SHLWAPI.236]
2413 *
2414 * Load the in-process server of a given GUID.
2415 *
2416 * PARAMS
2417 * refiid [I] GUID of the server to load.
2418 *
2419 * RETURNS
2420 * Success: A handle to the loaded server dll.
2421 * Failure: A NULL handle.
2422 */
2423 HMODULE WINAPI SHPinDllOfCLSID(REFIID refiid)
2424 {
2425 HKEY newkey;
2426 DWORD type, count;
2427 CHAR value[MAX_PATH], string[MAX_PATH];
2428
2429 strcpy(string, "CLSID\\");
2430 SHStringFromGUIDA(refiid, string + 6, sizeof(string)/sizeof(char) - 6);
2431 strcat(string, "\\InProcServer32");
2432
2433 count = MAX_PATH;
2434 RegOpenKeyExA(HKEY_CLASSES_ROOT, string, 0, 1, &newkey);
2435 RegQueryValueExA(newkey, 0, 0, &type, (PBYTE)value, &count);
2436 RegCloseKey(newkey);
2437 return LoadLibraryExA(value, 0, 0);
2438 }
2439
2440 /*************************************************************************
2441 * @ [SHLWAPI.237]
2442 *
2443 * Unicode version of SHLWAPI_183.
2444 */
2445 DWORD WINAPI SHRegisterClassW(WNDCLASSW * lpWndClass)
2446 {
2447 WNDCLASSW WndClass;
2448
2449 TRACE("(%p %s)\n",lpWndClass->hInstance, debugstr_w(lpWndClass->lpszClassName));
2450
2451 if (GetClassInfoW(lpWndClass->hInstance, lpWndClass->lpszClassName, &WndClass))
2452 return TRUE;
2453 return RegisterClassW(lpWndClass);
2454 }
2455
2456 /*************************************************************************
2457 * @ [SHLWAPI.238]
2458 *
2459 * Unregister a list of classes.
2460 *
2461 * PARAMS
2462 * hInst [I] Application instance that registered the classes
2463 * lppClasses [I] List of class names
2464 * iCount [I] Number of names in lppClasses
2465 *
2466 * RETURNS
2467 * Nothing.
2468 */
2469 void WINAPI SHUnregisterClassesA(HINSTANCE hInst, LPCSTR *lppClasses, INT iCount)
2470 {
2471 WNDCLASSA WndClass;
2472
2473 TRACE("(%p,%p,%d)\n", hInst, lppClasses, iCount);
2474
2475 while (iCount > 0)
2476 {
2477 if (GetClassInfoA(hInst, *lppClasses, &WndClass))
2478 UnregisterClassA(*lppClasses, hInst);
2479 lppClasses++;
2480 iCount--;
2481 }
2482 }
2483
2484 /*************************************************************************
2485 * @ [SHLWAPI.239]
2486 *
2487 * Unicode version of SHUnregisterClassesA.
2488 */
2489 void WINAPI SHUnregisterClassesW(HINSTANCE hInst, LPCWSTR *lppClasses, INT iCount)
2490 {
2491 WNDCLASSW WndClass;
2492
2493 TRACE("(%p,%p,%d)\n", hInst, lppClasses, iCount);
2494
2495 while (iCount > 0)
2496 {
2497 if (GetClassInfoW(hInst, *lppClasses, &WndClass))
2498 UnregisterClassW(*lppClasses, hInst);
2499 lppClasses++;
2500 iCount--;
2501 }
2502 }
2503
2504 /*************************************************************************
2505 * @ [SHLWAPI.240]
2506 *
2507 * Call The correct (Ascii/Unicode) default window procedure for a window.
2508 *
2509 * PARAMS
2510 * hWnd [I] Window to call the default procedure for
2511 * uMessage [I] Message ID
2512 * wParam [I] WPARAM of message
2513 * lParam [I] LPARAM of message
2514 *
2515 * RETURNS
2516 * The result of calling DefWindowProcA() or DefWindowProcW().
2517 */
2518 LRESULT CALLBACK SHDefWindowProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
2519 {
2520 if (IsWindowUnicode(hWnd))
2521 return DefWindowProcW(hWnd, uMessage, wParam, lParam);
2522 return DefWindowProcA(hWnd, uMessage, wParam, lParam);
2523 }
2524
2525 /*************************************************************************
2526 * @ [SHLWAPI.256]
2527 */
2528 HRESULT WINAPI IUnknown_GetSite(LPUNKNOWN lpUnknown, REFIID iid, PVOID *lppSite)
2529 {
2530 HRESULT hRet = E_INVALIDARG;
2531 LPOBJECTWITHSITE lpSite = NULL;
2532
2533 TRACE("(%p,%s,%p)\n", lpUnknown, debugstr_guid(iid), lppSite);
2534
2535 if (lpUnknown && iid && lppSite)
2536 {
2537 hRet = IUnknown_QueryInterface(lpUnknown, &IID_IObjectWithSite,
2538 (void**)&lpSite);
2539 if (SUCCEEDED(hRet) && lpSite)
2540 {
2541 hRet = IObjectWithSite_GetSite(lpSite, iid, lppSite);
2542 IObjectWithSite_Release(lpSite);
2543 }
2544 }
2545 return hRet;
2546 }
2547
2548 /*************************************************************************
2549 * @ [SHLWAPI.257]
2550 *
2551 * Create a worker window using CreateWindowExA().
2552 *
2553 * PARAMS
2554 * wndProc [I] Window procedure
2555 * hWndParent [I] Parent window
2556 * dwExStyle [I] Extra style flags
2557 * dwStyle [I] Style flags
2558 * hMenu [I] Window menu
2559 * wnd_extra [I] Window extra bytes value
2560 *
2561 * RETURNS
2562 * Success: The window handle of the newly created window.
2563 * Failure: 0.
2564 */
2565 HWND WINAPI SHCreateWorkerWindowA(LONG wndProc, HWND hWndParent, DWORD dwExStyle,
2566 DWORD dwStyle, HMENU hMenu, LONG_PTR wnd_extra)
2567 {
2568 static const char szClass[] = "WorkerA";
2569 WNDCLASSA wc;
2570 HWND hWnd;
2571
2572 TRACE("(0x%08x, %p, 0x%08x, 0x%08x, %p, 0x%08lx)\n",
2573 wndProc, hWndParent, dwExStyle, dwStyle, hMenu, wnd_extra);
2574
2575 /* Create Window class */
2576 wc.style = 0;
2577 wc.lpfnWndProc = DefWindowProcA;
2578 wc.cbClsExtra = 0;
2579 wc.cbWndExtra = sizeof(LONG_PTR);
2580 wc.hInstance = shlwapi_hInstance;
2581 wc.hIcon = NULL;
2582 wc.hCursor = LoadCursorA(NULL, (LPSTR)IDC_ARROW);
2583 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
2584 wc.lpszMenuName = NULL;
2585 wc.lpszClassName = szClass;
2586
2587 SHRegisterClassA(&wc);
2588
2589 hWnd = CreateWindowExA(dwExStyle, szClass, 0, dwStyle, 0, 0, 0, 0,
2590 hWndParent, hMenu, shlwapi_hInstance, 0);
2591 if (hWnd)
2592 {
2593 SetWindowLongPtrW(hWnd, 0, wnd_extra);
2594
2595 if (wndProc) SetWindowLongPtrA(hWnd, GWLP_WNDPROC, wndProc);
2596 }
2597
2598 return hWnd;
2599 }
2600
2601 typedef struct tagPOLICYDATA
2602 {
2603 DWORD policy; /* flags value passed to SHRestricted */
2604 LPCWSTR appstr; /* application str such as "Explorer" */
2605 LPCWSTR keystr; /* name of the actual registry key / policy */
2606 } POLICYDATA, *LPPOLICYDATA;
2607
2608 #define SHELL_NO_POLICY 0xffffffff
2609
2610 /* default shell policy registry key */
2611 static const WCHAR strRegistryPolicyW[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o',
2612 's','o','f','t','\\','W','i','n','d','o','w','s','\\',
2613 'C','u','r','r','e','n','t','V','e','r','s','i','o','n',
2614 '\\','P','o','l','i','c','i','e','s',0};
2615
2616 /*************************************************************************
2617 * @ [SHLWAPI.271]
2618 *
2619 * Retrieve a policy value from the registry.
2620 *
2621 * PARAMS
2622 * lpSubKey [I] registry key name
2623 * lpSubName [I] subname of registry key
2624 * lpValue [I] value name of registry value
2625 *
2626 * RETURNS
2627 * the value associated with the registry key or 0 if not found
2628 */
2629 DWORD WINAPI SHGetRestriction(LPCWSTR lpSubKey, LPCWSTR lpSubName, LPCWSTR lpValue)
2630 {
2631 DWORD retval, datsize = sizeof(retval);
2632 HKEY hKey;
2633
2634 if (!lpSubKey)
2635 lpSubKey = strRegistryPolicyW;
2636
2637 retval = RegOpenKeyW(HKEY_LOCAL_MACHINE, lpSubKey, &hKey);
2638 if (retval != ERROR_SUCCESS)
2639 retval = RegOpenKeyW(HKEY_CURRENT_USER, lpSubKey, &hKey);
2640 if (retval != ERROR_SUCCESS)
2641 return 0;
2642
2643 SHGetValueW(hKey, lpSubName, lpValue, NULL, &retval, &datsize);
2644 RegCloseKey(hKey);
2645 return retval;
2646 }
2647
2648 /*************************************************************************
2649 * @ [SHLWAPI.266]
2650 *
2651 * Helper function to retrieve the possibly cached value for a specific policy
2652 *
2653 * PARAMS
2654 * policy [I] The policy to look for
2655 * initial [I] Main registry key to open, if NULL use default
2656 * polTable [I] Table of known policies, 0 terminated
2657 * polArr [I] Cache array of policy values
2658 *
2659 * RETURNS
2660 * The retrieved policy value or 0 if not successful
2661 *
2662 * NOTES
2663 * This function is used by the native SHRestricted function to search for the
2664 * policy and cache it once retrieved. The current Wine implementation uses a
2665 * different POLICYDATA structure and implements a similar algorithm adapted to
2666 * that structure.
2667 */
2668 DWORD WINAPI SHRestrictionLookup(
2669 DWORD policy,
2670 LPCWSTR initial,
2671 LPPOLICYDATA polTable,
2672 LPDWORD polArr)
2673 {
2674 TRACE("(0x%08x %s %p %p)\n", policy, debugstr_w(initial), polTable, polArr);
2675
2676 if (!polTable || !polArr)
2677 return 0;
2678
2679 for (;polTable->policy; polTable++, polArr++)
2680 {
2681 if (policy == polTable->policy)
2682 {
2683 /* we have a known policy */
2684
2685 /* check if this policy has been cached */
2686 if (*polArr == SHELL_NO_POLICY)
2687 *polArr = SHGetRestriction(initial, polTable->appstr, polTable->keystr);
2688 return *polArr;
2689 }
2690 }
2691 /* we don't know this policy, return 0 */
2692 TRACE("unknown policy: (%08x)\n", policy);
2693 return 0;
2694 }
2695
2696 /*************************************************************************
2697 * @ [SHLWAPI.267]
2698 *
2699 * Get an interface from an object.
2700 *
2701 * RETURNS
2702 * Success: S_OK. ppv contains the requested interface.
2703 * Failure: An HRESULT error code.
2704 *
2705 * NOTES
2706 * This QueryInterface asks the inner object for an interface. In case
2707 * of aggregation this request would be forwarded by the inner to the
2708 * outer object. This function asks the inner object directly for the
2709 * interface circumventing the forwarding to the outer object.
2710 */
2711 HRESULT WINAPI SHWeakQueryInterface(
2712 IUnknown * pUnk, /* [in] Outer object */
2713 IUnknown * pInner, /* [in] Inner object */
2714 IID * riid, /* [in] Interface GUID to query for */
2715 LPVOID* ppv) /* [out] Destination for queried interface */
2716 {
2717 HRESULT hret = E_NOINTERFACE;
2718 TRACE("(pUnk=%p pInner=%p\n\tIID: %s %p)\n",pUnk,pInner,debugstr_guid(riid), ppv);
2719
2720 *ppv = NULL;
2721 if(pUnk && pInner) {
2722 hret = IUnknown_QueryInterface(pInner, riid, ppv);
2723 if (SUCCEEDED(hret)) IUnknown_Release(pUnk);
2724 }
2725 TRACE("-- 0x%08x\n", hret);
2726 return hret;
2727 }
2728
2729 /*************************************************************************
2730 * @ [SHLWAPI.268]
2731 *
2732 * Move a reference from one interface to another.
2733 *
2734 * PARAMS
2735 * lpDest [O] Destination to receive the reference
2736 * lppUnknown [O] Source to give up the reference to lpDest
2737 *
2738 * RETURNS
2739 * Nothing.
2740 */
2741 VOID WINAPI SHWeakReleaseInterface(IUnknown *lpDest, IUnknown **lppUnknown)
2742 {
2743 TRACE("(%p,%p)\n", lpDest, lppUnknown);
2744
2745 if (*lppUnknown)
2746 {
2747 /* Copy Reference*/
2748 IUnknown_AddRef(lpDest);
2749 IUnknown_AtomicRelease(lppUnknown); /* Release existing interface */
2750 }
2751 }
2752
2753 /*************************************************************************
2754 * @ [SHLWAPI.269]
2755 *
2756 * Convert an ASCII string of a CLSID into a CLSID.
2757 *
2758 * PARAMS
2759 * idstr [I] String representing a CLSID in registry format
2760 * id [O] Destination for the converted CLSID
2761 *
2762 * RETURNS
2763 * Success: TRUE. id contains the converted CLSID.
2764 * Failure: FALSE.
2765 */
2766 BOOL WINAPI GUIDFromStringA(LPCSTR idstr, CLSID *id)
2767 {
2768 WCHAR wClsid[40];
2769 MultiByteToWideChar(CP_ACP, 0, idstr, -1, wClsid, sizeof(wClsid)/sizeof(WCHAR));
2770 return SUCCEEDED(CLSIDFromString(wClsid, id));
2771 }
2772
2773 /*************************************************************************
2774 * @ [SHLWAPI.270]
2775 *
2776 * Unicode version of GUIDFromStringA.
2777 */
2778 BOOL WINAPI GUIDFromStringW(LPCWSTR idstr, CLSID *id)
2779 {
2780 return SUCCEEDED(CLSIDFromString((LPCOLESTR)idstr, id));
2781 }
2782
2783 /*************************************************************************
2784 * @ [SHLWAPI.276]
2785 *
2786 * Determine if the browser is integrated into the shell, and set a registry
2787 * key accordingly.
2788 *
2789 * PARAMS
2790 * None.
2791 *
2792 * RETURNS
2793 * 1, If the browser is not integrated.
2794 * 2, If the browser is integrated.
2795 *
2796 * NOTES
2797 * The key "HKLM\Software\Microsoft\Internet Explorer\IntegratedBrowser" is
2798 * either set to TRUE, or removed depending on whether the browser is deemed
2799 * to be integrated.
2800 */
2801 DWORD WINAPI WhichPlatform(void)
2802 {
2803 static const char szIntegratedBrowser[] = "IntegratedBrowser";
2804 static DWORD dwState = 0;
2805 HKEY hKey;
2806 DWORD dwRet, dwData, dwSize;
2807 HMODULE hshell32;
2808
2809 if (dwState)
2810 return dwState;
2811
2812 /* If shell32 exports DllGetVersion(), the browser is integrated */
2813 dwState = 1;
2814 hshell32 = LoadLibraryA("shell32.dll");
2815 if (hshell32)
2816 {
2817 FARPROC pDllGetVersion;
2818 pDllGetVersion = GetProcAddress(hshell32, "DllGetVersion");
2819 dwState = pDllGetVersion ? 2 : 1;
2820 FreeLibrary(hshell32);
2821 }
2822
2823 /* Set or delete the key accordingly */
2824 dwRet = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
2825 "Software\\Microsoft\\Internet Explorer", 0,
2826 KEY_ALL_ACCESS, &hKey);
2827 if (!dwRet)
2828 {
2829 dwRet = RegQueryValueExA(hKey, szIntegratedBrowser, 0, 0,
2830 (LPBYTE)&dwData, &dwSize);
2831
2832 if (!dwRet && dwState == 1)
2833 {
2834 /* Value exists but browser is not integrated */
2835 RegDeleteValueA(hKey, szIntegratedBrowser);
2836 }
2837 else if (dwRet && dwState == 2)
2838 {
2839 /* Browser is integrated but value does not exist */
2840 dwData = TRUE;
2841 RegSetValueExA(hKey, szIntegratedBrowser, 0, REG_DWORD,
2842 (LPBYTE)&dwData, sizeof(dwData));
2843 }
2844 RegCloseKey(hKey);
2845 }
2846 return dwState;
2847 }
2848
2849 /*************************************************************************
2850 * @ [SHLWAPI.278]
2851 *
2852 * Unicode version of SHCreateWorkerWindowA.
2853 */
2854 HWND WINAPI SHCreateWorkerWindowW(LONG wndProc, HWND hWndParent, DWORD dwExStyle,
2855 DWORD dwStyle, HMENU hMenu, LONG msg_result)
2856 {
2857 static const WCHAR szClass[] = { 'W', 'o', 'r', 'k', 'e', 'r', 'W', 0 };
2858 WNDCLASSW wc;
2859 HWND hWnd;
2860
2861 TRACE("(0x%08x, %p, 0x%08x, 0x%08x, %p, 0x%08x)\n",
2862 wndProc, hWndParent, dwExStyle, dwStyle, hMenu, msg_result);
2863
2864 /* If our OS is natively ANSI, use the ANSI version */
2865 if (GetVersion() & 0x80000000) /* not NT */
2866 {
2867 TRACE("fallback to ANSI, ver 0x%08x\n", GetVersion());
2868 return SHCreateWorkerWindowA(wndProc, hWndParent, dwExStyle, dwStyle, hMenu, msg_result);
2869 }
2870
2871 /* Create Window class */
2872 wc.style = 0;
2873 wc.lpfnWndProc = DefWindowProcW;
2874 wc.cbClsExtra = 0;
2875 wc.cbWndExtra = 4;
2876 wc.hInstance = shlwapi_hInstance;
2877 wc.hIcon = NULL;
2878 wc.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
2879 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
2880 wc.lpszMenuName = NULL;
2881 wc.lpszClassName = szClass;
2882
2883 SHRegisterClassW(&wc);
2884
2885 hWnd = CreateWindowExW(dwExStyle, szClass, 0, dwStyle, 0, 0, 0, 0,
2886 hWndParent, hMenu, shlwapi_hInstance, 0);
2887 if (hWnd)
2888 {
2889 SetWindowLongPtrW(hWnd, DWLP_MSGRESULT, msg_result);
2890
2891 if (wndProc) SetWindowLongPtrW(hWnd, GWLP_WNDPROC, wndProc);
2892 }
2893
2894 return hWnd;
2895 }
2896
2897 /*************************************************************************
2898 * @ [SHLWAPI.279]
2899 *
2900 * Get and show a context menu from a shell folder.
2901 *
2902 * PARAMS
2903 * hWnd [I] Window displaying the shell folder
2904 * lpFolder [I] IShellFolder interface
2905 * lpApidl [I] Id for the particular folder desired
2906 *
2907 * RETURNS
2908 * Success: S_OK.
2909 * Failure: An HRESULT error code indicating the error.
2910 */
2911 HRESULT WINAPI SHInvokeDefaultCommand(HWND hWnd, IShellFolder* lpFolder, LPCITEMIDLIST lpApidl)
2912 {
2913 TRACE("%p %p %p\n", hWnd, lpFolder, lpApidl);
2914 return SHInvokeCommand(hWnd, lpFolder, lpApidl, 0);
2915 }
2916
2917 /*************************************************************************
2918 * @ [SHLWAPI.281]
2919 *
2920 * _SHPackDispParamsV
2921 */
2922 HRESULT WINAPI SHPackDispParamsV(DISPPARAMS *params, VARIANTARG *args, UINT cnt, __ms_va_list valist)
2923 {
2924 VARIANTARG *iter;
2925
2926 TRACE("(%p %p %u ...)\n", params, args, cnt);
2927
2928 params->rgvarg = args;
2929 params->rgdispidNamedArgs = NULL;
2930 params->cArgs = cnt;
2931 params->cNamedArgs = 0;
2932
2933 iter = args+cnt;
2934
2935 while(iter-- > args) {
2936 V_VT(iter) = va_arg(valist, enum VARENUM);
2937
2938 TRACE("vt=%d\n", V_VT(iter));
2939
2940 if(V_VT(iter) & VT_BYREF) {
2941 V_BYREF(iter) = va_arg(valist, LPVOID);
2942 } else {
2943 switch(V_VT(iter)) {
2944 case VT_I4:
2945 V_I4(iter) = va_arg(valist, LONG);
2946 break;
2947 case VT_BSTR:
2948 V_BSTR(iter) = va_arg(valist, BSTR);
2949 break;
2950 case VT_DISPATCH:
2951 V_DISPATCH(iter) = va_arg(valist, IDispatch*);
2952 break;
2953 case VT_BOOL:
2954 V_BOOL(iter) = va_arg(valist, int);
2955 break;
2956 case VT_UNKNOWN:
2957 V_UNKNOWN(iter) = va_arg(valist, IUnknown*);
2958 break;
2959 default:
2960 V_VT(iter) = VT_I4;
2961 V_I4(iter) = va_arg(valist, LONG);
2962 }
2963 }
2964 }
2965
2966 return S_OK;
2967 }
2968
2969 /*************************************************************************
2970 * @ [SHLWAPI.282]
2971 *
2972 * SHPackDispParams
2973 */
2974 HRESULT WINAPIV SHPackDispParams(DISPPARAMS *params, VARIANTARG *args, UINT cnt, ...)
2975 {
2976 __ms_va_list valist;
2977 HRESULT hres;
2978
2979 __ms_va_start(valist, cnt);
2980 hres = SHPackDispParamsV(params, args, cnt, valist);
2981 __ms_va_end(valist);
2982 return hres;
2983 }
2984
2985 /*************************************************************************
2986 * SHLWAPI_InvokeByIID
2987 *
2988 * This helper function calls IDispatch::Invoke for each sink
2989 * which implements given iid or IDispatch.
2990 *
2991 */
2992 static HRESULT SHLWAPI_InvokeByIID(
2993 IConnectionPoint* iCP,
2994 REFIID iid,
2995 DISPID dispId,
2996 DISPPARAMS* dispParams)
2997 {
2998 IEnumConnections *enumerator;
2999 CONNECTDATA rgcd;
3000 static DISPPARAMS empty = {NULL, NULL, 0, 0};
3001 DISPPARAMS* params = dispParams;
3002
3003 HRESULT result = IConnectionPoint_EnumConnections(iCP, &enumerator);
3004 if (FAILED(result))
3005 return result;
3006
3007 /* Invoke is never happening with an NULL dispParams */
3008 if (!params)
3009 params = &empty;
3010
3011 while(IEnumConnections_Next(enumerator, 1, &rgcd, NULL)==S_OK)
3012 {
3013 IDispatch *dispIface;
3014 if ((iid && SUCCEEDED(IUnknown_QueryInterface(rgcd.pUnk, iid, (LPVOID*)&dispIface))) ||
3015 SUCCEEDED(IUnknown_QueryInterface(rgcd.pUnk, &IID_IDispatch, (LPVOID*)&dispIface)))
3016 {
3017 IDispatch_Invoke(dispIface, dispId, &IID_NULL, 0, DISPATCH_METHOD, params, NULL, NULL, NULL);
3018 IDispatch_Release(dispIface);
3019 }
3020 IUnknown_Release(rgcd.pUnk);
3021 }
3022
3023 IEnumConnections_Release(enumerator);
3024
3025 return S_OK;
3026 }
3027
3028 /*************************************************************************
3029 * IConnectionPoint_InvokeWithCancel [SHLWAPI.283]
3030 */
3031 HRESULT WINAPI IConnectionPoint_InvokeWithCancel( IConnectionPoint* iCP,
3032 DISPID dispId, DISPPARAMS* dispParams,
3033 DWORD unknown1, DWORD unknown2 )
3034 {
3035 IID iid;
3036 HRESULT result;
3037
3038 FIXME("(%p)->(0x%x %p %x %x) partial stub\n", iCP, dispId, dispParams, unknown1, unknown2);
3039
3040 result = IConnectionPoint_GetConnectionInterface(iCP, &iid);
3041 if (SUCCEEDED(result))
3042 result = SHLWAPI_InvokeByIID(iCP, &iid, dispId, dispParams);
3043 else
3044 result = SHLWAPI_InvokeByIID(iCP, NULL, dispId, dispParams);
3045
3046 return result;
3047 }
3048
3049
3050 /*************************************************************************
3051 * @ [SHLWAPI.284]
3052 *
3053 * IConnectionPoint_SimpleInvoke
3054 */
3055 HRESULT WINAPI IConnectionPoint_SimpleInvoke(
3056 IConnectionPoint* iCP,
3057 DISPID dispId,
3058 DISPPARAMS* dispParams)
3059 {
3060 IID iid;
3061 HRESULT result;
3062
3063 TRACE("(%p)->(0x%x %p)\n",iCP,dispId,dispParams);
3064
3065 result = IConnectionPoint_GetConnectionInterface(iCP, &iid);
3066 if (SUCCEEDED(result))
3067 result = SHLWAPI_InvokeByIID(iCP, &iid, dispId, dispParams);
3068 else
3069 result = SHLWAPI_InvokeByIID(iCP, NULL, dispId, dispParams);
3070
3071 return result;
3072 }
3073
3074 /*************************************************************************
3075 * @ [SHLWAPI.285]
3076 *
3077 * Notify an IConnectionPoint object of changes.
3078 *
3079 * PARAMS
3080 * lpCP [I] Object to notify
3081 * dispID [I]
3082 *
3083 * RETURNS
3084 * Success: S_OK.
3085 * Failure: E_NOINTERFACE, if lpCP is NULL or does not support the
3086 * IConnectionPoint interface.
3087 */
3088 HRESULT WINAPI IConnectionPoint_OnChanged(IConnectionPoint* lpCP, DISPID dispID)
3089 {
3090 IEnumConnections *lpEnum;
3091 HRESULT hRet = E_NOINTERFACE;
3092
3093 TRACE("(%p,0x%8X)\n", lpCP, dispID);
3094
3095 /* Get an enumerator for the connections */
3096 if (lpCP)
3097 hRet = IConnectionPoint_EnumConnections(lpCP, &lpEnum);
3098
3099 if (SUCCEEDED(hRet))
3100 {
3101 IPropertyNotifySink *lpSink;
3102 CONNECTDATA connData;
3103 ULONG ulFetched;
3104
3105 /* Call OnChanged() for every notify sink in the connection point */
3106 while (IEnumConnections_Next(lpEnum, 1, &connData, &ulFetched) == S_OK)
3107 {
3108 if (SUCCEEDED(IUnknown_QueryInterface(connData.pUnk, &IID_IPropertyNotifySink, (void**)&lpSink)) &&
3109 lpSink)
3110 {
3111 IPropertyNotifySink_OnChanged(lpSink, dispID);
3112 IPropertyNotifySink_Release(lpSink);
3113 }
3114 IUnknown_Release(connData.pUnk);
3115 }
3116
3117 IEnumConnections_Release(lpEnum);
3118 }
3119 return hRet;
3120 }
3121
3122 /*************************************************************************
3123 * @ [SHLWAPI.286]
3124 *
3125 * IUnknown_CPContainerInvokeParam
3126 */
3127 HRESULT WINAPIV IUnknown_CPContainerInvokeParam(
3128 IUnknown *container,
3129 REFIID riid,
3130 DISPID dispId,
3131 VARIANTARG* buffer,
3132 DWORD cParams, ...)
3133 {
3134 HRESULT result;
3135 IConnectionPoint *iCP;
3136 IConnectionPointContainer *iCPC;
3137 DISPPARAMS dispParams = {buffer, NULL, cParams, 0};
3138 __ms_va_list valist;
3139
3140 if (!container)
3141 return E_NOINTERFACE;
3142
3143 result = IUnknown_QueryInterface(container, &IID_IConnectionPointContainer,(LPVOID*) &iCPC);
3144 if (FAILED(result))
3145 return result;
3146
3147 result = IConnectionPointContainer_FindConnectionPoint(iCPC, riid, &iCP);
3148 IConnectionPointContainer_Release(iCPC);
3149 if(FAILED(result))
3150 return result;
3151
3152 __ms_va_start(valist, cParams);
3153 SHPackDispParamsV(&dispParams, buffer, cParams, valist);
3154 __ms_va_end(valist);
3155
3156 result = SHLWAPI_InvokeByIID(iCP, riid, dispId, &dispParams);
3157 IConnectionPoint_Release(iCP);
3158
3159 return result;
3160 }
3161
3162 /*************************************************************************
3163 * @ [SHLWAPI.287]
3164 *
3165 * Notify an IConnectionPointContainer object of changes.
3166 *
3167 * PARAMS
3168 * lpUnknown [I] Object to notify
3169 * dispID [I]
3170 *
3171 * RETURNS
3172 * Success: S_OK.
3173 * Failure: E_NOINTERFACE, if lpUnknown is NULL or does not support the
3174 * IConnectionPointContainer interface.
3175 */
3176 HRESULT WINAPI IUnknown_CPContainerOnChanged(IUnknown *lpUnknown, DISPID dispID)
3177 {
3178 IConnectionPointContainer* lpCPC = NULL;
3179 HRESULT hRet = E_NOINTERFACE;
3180
3181 TRACE("(%p,0x%8X)\n", lpUnknown, dispID);
3182
3183 if (lpUnknown)
3184 hRet = IUnknown_QueryInterface(lpUnknown, &IID_IConnectionPointContainer, (void**)&lpCPC);
3185
3186 if (SUCCEEDED(hRet))
3187 {
3188 IConnectionPoint* lpCP;
3189
3190 hRet = IConnectionPointContainer_FindConnectionPoint(lpCPC, &IID_IPropertyNotifySink, &lpCP);
3191 IConnectionPointContainer_Release(lpCPC);
3192
3193 hRet = IConnectionPoint_OnChanged(lpCP, dispID);
3194 IConnectionPoint_Release(lpCP);
3195 }
3196 return hRet;
3197 }
3198
3199 /*************************************************************************
3200 * @ [SHLWAPI.289]
3201 *
3202 * See PlaySoundW.
3203 */
3204 BOOL WINAPI PlaySoundWrapW(LPCWSTR pszSound, HMODULE hmod, DWORD fdwSound)
3205 {
3206 return PlaySoundW(pszSound, hmod, fdwSound);
3207 }
3208
3209 /*************************************************************************
3210 * @ [SHLWAPI.294]
3211 *
3212 * Retrieve a key value from an INI file. See GetPrivateProfileString for
3213 * more information.
3214 *
3215 * PARAMS
3216 * appName [I] The section in the INI file that contains the key
3217 * keyName [I] The key to be retrieved
3218 * out [O] The buffer into which the key's value will be copied
3219 * outLen [I] The length of the `out' buffer
3220 * filename [I] The location of the INI file
3221 *
3222 * RETURNS
3223 * Length of string copied into `out'.
3224 */
3225 DWORD WINAPI SHGetIniStringW(LPCWSTR appName, LPCWSTR keyName, LPWSTR out,
3226 DWORD outLen, LPCWSTR filename)
3227 {
3228 INT ret;
3229 WCHAR *buf;
3230
3231 TRACE("(%s,%s,%p,%08x,%s)\n", debugstr_w(appName), debugstr_w(keyName),
3232 out, outLen, debugstr_w(filename));
3233
3234 if(outLen == 0)
3235 return 0;
3236
3237 buf = HeapAlloc(GetProcessHeap(), 0, outLen * sizeof(WCHAR));
3238 if(!buf){
3239 *out = 0;
3240 return 0;
3241 }
3242
3243 ret = GetPrivateProfileStringW(appName, keyName, NULL, buf, outLen, filename);
3244 if(ret)
3245 strcpyW(out, buf);
3246 else
3247 *out = 0;
3248
3249 HeapFree(GetProcessHeap(), 0, buf);
3250
3251 return strlenW(out);
3252 }
3253
3254 /*************************************************************************
3255 * @ [SHLWAPI.295]
3256 *
3257 * Set a key value in an INI file. See WritePrivateProfileString for
3258 * more information.
3259 *
3260 * PARAMS
3261 * appName [I] The section in the INI file that contains the key
3262 * keyName [I] The key to be set
3263 * str [O] The value of the key
3264 * filename [I] The location of the INI file
3265 *
3266 * RETURNS
3267 * Success: TRUE
3268 * Failure: FALSE
3269 */
3270 BOOL WINAPI SHSetIniStringW(LPCWSTR appName, LPCWSTR keyName, LPCWSTR str,
3271 LPCWSTR filename)
3272 {
3273 TRACE("(%s, %p, %s, %s)\n", debugstr_w(appName), keyName, debugstr_w(str),
3274 debugstr_w(filename));
3275
3276 return WritePrivateProfileStringW(appName, keyName, str, filename);
3277 }
3278
3279 /*************************************************************************
3280 * @ [SHLWAPI.313]
3281 *
3282 * See SHGetFileInfoW.
3283 */
3284 DWORD WINAPI SHGetFileInfoWrapW(LPCWSTR path, DWORD dwFileAttributes,
3285 SHFILEINFOW *psfi, UINT sizeofpsfi, UINT flags)
3286 {
3287 return SHGetFileInfoW(path, dwFileAttributes, psfi, sizeofpsfi, flags);
3288 }
3289
3290 /*************************************************************************
3291 * @ [SHLWAPI.318]
3292 *
3293 * See DragQueryFileW.
3294 */
3295 UINT WINAPI DragQueryFileWrapW(HDROP hDrop, UINT lFile, LPWSTR lpszFile, UINT lLength)
3296 {
3297 return DragQueryFileW(hDrop, lFile, lpszFile, lLength);
3298 }
3299
3300 /*************************************************************************
3301 * @ [SHLWAPI.333]
3302 *
3303 * See SHBrowseForFolderW.
3304 */
3305 LPITEMIDLIST WINAPI SHBrowseForFolderWrapW(LPBROWSEINFOW lpBi)
3306 {
3307 return SHBrowseForFolderW(lpBi);
3308 }
3309
3310 /*************************************************************************
3311 * @ [SHLWAPI.334]
3312 *
3313 * See SHGetPathFromIDListW.
3314 */
3315 BOOL WINAPI SHGetPathFromIDListWrapW(LPCITEMIDLIST pidl,LPWSTR pszPath)
3316 {
3317 return SHGetPathFromIDListW(pidl, pszPath);
3318 }
3319
3320 /*************************************************************************
3321 * @ [SHLWAPI.335]
3322 *
3323 * See ShellExecuteExW.
3324 */
3325 BOOL WINAPI ShellExecuteExWrapW(LPSHELLEXECUTEINFOW lpExecInfo)
3326 {
3327 return ShellExecuteExW(lpExecInfo);
3328 }
3329
3330 /*************************************************************************
3331 * @ [SHLWAPI.336]
3332 *
3333 * See SHFileOperationW.
3334 */
3335 INT WINAPI SHFileOperationWrapW(LPSHFILEOPSTRUCTW lpFileOp)
3336 {
3337 return SHFileOperationW(lpFileOp);
3338 }
3339
3340 /*************************************************************************
3341 * @ [SHLWAPI.342]
3342 *
3343 */
3344 PVOID WINAPI SHInterlockedCompareExchange( PVOID *dest, PVOID xchg, PVOID compare )
3345 {
3346 return InterlockedCompareExchangePointer( dest, xchg, compare );
3347 }
3348
3349 /*************************************************************************
3350 * @ [SHLWAPI.350]
3351 *
3352 * See GetFileVersionInfoSizeW.
3353 */
3354 DWORD WINAPI GetFileVersionInfoSizeWrapW( LPCWSTR filename, LPDWORD handle )
3355 {
3356 return GetFileVersionInfoSizeW( filename, handle );
3357 }
3358
3359 /*************************************************************************
3360 * @ [SHLWAPI.351]
3361 *
3362 * See GetFileVersionInfoW.
3363 */
3364 BOOL WINAPI GetFileVersionInfoWrapW( LPCWSTR filename, DWORD handle,
3365 DWORD datasize, LPVOID data )
3366 {
3367 return GetFileVersionInfoW( filename, handle, datasize, data );
3368 }
3369
3370 /*************************************************************************
3371 * @ [SHLWAPI.352]
3372 *
3373 * See VerQueryValueW.
3374 */
3375 WORD WINAPI VerQueryValueWrapW( LPVOID pBlock, LPCWSTR lpSubBlock,
3376 LPVOID *lplpBuffer, UINT *puLen )
3377 {
3378 return VerQueryValueW( pBlock, lpSubBlock, lplpBuffer, puLen );
3379 }
3380
3381 #define IsIface(type) SUCCEEDED((hRet = IUnknown_QueryInterface(lpUnknown, &IID_##type, (void**)&lpObj)))
3382 #define IShellBrowser_EnableModeless IShellBrowser_EnableModelessSB
3383 #define EnableModeless(type) type##_EnableModeless((type*)lpObj, bModeless)
3384
3385 /*************************************************************************
3386 * @ [SHLWAPI.355]
3387 *
3388 * Change the modality of a shell object.
3389 *
3390 * PARAMS
3391 * lpUnknown [I] Object to make modeless
3392 * bModeless [I] TRUE=Make modeless, FALSE=Make modal
3393 *
3394 * RETURNS
3395 * Success: S_OK. The modality lpUnknown is changed.
3396 * Failure: An HRESULT error code indicating the error.
3397 *
3398 * NOTES
3399 * lpUnknown must support the IOleInPlaceFrame interface, the
3400 * IInternetSecurityMgrSite interface, the IShellBrowser interface
3401 * the IDocHostUIHandler interface, or the IOleInPlaceActiveObject interface,
3402 * or this call will fail.
3403 */
3404 HRESULT WINAPI IUnknown_EnableModeless(IUnknown *lpUnknown, BOOL bModeless)
3405 {
3406 IUnknown *lpObj;
3407 HRESULT hRet;
3408
3409 TRACE("(%p,%d)\n", lpUnknown, bModeless);
3410
3411 if (!lpUnknown)
3412 return E_FAIL;
3413
3414 if (IsIface(IOleInPlaceActiveObject))
3415 EnableModeless(IOleInPlaceActiveObject);
3416 else if (IsIface(IOleInPlaceFrame))
3417 EnableModeless(IOleInPlaceFrame);
3418 else if (IsIface(IShellBrowser))
3419 EnableModeless(IShellBrowser);
3420 else if (IsIface(IInternetSecurityMgrSite))
3421 EnableModeless(IInternetSecurityMgrSite);
3422 else if (IsIface(IDocHostUIHandler))
3423 EnableModeless(IDocHostUIHandler);
3424 else
3425 return hRet;
3426
3427 IUnknown_Release(lpObj);
3428 return S_OK;
3429 }
3430
3431 /*************************************************************************
3432 * @ [SHLWAPI.357]
3433 *
3434 * See SHGetNewLinkInfoW.
3435 */
3436 BOOL WINAPI SHGetNewLinkInfoWrapW(LPCWSTR pszLinkTo, LPCWSTR pszDir, LPWSTR pszName,
3437 BOOL *pfMustCopy, UINT uFlags)
3438 {
3439 return SHGetNewLinkInfoW(pszLinkTo, pszDir, pszName, pfMustCopy, uFlags);
3440 }
3441
3442 /*************************************************************************
3443 * @ [SHLWAPI.358]
3444 *
3445 * See SHDefExtractIconW.
3446 */
3447 UINT WINAPI SHDefExtractIconWrapW(LPCWSTR pszIconFile, int iIndex, UINT uFlags, HICON* phiconLarge,
3448 HICON* phiconSmall, UINT nIconSize)
3449 {
3450 return SHDefExtractIconW(pszIconFile, iIndex, uFlags, phiconLarge, phiconSmall, nIconSize);
3451 }
3452
3453 /*************************************************************************
3454 * @ [SHLWAPI.363]
3455 *
3456 * Get and show a context menu from a shell folder.
3457 *
3458 * PARAMS
3459 * hWnd [I] Window displaying the shell folder
3460 * lpFolder [I] IShellFolder interface
3461 * lpApidl [I] Id for the particular folder desired
3462 * dwCommandId [I] The command ID to invoke (0=invoke default)
3463 *
3464 * RETURNS
3465 * Success: S_OK. If bInvokeDefault is TRUE, the default menu action was
3466 * executed.
3467 * Failure: An HRESULT error code indicating the error.
3468 */
3469 HRESULT WINAPI SHInvokeCommand(HWND hWnd, IShellFolder* lpFolder, LPCITEMIDLIST lpApidl, DWORD dwCommandId)
3470 {
3471 IContextMenu *iContext;
3472 HRESULT hRet;
3473
3474 TRACE("(%p, %p, %p, %u)\n", hWnd, lpFolder, lpApidl, dwCommandId);
3475
3476 if (!lpFolder)
3477 return E_FAIL;
3478
3479 /* Get the context menu from the shell folder */
3480 hRet = IShellFolder_GetUIObjectOf(lpFolder, hWnd, 1, &lpApidl,
3481 &IID_IContextMenu, 0, (void**)&iContext);
3482 if (SUCCEEDED(hRet))
3483 {
3484 HMENU hMenu;
3485 if ((hMenu = CreatePopupMenu()))
3486 {
3487 HRESULT hQuery;
3488
3489 /* Add the context menu entries to the popup */
3490 hQuery = IContextMenu_QueryContextMenu(iContext, hMenu, 0, 1, 0x7FFF,
3491 dwCommandId ? CMF_NORMAL : CMF_DEFAULTONLY);
3492
3493 if (SUCCEEDED(hQuery))
3494 {
3495 if (!dwCommandId)
3496 dwCommandId = GetMenuDefaultItem(hMenu, 0, 0);
3497 if (dwCommandId != (UINT)-1)
3498 {
3499 CMINVOKECOMMANDINFO cmIci;
3500 /* Invoke the default item */
3501 memset(&cmIci,0,sizeof(cmIci));
3502 cmIci.cbSize = sizeof(cmIci);
3503 cmIci.fMask = CMIC_MASK_ASYNCOK;
3504 cmIci.hwnd = hWnd;
3505 cmIci.lpVerb = MAKEINTRESOURCEA(dwCommandId);
3506 cmIci.nShow = SW_SHOWNORMAL;
3507
3508 hRet = IContextMenu_InvokeCommand(iContext, &cmIci);
3509 }
3510 }
3511 DestroyMenu(hMenu);
3512 }
3513 IContextMenu_Release(iContext);
3514 }
3515 return hRet;
3516 }
3517
3518 /*************************************************************************
3519 * @ [SHLWAPI.370]
3520 *
3521 * See ExtractIconW.
3522 */
3523 HICON WINAPI ExtractIconWrapW(HINSTANCE hInstance, LPCWSTR lpszExeFileName,
3524 UINT nIconIndex)
3525 {
3526 return ExtractIconW(hInstance, lpszExeFileName, nIconIndex);
3527 }
3528
3529 /*************************************************************************
3530 * @ [SHLWAPI.377]
3531 *
3532 * Load a library from the directory of a particular process.
3533 *
3534 * PARAMS
3535 * new_mod [I] Library name
3536 * inst_hwnd [I] Module whose directory is to be used
3537 * dwCrossCodePage [I] Should be FALSE (currently ignored)
3538 *
3539 * RETURNS
3540 * Success: A handle to the loaded module
3541 * Failure: A NULL handle.
3542 */
3543 HMODULE WINAPI MLLoadLibraryA(LPCSTR new_mod, HMODULE inst_hwnd, DWORD dwCrossCodePage)
3544 {
3545 /* FIXME: Native appears to do DPA_Create and a DPA_InsertPtr for
3546 * each call here.
3547 * FIXME: Native shows calls to:
3548 * SHRegGetUSValue for "Software\Microsoft\Internet Explorer\International"
3549 * CheckVersion
3550 * RegOpenKeyExA for "HKLM\Software\Microsoft\Internet Explorer"
3551 * RegQueryValueExA for "LPKInstalled"
3552 * RegCloseKey
3553 * RegOpenKeyExA for "HKCU\Software\Microsoft\Internet Explorer\International"
3554 * RegQueryValueExA for "ResourceLocale"
3555 * RegCloseKey
3556 * RegOpenKeyExA for "HKLM\Software\Microsoft\Active Setup\Installed Components\{guid}"
3557 * RegQueryValueExA for "Locale"
3558 * RegCloseKey
3559 * and then tests the Locale ("en" for me).
3560 * code below
3561 * after the code then a DPA_Create (first time) and DPA_InsertPtr are done.
3562 */
3563 CHAR mod_path[2*MAX_PATH];
3564 LPSTR ptr;
3565 DWORD len;
3566
3567 FIXME("(%s,%p,%d) semi-stub!\n", debugstr_a(new_mod), inst_hwnd, dwCrossCodePage);
3568 len = GetModuleFileNameA(inst_hwnd, mod_path, sizeof(mod_path));
3569 if (!len || len >= sizeof(mod_path)) return NULL;
3570
3571 ptr = strrchr(mod_path, '\\');
3572 if (ptr) {
3573 strcpy(ptr+1, new_mod);
3574 TRACE("loading %s\n", debugstr_a(mod_path));
3575 return LoadLibraryA(mod_path);
3576 }
3577 return NULL;
3578 }
3579
3580 /*************************************************************************
3581 * @ [SHLWAPI.378]
3582 *
3583 * Unicode version of MLLoadLibraryA.
3584 */
3585 HMODULE WINAPI MLLoadLibraryW(LPCWSTR new_mod, HMODULE inst_hwnd, DWORD dwCrossCodePage)
3586 {
3587 WCHAR mod_path[2*MAX_PATH];
3588 LPWSTR ptr;
3589 DWORD len;
3590
3591 FIXME("(%s,%p,%d) semi-stub!\n", debugstr_w(new_mod), inst_hwnd, dwCrossCodePage);
3592 len = GetModuleFileNameW(inst_hwnd, mod_path, sizeof(mod_path) / sizeof(WCHAR));
3593 if (!len || len >= sizeof(mod_path) / sizeof(WCHAR)) return NULL;
3594
3595 ptr = strrchrW(mod_path, '\\');
3596 if (ptr) {
3597 strcpyW(ptr+1, new_mod);
3598 TRACE("loading %s\n", debugstr_w(mod_path));
3599 return LoadLibraryW(mod_path);
3600 }
3601 return NULL;
3602 }
3603
3604 /*************************************************************************
3605 * ColorAdjustLuma [SHLWAPI.@]
3606 *
3607 * Adjust the luminosity of a color
3608 *
3609 * PARAMS
3610 * cRGB [I] RGB value to convert
3611 * dwLuma [I] Luma adjustment
3612 * bUnknown [I] Unknown
3613 *
3614 * RETURNS
3615 * The adjusted RGB color.
3616 */
3617 COLORREF WINAPI ColorAdjustLuma(COLORREF cRGB, int dwLuma, BOOL bUnknown)
3618 {
3619 TRACE("(0x%8x,%d,%d)\n", cRGB, dwLuma, bUnknown);
3620
3621 if (dwLuma)
3622 {
3623 WORD wH, wL, wS;
3624
3625 ColorRGBToHLS(cRGB, &wH, &wL, &wS);
3626
3627 FIXME("Ignoring luma adjustment\n");
3628
3629 /* FIXME: The adjustment is not linear */
3630
3631 cRGB = ColorHLSToRGB(wH, wL, wS);
3632 }
3633 return cRGB;
3634 }
3635
3636 /*************************************************************************
3637 * @ [SHLWAPI.389]
3638 *
3639 * See GetSaveFileNameW.
3640 */
3641 BOOL WINAPI GetSaveFileNameWrapW(LPOPENFILENAMEW ofn)
3642 {
3643 return GetSaveFileNameW(ofn);
3644 }
3645
3646 /*************************************************************************
3647 * @ [SHLWAPI.390]
3648 *
3649 * See WNetRestoreConnectionW.
3650 */
3651 DWORD WINAPI WNetRestoreConnectionWrapW(HWND hwndOwner, LPWSTR lpszDevice)
3652 {
3653 return WNetRestoreConnectionW(hwndOwner, lpszDevice);
3654 }
3655
3656 /*************************************************************************
3657 * @ [SHLWAPI.391]
3658 *
3659 * See WNetGetLastErrorW.
3660 */
3661 DWORD WINAPI WNetGetLastErrorWrapW(LPDWORD lpError, LPWSTR lpErrorBuf, DWORD nErrorBufSize,
3662 LPWSTR lpNameBuf, DWORD nNameBufSize)
3663 {
3664 return WNetGetLastErrorW(lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize);
3665 }
3666
3667 /*************************************************************************
3668 * @ [SHLWAPI.401]
3669 *
3670 * See PageSetupDlgW.
3671 */
3672 BOOL WINAPI PageSetupDlgWrapW(LPPAGESETUPDLGW pagedlg)
3673 {
3674 return PageSetupDlgW(pagedlg);
3675 }
3676
3677 /*************************************************************************
3678 * @ [SHLWAPI.402]
3679 *
3680 * See PrintDlgW.
3681 */
3682 BOOL WINAPI PrintDlgWrapW(LPPRINTDLGW printdlg)
3683 {
3684 return PrintDlgW(printdlg);
3685 }
3686
3687 /*************************************************************************
3688 * @ [SHLWAPI.403]
3689 *
3690 * See GetOpenFileNameW.
3691 */
3692 BOOL WINAPI GetOpenFileNameWrapW(LPOPENFILENAMEW ofn)
3693 {
3694 return GetOpenFileNameW(ofn);
3695 }
3696
3697 /*************************************************************************
3698 * @ [SHLWAPI.404]
3699 */
3700 HRESULT WINAPI SHIShellFolder_EnumObjects(LPSHELLFOLDER lpFolder, HWND hwnd, SHCONTF flags, IEnumIDList **ppenum)
3701 {
3702 /* Windows attempts to get an IPersist interface and, if that fails, an
3703 * IPersistFolder interface on the folder passed-in here. If one of those
3704 * interfaces is available, it then calls GetClassID on the folder... and
3705 * then calls IShellFolder_EnumObjects no matter what, even crashing if
3706 * lpFolder isn't actually an IShellFolder object. The purpose of getting
3707 * the ClassID is unknown, so we don't do it here.
3708 *
3709 * For discussion and detailed tests, see:
3710 * "shlwapi: Be less strict on which type of IShellFolder can be enumerated"
3711 * wine-devel mailing list, 3 Jun 2010
3712 */
3713
3714 return IShellFolder_EnumObjects(lpFolder, hwnd, flags, ppenum);
3715 }
3716
3717 /* INTERNAL: Map from HLS color space to RGB */
3718 static WORD ConvertHue(int wHue, WORD wMid1, WORD wMid2)
3719 {
3720 wHue = wHue > 240 ? wHue - 240 : wHue < 0 ? wHue + 240 : wHue;
3721
3722 if (wHue > 160)
3723 return wMid1;
3724 else if (wHue > 120)
3725 wHue = 160 - wHue;
3726 else if (wHue > 40)
3727 return wMid2;
3728
3729 return ((wHue * (wMid2 - wMid1) + 20) / 40) + wMid1;
3730 }
3731
3732 /* Convert to RGB and scale into RGB range (0..255) */
3733 #define GET_RGB(h) (ConvertHue(h, wMid1, wMid2) * 255 + 120) / 240
3734
3735 /*************************************************************************
3736 * ColorHLSToRGB [SHLWAPI.@]
3737 *
3738 * Convert from hls color space into an rgb COLORREF.
3739 *
3740 * PARAMS
3741 * wHue [I] Hue amount
3742 * wLuminosity [I] Luminosity amount
3743 * wSaturation [I] Saturation amount
3744 *
3745 * RETURNS
3746 * A COLORREF representing the converted color.
3747 *
3748 * NOTES
3749 * Input hls values are constrained to the range (0..240).
3750 */
3751 COLORREF WINAPI ColorHLSToRGB(WORD wHue, WORD wLuminosity, WORD wSaturation)
3752 {
3753 WORD wRed;
3754
3755 if (wSaturation)
3756 {
3757 WORD wGreen, wBlue, wMid1, wMid2;
3758
3759 if (wLuminosity > 120)
3760 wMid2 = wSaturation + wLuminosity - (wSaturation * wLuminosity + 120) / 240;
3761 else
3762 wMid2 = ((wSaturation + 240) * wLuminosity + 120) / 240;
3763
3764 wMid1 = wLuminosity * 2 - wMid2;
3765
3766 wRed = GET_RGB(wHue + 80);
3767 wGreen = GET_RGB(wHue);
3768 wBlue = GET_RGB(wHue - 80);
3769
3770 return RGB(wRed, wGreen, wBlue);
3771 }
3772
3773 wRed = wLuminosity * 255 / 240;
3774 return RGB(wRed, wRed, wRed);
3775 }
3776
3777 /*************************************************************************
3778 * @ [SHLWAPI.413]
3779 *
3780 * Get the current docking status of the system.
3781 *
3782