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