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