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