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