Sync with trunk revision 63128.
[reactos.git] / 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 * PARAMS
3783 * dwFlags [I] DOCKINFO_ flags from "winbase.h", unused
3784 *
3785 * RETURNS
3786 * One of DOCKINFO_UNDOCKED, DOCKINFO_UNDOCKED, or 0 if the system is not
3787 * a notebook.
3788 */
3789 DWORD WINAPI SHGetMachineInfo(DWORD dwFlags)
3790 {
3791 HW_PROFILE_INFOA hwInfo;
3792
3793 TRACE("(0x%08x)\n", dwFlags);
3794
3795 GetCurrentHwProfileA(&hwInfo);
3796 switch (hwInfo.dwDockInfo & (DOCKINFO_DOCKED|DOCKINFO_UNDOCKED))
3797 {
3798 case DOCKINFO_DOCKED:
3799 case DOCKINFO_UNDOCKED:
3800 return hwInfo.dwDockInfo & (DOCKINFO_DOCKED|DOCKINFO_UNDOCKED);
3801 default:
3802 return 0;
3803 }
3804 }
3805
3806 /*************************************************************************
3807 * @ [SHLWAPI.416]
3808 *
3809 */
3810 DWORD WINAPI SHWinHelpOnDemandW(HWND hwnd, LPCWSTR helpfile, DWORD flags1, VOID *ptr1, DWORD flags2)
3811 {
3812
3813 FIXME("(%p, %s, 0x%x, %p, %d)\n", hwnd, debugstr_w(helpfile), flags1, ptr1, flags2);
3814 return 0;
3815 }
3816
3817 /*************************************************************************
3818 * @ [SHLWAPI.417]
3819 *
3820 */
3821 DWORD WINAPI SHWinHelpOnDemandA(HWND hwnd, LPCSTR helpfile, DWORD flags1, VOID *ptr1, DWORD flags2)
3822 {
3823
3824 FIXME("(%p, %s, 0x%x, %p, %d)\n", hwnd, debugstr_a(helpfile), flags1, ptr1, flags2);
3825 return 0;
3826 }
3827
3828 /*************************************************************************
3829 * @ [SHLWAPI.418]
3830 *
3831 * Function seems to do FreeLibrary plus other things.
3832 *
3833 * FIXME native shows the following calls:
3834 * RtlEnterCriticalSection
3835 * LocalFree
3836 * GetProcAddress(Comctl32??, 150L)
3837 * DPA_DeletePtr
3838 * RtlLeaveCriticalSection
3839 * followed by the FreeLibrary.
3840 * The above code may be related to .377 above.
3841 */
3842 BOOL WINAPI MLFreeLibrary(HMODULE hModule)
3843 {
3844 FIXME("(%p) semi-stub\n", hModule);
3845 return FreeLibrary(hModule);
3846 }
3847
3848 /*************************************************************************
3849 * @ [SHLWAPI.419]
3850 */
3851 BOOL WINAPI SHFlushSFCacheWrap(void) {
3852 FIXME(": stub\n");
3853 return TRUE;
3854 }
3855
3856 /*************************************************************************
3857 * @ [SHLWAPI.429]
3858 * FIXME I have no idea what this function does or what its arguments are.
3859 */
3860 BOOL WINAPI MLIsMLHInstance(HINSTANCE hInst)
3861 {
3862 FIXME("(%p) stub\n", hInst);
3863 return FALSE;
3864 }
3865
3866
3867 /*************************************************************************
3868 * @ [SHLWAPI.430]
3869 */
3870 DWORD WINAPI MLSetMLHInstance(HINSTANCE hInst, HANDLE hHeap)
3871 {
3872 FIXME("(%p,%p) stub\n", hInst, hHeap);
3873 return E_FAIL; /* This is what is used if shlwapi not loaded */
3874 }
3875
3876 /*************************************************************************
3877 * @ [SHLWAPI.431]
3878 */
3879 DWORD WINAPI MLClearMLHInstance(DWORD x)
3880 {
3881 FIXME("(0x%08x)stub\n", x);
3882 return 0xabba1247;
3883 }
3884
3885 /*************************************************************************
3886 * @ [SHLWAPI.432]
3887 *
3888 * See SHSendMessageBroadcastW
3889 *
3890 */
3891 DWORD WINAPI SHSendMessageBroadcastA(UINT uMsg, WPARAM wParam, LPARAM lParam)
3892 {
3893 return SendMessageTimeoutA(HWND_BROADCAST, uMsg, wParam, lParam,
3894 SMTO_ABORTIFHUNG, 2000, NULL);
3895 }
3896
3897 /*************************************************************************
3898 * @ [SHLWAPI.433]
3899 *
3900 * A wrapper for sending Broadcast Messages to all top level Windows
3901 *
3902 */
3903 DWORD WINAPI SHSendMessageBroadcastW(UINT uMsg, WPARAM wParam, LPARAM lParam)
3904 {
3905 return SendMessageTimeoutW(HWND_BROADCAST, uMsg, wParam, lParam,
3906 SMTO_ABORTIFHUNG, 2000, NULL);
3907 }
3908
3909 /*************************************************************************
3910 * @ [SHLWAPI.436]
3911 *
3912 * Convert a Unicode string CLSID into a CLSID.
3913 *
3914 * PARAMS
3915 * idstr [I] string containing a CLSID in text form
3916 * id [O] CLSID extracted from the string
3917 *
3918 * RETURNS
3919 * S_OK on success or E_INVALIDARG on failure
3920 */
3921 HRESULT WINAPI CLSIDFromStringWrap(LPCWSTR idstr, CLSID *id)
3922 {
3923 return CLSIDFromString((LPCOLESTR)idstr, id);
3924 }
3925
3926 /*************************************************************************
3927 * @ [SHLWAPI.437]
3928 *
3929 * Determine if the OS supports a given feature.
3930 *
3931 * PARAMS
3932 * dwFeature [I] Feature requested (undocumented)
3933 *
3934 * RETURNS
3935 * TRUE If the feature is available.
3936 * FALSE If the feature is not available.
3937 */
3938 BOOL WINAPI IsOS(DWORD feature)
3939 {
3940 OSVERSIONINFOA osvi;
3941 DWORD platform, majorv, minorv;
3942
3943 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
3944 if(!GetVersionExA(&osvi)) {
3945 ERR("GetVersionEx failed\n");
3946 return FALSE;
3947 }
3948
3949 majorv = osvi.dwMajorVersion;
3950 minorv = osvi.dwMinorVersion;
3951 platform = osvi.dwPlatformId;
3952
3953 #define ISOS_RETURN(x) \
3954 TRACE("(0x%x) ret=%d\n",feature,(x)); \
3955 return (x);
3956
3957 switch(feature) {
3958 case OS_WIN32SORGREATER:
3959 ISOS_RETURN(platform == VER_PLATFORM_WIN32s
3960 || platform == VER_PLATFORM_WIN32_WINDOWS)
3961 case OS_NT:
3962 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
3963 case OS_WIN95ORGREATER:
3964 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS)
3965 case OS_NT4ORGREATER:
3966 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 4)
3967 case OS_WIN2000ORGREATER_ALT:
3968 case OS_WIN2000ORGREATER:
3969 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5)
3970 case OS_WIN98ORGREATER:
3971 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv >= 10)
3972 case OS_WIN98_GOLD:
3973 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv == 10)
3974 case OS_WIN2000PRO:
3975 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5)
3976 case OS_WIN2000SERVER:
3977 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1))
3978 case OS_WIN2000ADVSERVER:
3979 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1))
3980 case OS_WIN2000DATACENTER:
3981 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1))
3982 case OS_WIN2000TERMINAL:
3983 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1))
3984 case OS_EMBEDDED:
3985 FIXME("(OS_EMBEDDED) What should we return here?\n");
3986 return FALSE;
3987 case OS_TERMINALCLIENT:
3988 FIXME("(OS_TERMINALCLIENT) What should we return here?\n");
3989 return FALSE;
3990 case OS_TERMINALREMOTEADMIN:
3991 FIXME("(OS_TERMINALREMOTEADMIN) What should we return here?\n");
3992 return FALSE;
3993 case OS_WIN95_GOLD:
3994 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv == 0)
3995 case OS_MEORGREATER:
3996 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv >= 90)
3997 case OS_XPORGREATER:
3998 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5 && minorv >= 1)
3999 case OS_HOME:
4000 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5 && minorv >= 1)
4001 case OS_PROFESSIONAL:
4002 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
4003 case OS_DATACENTER:
4004 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
4005 case OS_ADVSERVER:
4006 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5)
4007 case OS_SERVER:
4008 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
4009 case OS_TERMINALSERVER:
4010 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
4011 case OS_PERSONALTERMINALSERVER:
4012 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && minorv >= 1 && majorv >= 5)
4013 case OS_FASTUSERSWITCHING:
4014 FIXME("(OS_FASTUSERSWITCHING) What should we return here?\n");
4015 return TRUE;
4016 case OS_WELCOMELOGONUI:
4017 FIXME("(OS_WELCOMELOGONUI) What should we return here?\n");
4018 return FALSE;
4019 case OS_DOMAINMEMBER:
4020 FIXME("(OS_DOMAINMEMBER) What should we return here?\n");
4021 return TRUE;
4022 case OS_ANYSERVER:
4023 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
4024 case OS_WOW6432:
4025 {
4026 BOOL is_wow64;
4027 IsWow64Process(GetCurrentProcess(), &is_wow64);
4028 return is_wow64;
4029 }
4030 case OS_WEBSERVER:
4031 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
4032 case OS_SMALLBUSINESSSERVER:
4033 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
4034 case OS_TABLETPC:
4035 FIXME("(OS_TABLEPC) What should we return here?\n");
4036 return FALSE;
4037 case OS_SERVERADMINUI:
4038 FIXME("(OS_SERVERADMINUI) What should we return here?\n");
4039 return FALSE;
4040 case OS_MEDIACENTER:
4041 FIXME("(OS_MEDIACENTER) What should we return here?\n");
4042 return FALSE;
4043 case OS_APPLIANCE:
4044 FIXME("(OS_APPLIANCE) What should we return here?\n");
4045 return FALSE;
4046 case 0x25: /*OS_VISTAORGREATER*/
4047 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 6)
4048 }
4049
4050 #undef ISOS_RETURN
4051
4052 WARN("(0x%x) unknown parameter\n",feature);
4053
4054 return FALSE;
4055 }
4056
4057 /*************************************************************************
4058 * @ [SHLWAPI.439]
4059 */
4060 HRESULT WINAPI SHLoadRegUIStringW(HKEY hkey, LPCWSTR value, LPWSTR buf, DWORD size)
4061 {
4062 DWORD type, sz = size;
4063
4064 if(RegQueryValueExW(hkey, value, NULL, &type, (LPBYTE)buf, &sz) != ERROR_SUCCESS)
4065 return E_FAIL;
4066
4067 return SHLoadIndirectString(buf, buf, size, NULL);
4068 }
4069
4070 /*************************************************************************
4071 * @ [SHLWAPI.478]
4072 *
4073 * Call IInputObject_TranslateAcceleratorIO() on an object.
4074 *
4075 * PARAMS
4076 * lpUnknown [I] Object supporting the IInputObject interface.
4077 * lpMsg [I] Key message to be processed.
4078 *
4079 * RETURNS
4080 * Success: S_OK.
4081 * Failure: An HRESULT error code, or E_INVALIDARG if lpUnknown is NULL.
4082 */
4083 HRESULT WINAPI IUnknown_TranslateAcceleratorIO(IUnknown *lpUnknown, LPMSG lpMsg)
4084 {
4085 IInputObject* lpInput = NULL;
4086 HRESULT hRet = E_INVALIDARG;
4087
4088 TRACE("(%p,%p)\n", lpUnknown, lpMsg);
4089 if (lpUnknown)
4090 {
4091 hRet = IUnknown_QueryInterface(lpUnknown, &IID_IInputObject,
4092 (void**)&lpInput);
4093 if (SUCCEEDED(hRet) && lpInput)
4094 {
4095 hRet = IInputObject_TranslateAcceleratorIO(lpInput, lpMsg);
4096 IInputObject_Release(lpInput);
4097 }
4098 }
4099 return hRet;
4100 }
4101
4102 /*************************************************************************
4103 * @ [SHLWAPI.481]
4104 *
4105 * Call IInputObject_HasFocusIO() on an object.
4106 *
4107 * PARAMS
4108 * lpUnknown [I] Object supporting the IInputObject interface.
4109 *
4110 * RETURNS
4111 * Success: S_OK, if lpUnknown is an IInputObject object and has the focus,
4112 * or S_FALSE otherwise.
4113 * Failure: An HRESULT error code, or E_INVALIDARG if lpUnknown is NULL.
4114 */
4115 HRESULT WINAPI IUnknown_HasFocusIO(IUnknown *lpUnknown)
4116 {
4117 IInputObject* lpInput = NULL;
4118 HRESULT hRet = E_INVALIDARG;
4119
4120 TRACE("(%p)\n", lpUnknown);
4121 if (lpUnknown)
4122 {
4123 hRet = IUnknown_QueryInterface(lpUnknown, &IID_IInputObject,
4124 (void**)&lpInput);
4125 if (SUCCEEDED(hRet) && lpInput)
4126 {
4127 hRet = IInputObject_HasFocusIO(lpInput);
4128 IInputObject_Release(lpInput);
4129 }
4130 }
4131 return hRet;
4132 }
4133
4134 /*************************************************************************
4135 * ColorRGBToHLS [SHLWAPI.@]
4136 *
4137 * Convert an rgb COLORREF into the hls color space.
4138 *
4139 * PARAMS
4140 * cRGB [I] Source rgb value
4141 * pwHue [O] Destination for converted hue
4142 * pwLuminance [O] Destination for converted luminance
4143 * pwSaturation [O] Destination for converted saturation
4144 *
4145 * RETURNS
4146 * Nothing. pwHue, pwLuminance and pwSaturation are set to the converted
4147 * values.
4148 *
4149 * NOTES
4150 * Output HLS values are constrained to the range (0..240).
4151 * For Achromatic conversions, Hue is set to 160.
4152 */
4153 VOID WINAPI ColorRGBToHLS(COLORREF cRGB, LPWORD pwHue,
4154 LPWORD pwLuminance, LPWORD pwSaturation)
4155 {
4156 int wR, wG, wB, wMax, wMin, wHue, wLuminosity, wSaturation;
4157
4158 TRACE("(%08x,%p,%p,%p)\n", cRGB, pwHue, pwLuminance, pwSaturation);
4159
4160 wR = GetRValue(cRGB);
4161 wG = GetGValue(cRGB);
4162 wB = GetBValue(cRGB);
4163
4164 wMax = max(wR, max(wG, wB));
4165 wMin = min(wR, min(wG, wB));
4166
4167 /* Luminosity */
4168 wLuminosity = ((wMax + wMin) * 240 + 255) / 510;
4169
4170 if (wMax == wMin)
4171 {
4172 /* Achromatic case */
4173 wSaturation = 0;
4174 /* Hue is now unrepresentable, but this is what native returns... */
4175 wHue = 160;
4176 }
4177 else
4178 {
4179 /* Chromatic case */
4180 int wDelta = wMax - wMin, wRNorm, wGNorm, wBNorm;
4181
4182 /* Saturation */
4183 if (wLuminosity <= 120)
4184 wSaturation = ((wMax + wMin)/2 + wDelta * 240) / (wMax + wMin);
4185 else
4186 wSaturation = ((510 - wMax - wMin)/2 + wDelta * 240) / (510 - wMax - wMin);
4187
4188 /* Hue */
4189 wRNorm = (wDelta/2 + wMax * 40 - wR * 40) / wDelta;
4190 wGNorm = (wDelta/2 + wMax * 40 - wG * 40) / wDelta;
4191 wBNorm = (wDelta/2 + wMax * 40 - wB * 40) / wDelta;
4192
4193 if (wR == wMax)
4194 wHue = wBNorm - wGNorm;
4195 else if (wG == wMax)
4196 wHue = 80 + wRNorm - wBNorm;
4197 else
4198 wHue = 160 + wGNorm - wRNorm;
4199 if (wHue < 0)
4200 wHue += 240;
4201 else if (wHue > 240)
4202 wHue -= 240;
4203 }
4204 if (pwHue)
4205 *pwHue = wHue;
4206 if (pwLuminance)
4207 *pwLuminance = wLuminosity;
4208 if (pwSaturation)
4209 *pwSaturation = wSaturation;
4210 }
4211
4212 /*************************************************************************
4213 * SHCreateShellPalette [SHLWAPI.@]
4214 */
4215 HPALETTE WINAPI SHCreateShellPalette(HDC hdc)
4216 {
4217 FIXME("stub\n");
4218 return CreateHalftonePalette(hdc);
4219 }
4220
4221 /*************************************************************************
4222 * SHGetInverseCMAP (SHLWAPI.@)
4223 *
4224 * Get an inverse color map table.
4225 *
4226 * PARAMS
4227 * lpCmap [O] Destination for color map
4228 * dwSize [I] Size of memory pointed to by lpCmap
4229 *
4230 * RETURNS
4231 * Success: S_OK.
4232 * Failure: E_POINTER, If lpCmap is invalid.
4233 * E_INVALIDARG, If dwFlags is invalid
4234 * E_OUTOFMEMORY, If there is no memory available
4235 *
4236 * NOTES
4237 * dwSize may only be CMAP_PTR_SIZE (4) or CMAP_SIZE (8192).
4238 * If dwSize = CMAP_PTR_SIZE, *lpCmap is set to the address of this DLL's
4239 * internal CMap.
4240 * If dwSize = CMAP_SIZE, lpCmap is filled with a copy of the data from
4241 * this DLL's internal CMap.
4242 */
4243 HRESULT WINAPI SHGetInverseCMAP(LPDWORD dest, DWORD dwSize)
4244 {
4245 if (dwSize == 4) {
4246 FIXME(" - returning bogus address for SHGetInverseCMAP\n");
4247 *dest = (DWORD)0xabba1249;
4248 return 0;
4249 }
4250 FIXME("(%p, %#x) stub\n", dest, dwSize);
4251 return 0;
4252 }
4253
4254 /*************************************************************************
4255 * SHIsLowMemoryMachine [SHLWAPI.@]
4256 *
4257 * Determine if the current computer has low memory.
4258 *
4259 * PARAMS
4260 * x [I] FIXME
4261 *
4262 * RETURNS
4263 * TRUE if the users machine has 16 Megabytes of memory or less,
4264 * FALSE otherwise.
4265 */
4266 BOOL WINAPI SHIsLowMemoryMachine (DWORD x)
4267 {
4268 FIXME("(0x%08x) stub\n", x);
4269 return FALSE;
4270 }
4271
4272 /*************************************************************************
4273 * GetMenuPosFromID [SHLWAPI.@]
4274 *
4275 * Return the position of a menu item from its Id.
4276 *
4277 * PARAMS
4278 * hMenu [I] Menu containing the item
4279 * wID [I] Id of the menu item
4280 *
4281 * RETURNS
4282 * Success: The index of the menu item in hMenu.
4283 * Failure: -1, If the item is not found.
4284 */
4285 INT WINAPI GetMenuPosFromID(HMENU hMenu, UINT wID)
4286 {
4287 MENUITEMINFOW mi;
4288 INT nCount = GetMenuItemCount(hMenu), nIter = 0;
4289
4290 TRACE("%p %u\n", hMenu, wID);
4291
4292 while (nIter < nCount)
4293 {
4294 mi.cbSize = sizeof(mi);
4295 mi.fMask = MIIM_ID;
4296 if (GetMenuItemInfoW(hMenu, nIter, TRUE, &mi) && mi.wID == wID)
4297 {
4298 TRACE("ret %d\n", nIter);
4299 return nIter;
4300 }
4301 nIter++;
4302 }
4303
4304 return -1;
4305 }
4306
4307 /*************************************************************************
4308 * @ [SHLWAPI.179]
4309 *
4310 * Same as SHLWAPI.GetMenuPosFromID
4311 */
4312 DWORD WINAPI SHMenuIndexFromID(HMENU hMenu, UINT uID)
4313 {
4314 TRACE("%p %u\n", hMenu, uID);
4315 return GetMenuPosFromID(hMenu, uID);
4316 }
4317
4318
4319 /*************************************************************************
4320 * @ [SHLWAPI.448]
4321 */
4322 VOID WINAPI FixSlashesAndColonW(LPWSTR lpwstr)
4323 {
4324 while (*lpwstr)
4325 {
4326 if (*lpwstr == '/')
4327 *lpwstr = '\\';
4328 lpwstr++;
4329 }
4330 }
4331
4332
4333 /*************************************************************************
4334 * @ [SHLWAPI.461]
4335 */
4336 DWORD WINAPI SHGetAppCompatFlags(DWORD dwUnknown)
4337 {
4338 FIXME("(0x%08x) stub\n", dwUnknown);
4339 return 0;
4340 }
4341
4342
4343 /*************************************************************************
4344 * @ [SHLWAPI.549]
4345 */
4346 HRESULT WINAPI SHCoCreateInstanceAC(REFCLSID rclsid, LPUNKNOWN pUnkOuter,
4347 DWORD dwClsContext, REFIID iid, LPVOID *ppv)
4348 {
4349 return CoCreateInstance(rclsid, pUnkOuter, dwClsContext, iid, ppv);
4350 }
4351
4352 /*************************************************************************
4353 * SHSkipJunction [SHLWAPI.@]
4354 *
4355 * Determine if a bind context can be bound to an object
4356 *
4357 * PARAMS
4358 * pbc [I] Bind context to check
4359 * pclsid [I] CLSID of object to be bound to
4360 *
4361 * RETURNS
4362 * TRUE: If it is safe to bind
4363 * FALSE: If pbc is invalid or binding would not be safe
4364 *
4365 */
4366 BOOL WINAPI SHSkipJunction(IBindCtx *pbc, const CLSID *pclsid)
4367 {
4368 static WCHAR szSkipBinding[] = { 'S','k','i','p',' ',
4369 'B','i','n','d','i','n','g',' ','C','L','S','I','D','\0' };
4370 BOOL bRet = FALSE;
4371
4372 if (pbc)
4373 {
4374 IUnknown* lpUnk;
4375
4376 if (SUCCEEDED(IBindCtx_GetObjectParam(pbc, szSkipBinding, &lpUnk)))
4377 {
4378 CLSID clsid;
4379
4380 if (SUCCEEDED(IUnknown_GetClassID(lpUnk, &clsid)) &&
4381 IsEqualGUID(pclsid, &clsid))
4382 bRet = TRUE;
4383
4384 IUnknown_Release(lpUnk);
4385 }
4386 }
4387 return bRet;
4388 }
4389
4390 /***********************************************************************
4391 * SHGetShellKey (SHLWAPI.491)
4392 */
4393 HKEY WINAPI SHGetShellKey(DWORD flags, LPCWSTR sub_key, BOOL create)
4394 {
4395 enum _shellkey_flags {
4396 SHKEY_Root_HKCU = 0x1,
4397 SHKEY_Root_HKLM = 0x2,
4398 SHKEY_Key_Explorer = 0x00,
4399 SHKEY_Key_Shell = 0x10,
4400 SHKEY_Key_ShellNoRoam = 0x20,
4401 SHKEY_Key_Classes = 0x30,
4402 SHKEY_Subkey_Default = 0x0000,
4403 SHKEY_Subkey_ResourceName = 0x1000,
4404 SHKEY_Subkey_Handlers = 0x2000,
4405 SHKEY_Subkey_Associations = 0x3000,
4406 SHKEY_Subkey_Volatile = 0x4000,
4407 SHKEY_Subkey_MUICache = 0x5000,
4408 SHKEY_Subkey_FileExts = 0x6000
4409 };
4410
4411 static const WCHAR explorerW[] = {'S','o','f','t','w','a','r','e','\\',
4412 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
4413 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4414 'E','x','p','l','o','r','e','r','\\'};
4415 static const WCHAR shellW[] = {'S','o','f','t','w','a','r','e','\\',
4416 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
4417 'S','h','e','l','l','\\'};
4418 static const WCHAR shell_no_roamW[] = {'S','o','f','t','w','a','r','e','\\',
4419 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
4420 'S','h','e','l','l','N','o','R','o','a','m','\\'};
4421 static const WCHAR classesW[] = {'S','o','f','t','w','a','r','e','\\',
4422 'C','l','a','s','s','e','s','\\'};
4423
4424 static const WCHAR localized_resource_nameW[] = {'L','o','c','a','l','i','z','e','d',
4425 'R','e','s','o','u','r','c','e','N','a','m','e','\\'};
4426 static const WCHAR handlersW[] = {'H','a','n','d','l','e','r','s','\\'};
4427 static const WCHAR associationsW[] = {'A','s','s','o','c','i','a','t','i','o','n','s','\\'};
4428 static const WCHAR volatileW[] = {'V','o','l','a','t','i','l','e','\\'};
4429 static const WCHAR mui_cacheW[] = {'M','U','I','C','a','c','h','e','\\'};
4430 static const WCHAR file_extsW[] = {'F','i','l','e','E','x','t','s','\\'};
4431
4432 WCHAR *path;
4433 const WCHAR *key, *subkey;
4434 int size_key, size_subkey, size_user;
4435 HKEY hkey = NULL;
4436
4437 TRACE("(0x%08x, %s, %d)\n", flags, debugstr_w(sub_key), create);
4438
4439 /* For compatibility with Vista+ */
4440 if(flags == 0x1ffff)
4441 flags = 0x21;
4442
4443 switch(flags&0xff0) {
4444 case SHKEY_Key_Explorer:
4445 key = explorerW;
4446 size_key = sizeof(explorerW);
4447 break;
4448 case SHKEY_Key_Shell:
4449 key = shellW;
4450 size_key = sizeof(shellW);
4451 break;
4452 case SHKEY_Key_ShellNoRoam:
4453 key = shell_no_roamW;
4454 size_key = sizeof(shell_no_roamW);
4455 break;
4456 case SHKEY_Key_Classes:
4457 key = classesW;
4458 size_key = sizeof(classesW);
4459 break;
4460 default:
4461 FIXME("unsupported flags (0x%08x)\n", flags);
4462 return NULL;
4463 }
4464
4465 switch(flags&0xff000) {
4466 case SHKEY_Subkey_Default:
4467 subkey = NULL;
4468 size_subkey = 0;
4469 break;
4470 case SHKEY_Subkey_ResourceName:
4471 subkey = localized_resource_nameW;
4472 size_subkey = sizeof(localized_resource_nameW);
4473 break;
4474 case SHKEY_Subkey_Handlers:
4475 subkey = handlersW;
4476 size_subkey = sizeof(handlersW);
4477 break;
4478 case SHKEY_Subkey_Associations:
4479 subkey = associationsW;
4480 size_subkey = sizeof(associationsW);
4481 break;
4482 case SHKEY_Subkey_Volatile:
4483 subkey = volatileW;
4484 size_subkey = sizeof(volatileW);
4485 break;
4486 case SHKEY_Subkey_MUICache:
4487 subkey = mui_cacheW;
4488 size_subkey = sizeof(mui_cacheW);
4489 break;
4490 case SHKEY_Subkey_FileExts:
4491 subkey = file_extsW;
4492 size_subkey = sizeof(file_extsW);
4493 break;
4494 default:
4495 FIXME("unsupported flags (0x%08x)\n", flags);
4496 return NULL;
4497 }
4498
4499 if(sub_key)
4500 size_user = lstrlenW(sub_key)*sizeof(WCHAR);
4501 else
4502 size_user = 0;
4503
4504 path = HeapAlloc(GetProcessHeap(), 0, size_key+size_subkey+size_user+sizeof(WCHAR));
4505 if(!path) {
4506 ERR("Out of memory\n");
4507 return NULL;
4508 }
4509
4510 memcpy(path, key, size_key);
4511 if(subkey)
4512 memcpy(path+size_key/sizeof(WCHAR), subkey, size_subkey);
4513 if(sub_key)
4514 memcpy(path+(size_key+size_subkey)/sizeof(WCHAR), sub_key, size_user);
4515 path[(size_key+size_subkey+size_user)/sizeof(WCHAR)] = '\0';
4516
4517 if(create)
4518 RegCreateKeyExW((flags&0xf)==SHKEY_Root_HKLM?HKEY_LOCAL_MACHINE:HKEY_CURRENT_USER,
4519 path, 0, NULL, 0, MAXIMUM_ALLOWED, NULL, &hkey, NULL);
4520 else
4521 RegOpenKeyExW((flags&0xf)==SHKEY_Root_HKLM?HKEY_LOCAL_MACHINE:HKEY_CURRENT_USER,
4522 path, 0, MAXIMUM_ALLOWED, &hkey);
4523
4524 HeapFree(GetProcessHeap(), 0, path);
4525 return hkey;
4526 }
4527
4528 /***********************************************************************
4529 * SHQueueUserWorkItem (SHLWAPI.@)
4530 */
4531 BOOL WINAPI SHQueueUserWorkItem(LPTHREAD_START_ROUTINE pfnCallback,
4532 LPVOID pContext, LONG lPriority, DWORD_PTR dwTag,
4533 DWORD_PTR *pdwId, LPCSTR pszModule, DWORD dwFlags)
4534 {
4535 TRACE("(%p, %p, %d, %lx, %p, %s, %08x)\n", pfnCallback, pContext,
4536 lPriority, dwTag, pdwId, debugstr_a(pszModule), dwFlags);
4537
4538 if(lPriority || dwTag || pdwId || pszModule || dwFlags)
4539 FIXME("Unsupported arguments\n");
4540
4541 return QueueUserWorkItem(pfnCallback, pContext, 0);
4542 }
4543
4544 /***********************************************************************
4545 * SHSetTimerQueueTimer (SHLWAPI.263)
4546 */
4547 HANDLE WINAPI SHSetTimerQueueTimer(HANDLE hQueue,
4548 WAITORTIMERCALLBACK pfnCallback, LPVOID pContext, DWORD dwDueTime,
4549 DWORD dwPeriod, LPCSTR lpszLibrary, DWORD dwFlags)
4550 {
4551 HANDLE hNewTimer;
4552
4553 /* SHSetTimerQueueTimer flags -> CreateTimerQueueTimer flags */
4554 if (dwFlags & TPS_LONGEXECTIME) {
4555 dwFlags &= ~TPS_LONGEXECTIME;
4556 dwFlags |= WT_EXECUTELONGFUNCTION;
4557 }
4558 if (dwFlags & TPS_EXECUTEIO) {
4559 dwFlags &= ~TPS_EXECUTEIO;
4560 dwFlags |= WT_EXECUTEINIOTHREAD;
4561 }
4562
4563 if (!CreateTimerQueueTimer(&hNewTimer, hQueue, pfnCallback, pContext,
4564 dwDueTime, dwPeriod, dwFlags))
4565 return NULL;
4566
4567 return hNewTimer;
4568 }
4569
4570 /***********************************************************************
4571 * IUnknown_OnFocusChangeIS (SHLWAPI.@)
4572 */
4573 HRESULT WINAPI IUnknown_OnFocusChangeIS(LPUNKNOWN lpUnknown, LPUNKNOWN pFocusObject, BOOL bFocus)
4574 {
4575 IInputObjectSite *pIOS = NULL;
4576 HRESULT hRet = E_INVALIDARG;
4577
4578 TRACE("(%p, %p, %s)\n", lpUnknown, pFocusObject, bFocus ? "TRUE" : "FALSE");
4579
4580 if (lpUnknown)
4581 {
4582 hRet = IUnknown_QueryInterface(lpUnknown, &IID_IInputObjectSite,
4583 (void **)&pIOS);
4584 if (SUCCEEDED(hRet) && pIOS)
4585 {
4586 hRet = IInputObjectSite_OnFocusChangeIS(pIOS, pFocusObject, bFocus);
4587 IInputObjectSite_Release(pIOS);
4588 }
4589 }
4590 return hRet;
4591 }
4592
4593 /***********************************************************************
4594 * SKAllocValueW (SHLWAPI.519)
4595 */
4596 HRESULT WINAPI SKAllocValueW(DWORD flags, LPCWSTR subkey, LPCWSTR value, DWORD *type,
4597 LPVOID *data, DWORD *count)
4598 {
4599 DWORD ret, size;
4600 HKEY hkey;
4601
4602 TRACE("(0x%x, %s, %s, %p, %p, %p)\n", flags, debugstr_w(subkey),
4603 debugstr_w(value), type, data, count);
4604
4605 hkey = SHGetShellKey(flags, subkey, FALSE);
4606 if (!hkey)
4607 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
4608
4609 ret = SHQueryValueExW(hkey, value, NULL, type, NULL, &size);
4610 if (ret) {
4611 RegCloseKey(hkey);
4612 return HRESULT_FROM_WIN32(ret);
4613 }
4614
4615 size += 2;
4616 *data = LocalAlloc(0, size);
4617 if (!*data) {
4618 RegCloseKey(hkey);
4619 return E_OUTOFMEMORY;
4620 }
4621
4622 ret = SHQueryValueExW(hkey, value, NULL, type, *data, &size);
4623 if (count)
4624 *count = size;
4625
4626 RegCloseKey(hkey);
4627 return HRESULT_FROM_WIN32(ret);
4628 }
4629
4630 /***********************************************************************
4631 * SKDeleteValueW (SHLWAPI.518)
4632 */
4633 HRESULT WINAPI SKDeleteValueW(DWORD flags, LPCWSTR subkey, LPCWSTR value)
4634 {
4635 DWORD ret;
4636 HKEY hkey;
4637
4638 TRACE("(0x%x, %s %s)\n", flags, debugstr_w(subkey), debugstr_w(value));
4639
4640 hkey = SHGetShellKey(flags, subkey, FALSE);
4641 if (!hkey)
4642 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
4643
4644 ret = RegDeleteValueW(hkey, value);
4645
4646 RegCloseKey(hkey);
4647 return HRESULT_FROM_WIN32(ret);
4648 }
4649
4650 /***********************************************************************
4651 * SKGetValueW (SHLWAPI.516)
4652 */
4653 HRESULT WINAPI SKGetValueW(DWORD flags, LPCWSTR subkey, LPCWSTR value, DWORD *type,
4654 void *data, DWORD *count)
4655 {
4656 DWORD ret;
4657 HKEY hkey;
4658
4659 TRACE("(0x%x, %s, %s, %p, %p, %p)\n", flags, debugstr_w(subkey),
4660 debugstr_w(value), type, data, count);
4661
4662 hkey = SHGetShellKey(flags, subkey, FALSE);
4663 if (!hkey)
4664 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
4665
4666 ret = SHQueryValueExW(hkey, value, NULL, type, data, count);
4667
4668 RegCloseKey(hkey);
4669 return HRESULT_FROM_WIN32(ret);
4670 }
4671
4672 /***********************************************************************
4673 * SKSetValueW (SHLWAPI.516)
4674 */
4675 HRESULT WINAPI SKSetValueW(DWORD flags, LPCWSTR subkey, LPCWSTR value,
4676 DWORD type, void *data, DWORD count)
4677 {
4678 DWORD ret;
4679 HKEY hkey;
4680
4681 TRACE("(0x%x, %s, %s, %x, %p, %d)\n", flags, debugstr_w(subkey),
4682 debugstr_w(value), type, data, count);
4683
4684 hkey = SHGetShellKey(flags, subkey, TRUE);
4685 if (!hkey)
4686 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
4687
4688 ret = RegSetValueExW(hkey, value, 0, type, data, count);
4689
4690 RegCloseKey(hkey);
4691 return HRESULT_FROM_WIN32(ret);
4692 }
4693
4694 typedef HRESULT (WINAPI *DllGetVersion_func)(DLLVERSIONINFO *);
4695
4696 /***********************************************************************
4697 * GetUIVersion (SHLWAPI.452)
4698 */
4699 DWORD WINAPI GetUIVersion(void)
4700 {
4701 static DWORD version;
4702
4703 if (!version)
4704 {
4705 DllGetVersion_func pDllGetVersion;
4706 HMODULE dll = LoadLibraryA("shell32.dll");
4707 if (!dll) return 0;
4708
4709 pDllGetVersion = (DllGetVersion_func)GetProcAddress(dll, "DllGetVersion");
4710 if (pDllGetVersion)
4711 {
4712 DLLVERSIONINFO dvi;
4713 dvi.cbSize = sizeof(DLLVERSIONINFO);
4714 if (pDllGetVersion(&dvi) == S_OK) version = dvi.dwMajorVersion;
4715 }
4716 FreeLibrary( dll );
4717 if (!version) version = 3; /* old shell dlls don't have DllGetVersion */
4718 }
4719 return version;
4720 }
4721
4722 /***********************************************************************
4723 * ShellMessageBoxWrapW [SHLWAPI.388]
4724 *
4725 * See shell32.ShellMessageBoxW
4726 *
4727 * NOTE:
4728 * shlwapi.ShellMessageBoxWrapW is a duplicate of shell32.ShellMessageBoxW
4729 * because we can't forward to it in the .spec file since it's exported by
4730 * ordinal. If you change the implementation here please update the code in
4731 * shell32 as well.
4732 */
4733 INT WINAPIV ShellMessageBoxWrapW(HINSTANCE hInstance, HWND hWnd, LPCWSTR lpText,
4734 LPCWSTR lpCaption, UINT uType, ...)
4735 {
4736 WCHAR *szText = NULL, szTitle[100];
4737 LPCWSTR pszText, pszTitle = szTitle;
4738 LPWSTR pszTemp;
4739 __ms_va_list args;
4740 int ret;
4741
4742 __ms_va_start(args, uType);
4743
4744 TRACE("(%p,%p,%p,%p,%08x)\n", hInstance, hWnd, lpText, lpCaption, uType);
4745
4746 if (IS_INTRESOURCE(lpCaption))
4747 LoadStringW(hInstance, LOWORD(lpCaption), szTitle, sizeof(szTitle)/sizeof(szTitle[0]));
4748 else
4749 pszTitle = lpCaption;
4750
4751 if (IS_INTRESOURCE(lpText))
4752 {
4753 const WCHAR *ptr;
4754 UINT len = LoadStringW(hInstance, LOWORD(lpText), (LPWSTR)&ptr, 0);
4755
4756 if (len)
4757 {
4758 szText = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
4759 if (szText) LoadStringW(hInstance, LOWORD(lpText), szText, len + 1);
4760 }
4761 pszText = szText;
4762 if (!pszText) {
4763 WARN("Failed to load id %d\n", LOWORD(lpText));
4764 __ms_va_end(args);
4765 return 0;
4766 }
4767 }
4768 else
4769 pszText = lpText;
4770
4771 FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
4772 pszText, 0, 0, (LPWSTR)&pszTemp, 0, &args);
4773
4774 __ms_va_end(args);
4775
4776 ret = MessageBoxW(hWnd, pszTemp, pszTitle, uType);
4777
4778 HeapFree(GetProcessHeap(), 0, szText);
4779 LocalFree(pszTemp);
4780 return ret;
4781 }
4782
4783 /***********************************************************************
4784 * ZoneComputePaneSize [SHLWAPI.382]
4785 */
4786 UINT WINAPI ZoneComputePaneSize(HWND hwnd)
4787 {
4788 FIXME("\n");
4789 return 0x95;
4790 }
4791
4792 /***********************************************************************
4793 * SHChangeNotifyWrap [SHLWAPI.394]
4794 */
4795 void WINAPI SHChangeNotifyWrap(LONG wEventId, UINT uFlags, LPCVOID dwItem1, LPCVOID dwItem2)
4796 {
4797 SHChangeNotify(wEventId, uFlags, dwItem1, dwItem2);
4798 }
4799
4800 typedef struct SHELL_USER_SID { /* according to MSDN this should be in shlobj.h... */
4801 SID_IDENTIFIER_AUTHORITY sidAuthority;
4802 DWORD dwUserGroupID;
4803 DWORD dwUserID;
4804 } SHELL_USER_SID, *PSHELL_USER_SID;
4805
4806 typedef struct SHELL_USER_PERMISSION { /* ...and this should be in shlwapi.h */
4807 SHELL_USER_SID susID;
4808 DWORD dwAccessType;
4809 BOOL fInherit;
4810 DWORD dwAccessMask;
4811 DWORD dwInheritMask;
4812 DWORD dwInheritAccessMask;
4813 } SHELL_USER_PERMISSION, *PSHELL_USER_PERMISSION;
4814
4815 /***********************************************************************
4816 * GetShellSecurityDescriptor [SHLWAPI.475]
4817 *
4818 * prepares SECURITY_DESCRIPTOR from a set of ACEs
4819 *
4820 * PARAMS
4821 * apUserPerm [I] array of pointers to SHELL_USER_PERMISSION structures,
4822 * each of which describes permissions to apply
4823 * cUserPerm [I] number of entries in apUserPerm array
4824 *
4825 * RETURNS
4826 * success: pointer to SECURITY_DESCRIPTOR
4827 * failure: NULL
4828 *
4829 * NOTES
4830 * Call should free returned descriptor with LocalFree
4831 */
4832 PSECURITY_DESCRIPTOR WINAPI GetShellSecurityDescriptor(PSHELL_USER_PERMISSION *apUserPerm, int cUserPerm)
4833 {
4834 PSID *sidlist;
4835 PSID cur_user = NULL;
4836 BYTE tuUser[2000];
4837 DWORD acl_size;
4838 int sid_count, i;
4839 PSECURITY_DESCRIPTOR psd = NULL;
4840
4841 TRACE("%p %d\n", apUserPerm, cUserPerm);
4842
4843 if (apUserPerm == NULL || cUserPerm <= 0)
4844 return NULL;
4845
4846 sidlist = HeapAlloc(GetProcessHeap(), 0, cUserPerm * sizeof(PSID));
4847 if (!sidlist)
4848 return NULL;
4849
4850 acl_size = sizeof(ACL);
4851
4852 for(sid_count = 0; sid_count < cUserPerm; sid_count++)
4853 {
4854 static SHELL_USER_SID null_sid = {{SECURITY_NULL_SID_AUTHORITY}, 0, 0};
4855 PSHELL_USER_PERMISSION perm = apUserPerm[sid_count];
4856 PSHELL_USER_SID sid = &perm->susID;
4857 PSID pSid;
4858 BOOL ret = TRUE;
4859
4860 if (!memcmp((void*)sid, (void*)&null_sid, sizeof(SHELL_USER_SID)))
4861 { /* current user's SID */
4862 if (!cur_user)
4863 {
4864 HANDLE Token;
4865 DWORD bufsize = sizeof(tuUser);
4866
4867 ret = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &Token);
4868 if (ret)
4869 {
4870 ret = GetTokenInformation(Token, TokenUser, (void*)tuUser, bufsize, &bufsize );
4871 if (ret)
4872 cur_user = ((PTOKEN_USER)tuUser)->User.Sid;
4873 CloseHandle(Token);
4874 }
4875 }
4876 pSid = cur_user;
4877 } else if (sid->dwUserID==0) /* one sub-authority */
4878 ret = AllocateAndInitializeSid(&sid->sidAuthority, 1, sid->dwUserGroupID, 0,
4879 0, 0, 0, 0, 0, 0, &pSid);
4880 else
4881 ret = AllocateAndInitializeSid(&sid->sidAuthority, 2, sid->dwUserGroupID, sid->dwUserID,
4882 0, 0, 0, 0, 0, 0, &pSid);
4883 if (!ret)
4884 goto free_sids;
4885
4886 sidlist[sid_count] = pSid;
4887 /* increment acl_size (1 ACE for non-inheritable and 2 ACEs for inheritable records */
4888 acl_size += (sizeof(ACCESS_ALLOWED_ACE)-sizeof(DWORD) + GetLengthSid(pSid)) * (perm->fInherit ? 2 : 1);
4889 }
4890
4891 psd = LocalAlloc(0, sizeof(SECURITY_DESCRIPTOR) + acl_size);
4892
4893 if (psd != NULL)
4894 {
4895 PACL pAcl = (PACL)(((BYTE*)psd)+sizeof(SECURITY_DESCRIPTOR));
4896
4897 if (!InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION))
4898 goto error;
4899
4900 if (!InitializeAcl(pAcl, acl_size, ACL_REVISION))
4901 goto error;
4902
4903 for(i = 0; i < sid_count; i++)
4904 {
4905 PSHELL_USER_PERMISSION sup = apUserPerm[i];
4906 PSID sid = sidlist[i];
4907
4908 switch(sup->dwAccessType)
4909 {
4910 case ACCESS_ALLOWED_ACE_TYPE:
4911 if (!AddAccessAllowedAce(pAcl, ACL_REVISION, sup->dwAccessMask, sid))
4912 goto error;
4913 if (sup->fInherit && !AddAccessAllowedAceEx(pAcl, ACL_REVISION,
4914 (BYTE)sup->dwInheritMask, sup->dwInheritAccessMask, sid))
4915 goto error;
4916 break;
4917 case ACCESS_DENIED_ACE_TYPE:
4918 if (!AddAccessDeniedAce(pAcl, ACL_REVISION, sup->dwAccessMask, sid))
4919 goto error;
4920 if (sup->fInherit && !AddAccessDeniedAceEx(pAcl, ACL_REVISION,
4921 (BYTE)sup->dwInheritMask, sup->dwInheritAccessMask, sid))
4922 goto error;
4923 break;
4924 default:
4925 goto error;
4926 }
4927 }
4928
4929 if (!SetSecurityDescriptorDacl(psd, TRUE, pAcl, FALSE))
4930 goto error;
4931 }
4932 goto free_sids;
4933
4934 error:
4935 LocalFree(psd);
4936 psd = NULL;
4937 free_sids:
4938 for(i = 0; i < sid_count; i++)
4939 {
4940 if (!cur_user || sidlist[i] != cur_user)
4941 FreeSid(sidlist[i]);
4942 }
4943 HeapFree(GetProcessHeap(), 0, sidlist);
4944
4945 return psd;
4946 }
4947
4948 /***********************************************************************
4949 * SHCreatePropertyBagOnRegKey [SHLWAPI.471]
4950 *
4951 * Creates a property bag from a registry key
4952 *
4953 * PARAMS
4954 * hKey [I] Handle to the desired registry key
4955 * subkey [I] Name of desired subkey, or NULL to open hKey directly
4956 * grfMode [I] Optional flags
4957 * riid [I] IID of requested property bag interface
4958 * ppv [O] Address to receive pointer to the new interface
4959 *
4960 * RETURNS
4961 * success: 0
4962 * failure: error code
4963 *
4964 */
4965 HRESULT WINAPI SHCreatePropertyBagOnRegKey (HKEY hKey, LPCWSTR subkey,
4966 DWORD grfMode, REFIID riid, void **ppv)
4967 {
4968 FIXME("%p %s %d %s %p STUB\n", hKey, debugstr_w(subkey), grfMode,
4969 debugstr_guid(riid), ppv);
4970
4971 return E_NOTIMPL;
4972 }
4973
4974 /***********************************************************************
4975 * SHGetViewStatePropertyBag [SHLWAPI.515]
4976 *
4977 * Retrieves a property bag in which the view state information of a folder
4978 * can be stored.
4979 *
4980 * PARAMS
4981 * pidl [I] PIDL of the folder requested
4982 * bag_name [I] Name of the property bag requested
4983 * flags [I] Optional flags
4984 * riid [I] IID of requested property bag interface
4985 * ppv [O] Address to receive pointer to the new interface
4986 *
4987 * RETURNS
4988 * success: S_OK
4989 * failure: error code
4990 *
4991 */
4992 HRESULT WINAPI SHGetViewStatePropertyBag(LPCITEMIDLIST pidl, LPWSTR bag_name,
4993 DWORD flags, REFIID riid, void **ppv)
4994 {
4995 FIXME("%p %s %d %s %p STUB\n", pidl, debugstr_w(bag_name), flags,
4996 debugstr_guid(riid), ppv);
4997
4998 return E_NOTIMPL;
4999 }
5000
5001 /***********************************************************************
5002 * SHFormatDateTimeW [SHLWAPI.354]
5003 *
5004 * Produces a string representation of a time.
5005 *
5006 * PARAMS
5007 * fileTime [I] Pointer to FILETIME structure specifying the time
5008 * flags [I] Flags specifying the desired output
5009 * buf [O] Pointer to buffer for output
5010 * size [I] Number of characters that can be contained in buffer
5011 *
5012 * RETURNS
5013 * success: number of characters written to the buffer
5014 * failure: 0
5015 *
5016 */
5017 INT WINAPI SHFormatDateTimeW(const FILETIME UNALIGNED *fileTime, DWORD *flags,
5018 LPWSTR buf, UINT size)
5019 {
5020 #define SHFORMATDT_UNSUPPORTED_FLAGS (FDTF_RELATIVE | FDTF_LTRDATE | FDTF_RTLDATE | FDTF_NOAUTOREADINGORDER)
5021 DWORD fmt_flags = flags ? *flags : FDTF_DEFAULT;
5022 SYSTEMTIME st;
5023 FILETIME ft;
5024 INT ret = 0;
5025
5026 TRACE("%p %p %p %u\n", fileTime, flags, buf, size);
5027
5028 if (!buf || !size)
5029 return 0;
5030
5031 if (fmt_flags & SHFORMATDT_UNSUPPORTED_FLAGS)
5032 FIXME("ignoring some flags - 0x%08x\n", fmt_flags & SHFORMATDT_UNSUPPORTED_FLAGS);
5033
5034 FileTimeToLocalFileTime(fileTime, &ft);
5035 FileTimeToSystemTime(&ft, &st);
5036
5037 /* first of all date */
5038 if (fmt_flags & (FDTF_LONGDATE | FDTF_SHORTDATE))
5039 {
5040 static const WCHAR sep1[] = {',',' ',0};
5041 static const WCHAR sep2[] = {' ',0};
5042
5043 DWORD date = fmt_flags & FDTF_LONGDATE ? DATE_LONGDATE : DATE_SHORTDATE;
5044 ret = GetDateFormatW(LOCALE_USER_DEFAULT, date, &st, NULL, buf, size);
5045 if (ret >= size) return ret;
5046
5047 /* add separator */
5048 if (ret < size && (fmt_flags & (FDTF_LONGTIME | FDTF_SHORTTIME)))
5049 {
5050 if ((fmt_flags & FDTF_LONGDATE) && (ret < size + 2))
5051 {
5052 if (ret < size + 2)
5053 {
5054 lstrcatW(&buf[ret-1], sep1);
5055 ret += 2;
5056 }
5057 }
5058 else
5059 {
5060 lstrcatW(&buf[ret-1], sep2);
5061 ret++;
5062 }
5063 }
5064 }
5065 /* time part */
5066 if (fmt_flags & (FDTF_LONGTIME | FDTF_SHORTTIME))
5067 {
5068 DWORD time = fmt_flags & FDTF_LONGTIME ? 0 : TIME_NOSECONDS;
5069
5070 if (ret) ret--;
5071 ret += GetTimeFormatW(LOCALE_USER_DEFAULT, time, &st, NULL, &buf[ret], size - ret);
5072 }
5073
5074 return ret;
5075
5076 #undef SHFORMATDT_UNSUPPORTED_FLAGS
5077 }
5078
5079 /***********************************************************************
5080 * SHFormatDateTimeA [SHLWAPI.353]
5081 *
5082 * See SHFormatDateTimeW.
5083 *
5084 */
5085 INT WINAPI SHFormatDateTimeA(const FILETIME UNALIGNED *fileTime, DWORD *flags,
5086 LPSTR buf, UINT size)
5087 {
5088 WCHAR *bufW;
5089 INT retval;
5090
5091 if (!buf || !size)
5092 return 0;
5093
5094 bufW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * size);
5095 retval = SHFormatDateTimeW(fileTime, flags, bufW, size);
5096
5097 if (retval != 0)
5098 WideCharToMultiByte(CP_ACP, 0, bufW, -1, buf, size, NULL, NULL);
5099
5100 HeapFree(GetProcessHeap(), 0, bufW);
5101 return retval;
5102 }
5103
5104 /***********************************************************************
5105 * ZoneCheckUrlExW [SHLWAPI.231]
5106 *
5107 * Checks the details of the security zone for the supplied site. (?)
5108 *
5109 * PARAMS
5110 *
5111 * szURL [I] Pointer to the URL to check
5112 *
5113 * Other parameters currently unknown.
5114 *
5115 * RETURNS
5116 * unknown
5117 */
5118
5119 INT WINAPI ZoneCheckUrlExW(LPWSTR szURL, PVOID pUnknown, DWORD dwUnknown2,
5120 DWORD dwUnknown3, DWORD dwUnknown4, DWORD dwUnknown5, DWORD dwUnknown6,
5121 DWORD dwUnknown7)
5122 {
5123 FIXME("(%s,%p,%x,%x,%x,%x,%x,%x) STUB\n", debugstr_w(szURL), pUnknown, dwUnknown2,
5124 dwUnknown3, dwUnknown4, dwUnknown5, dwUnknown6, dwUnknown7);
5125
5126 return 0;
5127 }
5128
5129 /***********************************************************************
5130 * SHVerbExistsNA [SHLWAPI.196]
5131 *
5132 *
5133 * PARAMS
5134 *
5135 * verb [I] a string, often appears to be an extension.
5136 *
5137 * Other parameters currently unknown.
5138 *
5139 * RETURNS
5140 * unknown
5141 */
5142 INT WINAPI SHVerbExistsNA(LPSTR verb, PVOID pUnknown, PVOID pUnknown2, DWORD dwUnknown3)
5143 {
5144 FIXME("(%s, %p, %p, %i) STUB\n",verb, pUnknown, pUnknown2, dwUnknown3);
5145 return 0;
5146 }
5147
5148 /*************************************************************************
5149 * @ [SHLWAPI.538]
5150 *
5151 * Undocumented: Implementation guessed at via Name and behavior
5152 *
5153 * PARAMS
5154 * lpUnknown [I] Object to get an IServiceProvider interface from
5155 * riid [I] Function requested for QueryService call
5156 * lppOut [O] Destination for the service interface pointer
5157 *
5158 * RETURNS
5159 * Success: S_OK. lppOut contains an object providing the requested service
5160 * Failure: An HRESULT error code
5161 *
5162 * NOTES
5163 * lpUnknown is expected to support the IServiceProvider interface.
5164 */
5165 HRESULT WINAPI IUnknown_QueryServiceForWebBrowserApp(IUnknown* lpUnknown,
5166 REFGUID riid, LPVOID *lppOut)
5167 {
5168 FIXME("%p %s %p semi-STUB\n", lpUnknown, debugstr_guid(riid), lppOut);
5169 return IUnknown_QueryService(lpUnknown,&IID_IWebBrowserApp,riid,lppOut);
5170 }
5171
5172 /**************************************************************************
5173 * SHPropertyBag_ReadLONG (SHLWAPI.496)
5174 *
5175 * This function asks a property bag to read a named property as a LONG.
5176 *
5177 * PARAMS
5178 * ppb: a IPropertyBag interface
5179 * pszPropName: Unicode string that names the property
5180 * pValue: address to receive the property value as a 32-bit signed integer
5181 *
5182 * RETURNS
5183 * 0 for Success
5184 */
5185 BOOL WINAPI SHPropertyBag_ReadLONG(IPropertyBag *ppb, LPCWSTR pszPropName, LPLONG pValue)
5186 {
5187 VARIANT var;
5188 HRESULT hr;
5189 TRACE("%p %s %p\n", ppb,debugstr_w(pszPropName),pValue);
5190 if (!pszPropName || !ppb || !pValue)
5191 return E_INVALIDARG;
5192 V_VT(&var) = VT_I4;
5193 hr = IPropertyBag_Read(ppb, pszPropName, &var, NULL);
5194 if (SUCCEEDED(hr))
5195 {
5196 if (V_VT(&var) == VT_I4)
5197 *pValue = V_I4(&var);
5198 else
5199 hr = DISP_E_BADVARTYPE;
5200 }
5201 return hr;
5202 }
5203
5204 /* return flags for SHGetObjectCompatFlags, names derived from registry value names */
5205 #define OBJCOMPAT_OTNEEDSSFCACHE 0x00000001
5206 #define OBJCOMPAT_NO_WEBVIEW 0x00000002
5207 #define OBJCOMPAT_UNBINDABLE 0x00000004
5208 #define OBJCOMPAT_PINDLL 0x00000008
5209 #define OBJCOMPAT_NEEDSFILESYSANCESTOR 0x00000010
5210 #define OBJCOMPAT_NOTAFILESYSTEM 0x00000020
5211 #define OBJCOMPAT_CTXMENU_NOVERBS 0x00000040
5212 #define OBJCOMPAT_CTXMENU_LIMITEDQI 0x00000080
5213 #define OBJCOMPAT_COCREATESHELLFOLDERONLY 0x00000100
5214 #define OBJCOMPAT_NEEDSSTORAGEANCESTOR 0x00000200
5215 #define OBJCOMPAT_NOLEGACYWEBVIEW 0x00000400
5216 #define OBJCOMPAT_CTXMENU_XPQCMFLAGS 0x00001000
5217 #define OBJCOMPAT_NOIPROPERTYSTORE 0x00002000
5218
5219 /* a search table for compatibility flags */
5220 struct objcompat_entry {
5221 const WCHAR name[30];
5222 DWORD value;
5223 };
5224
5225 /* expected to be sorted by name */
5226 static const struct objcompat_entry objcompat_table[] = {
5227 { {'C','O','C','R','E','A','T','E','S','H','E','L','L','F','O','L','D','E','R','O','N','L','Y',0},
5228 OBJCOMPAT_COCREATESHELLFOLDERONLY },
5229 { {'C','T','X','M','E','N','U','_','L','I','M','I','T','E','D','Q','I',0},
5230 OBJCOMPAT_CTXMENU_LIMITEDQI },
5231 { {'C','T','X','M','E','N','U','_','N','O','V','E','R','B','S',0},
5232 OBJCOMPAT_CTXMENU_LIMITEDQI },
5233 { {'C','T','X','M','E','N','U','_','X','P','Q','C','M','F','L','A','G','S',0},
5234 OBJCOMPAT_CTXMENU_XPQCMFLAGS },
5235 { {'N','E','E','D','S','F','I','L','E','S','Y','S','A','N','C','E','S','T','O','R',0},
5236 OBJCOMPAT_NEEDSFILESYSANCESTOR },
5237 { {'N','E','E','D','S','S','T','O','R','A','G','E','A','N','C','E','S','T','O','R',0},
5238 OBJCOMPAT_NEEDSSTORAGEANCESTOR },
5239 { {'N','O','I','P','R','O','P','E','R','T','Y','S','T','O','R','E',0},
5240 OBJCOMPAT_NOIPROPERTYSTORE },
5241 { {'N','O','L','E','G','A','C','Y','W','E','B','V','I','E','W',0},
5242 OBJCOMPAT_NOLEGACYWEBVIEW },
5243 { {'N','O','T','A','F','I','L','E','S','Y','S','T','E','M',0},
5244 OBJCOMPAT_NOTAFILESYSTEM },
5245 { {'N','O','_','W','E','B','V','I','E','W',0},
5246 OBJCOMPAT_NO_WEBVIEW },
5247 { {'O','T','N','E','E','D','S','S','F','C','A','C','H','E',0},
5248 OBJCOMPAT_OTNEEDSSFCACHE },
5249 { {'P','I','N','D','L','L',0},
5250 OBJCOMPAT_PINDLL },
5251 { {'U','N','B','I','N','D','A','B','L','E',0},
5252 OBJCOMPAT_UNBINDABLE }
5253 };
5254
5255 /**************************************************************************
5256 * SHGetObjectCompatFlags (SHLWAPI.476)
5257 *
5258 * Function returns an integer representation of compatibility flags stored
5259 * in registry for CLSID under ShellCompatibility subkey.
5260 *
5261 * PARAMS
5262 * pUnk: pointer to object IUnknown interface, idetifies CLSID
5263 * clsid: pointer to CLSID to retrieve data for
5264 *
5265 * RETURNS
5266 * 0 on failure, flags set on success
5267 */
5268 DWORD WINAPI SHGetObjectCompatFlags(IUnknown *pUnk, const CLSID *clsid)
5269 {
5270 static const WCHAR compatpathW[] =
5271 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
5272 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5273 'S','h','e','l','l','C','o','m','p','a','t','i','b','i','l','i','t','y','\\',
5274 'O','b','j','e','c','t','s','\\','%','s',0};
5275 WCHAR strW[sizeof(compatpathW)/sizeof(WCHAR) + 38 /* { CLSID } */];
5276 DWORD ret, length = sizeof(strW)/sizeof(WCHAR);
5277 OLECHAR *clsid_str;
5278 HKEY key;
5279 INT i;
5280
5281 TRACE("%p %s\n", pUnk, debugstr_guid(clsid));
5282
5283 if (!pUnk && !clsid) return 0;
5284
5285 if (pUnk && !clsid)
5286 {
5287 FIXME("iface not handled\n");
5288 return 0;
5289 }
5290
5291 StringFromCLSID(clsid, &clsid_str);
5292 sprintfW(strW, compatpathW, clsid_str);
5293 CoTaskMemFree(clsid_str);
5294
5295 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, strW, &key);
5296 if (ret != ERROR_SUCCESS) return 0;
5297
5298 /* now collect flag values */
5299 ret = 0;
5300 for (i = 0; RegEnumValueW(key, i, strW, &length, NULL, NULL, NULL, NULL) == ERROR_SUCCESS; i++)
5301 {
5302 INT left, right, res, x;
5303
5304 /* search in table */
5305 left = 0;
5306 right = sizeof(objcompat_table) / sizeof(struct objcompat_entry) - 1;
5307
5308 while (right >= left) {
5309 x = (left + right) / 2;
5310 res = strcmpW(strW, objcompat_table[x].name);
5311 if (res == 0)
5312 {
5313 ret |= objcompat_table[x].value;
5314 break;
5315 }
5316 else if (res < 0)
5317 right = x - 1;
5318 else
5319 left = x + 1;
5320 }
5321
5322 length = sizeof(strW)/sizeof(WCHAR);
5323 }
5324
5325 return ret;
5326 }