xref: /reactos/dll/win32/shell32/wine/shellord.c (revision 802dc971)
1 /*
2  * The parameters of many functions changes between different OS versions
3  * (NT uses Unicode strings, 95 uses ASCII strings)
4  *
5  * Copyright 1997 Marcus Meissner
6  *           1998 Jürgen Schmied
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 <wine/config.h>
24 
25 #define WIN32_NO_STATUS
26 #define _INC_WINDOWS
27 #define COBJMACROS
28 
29 #include <windef.h>
30 #include <winbase.h>
31 #include <wine/winternl.h>
32 #include <shlobj.h>
33 #include <undocshell.h>
34 #include <shlwapi.h>
35 #include <commdlg.h>
36 #include <commoncontrols.h>
37 #include "../shellrecyclebin/recyclebin.h"
38 
39 #include <wine/debug.h>
40 #include <wine/unicode.h>
41 
42 #include "pidl.h"
43 #include "shell32_main.h"
44 
45 WINE_DEFAULT_DEBUG_CHANNEL(shell);
46 WINE_DECLARE_DEBUG_CHANNEL(pidl);
47 
48 #ifdef __REACTOS__
49 #include <comctl32_undoc.h>
50 #include <shlwapi_undoc.h>
51 #else
52 /* FIXME: !!! move CREATEMRULIST and flags to header file !!! */
53 /*        !!! it is in both here and comctl32undoc.c      !!! */
54 typedef struct tagCREATEMRULIST
55 {
56     DWORD  cbSize;        /* size of struct */
57     DWORD  nMaxItems;     /* max no. of items in list */
58     DWORD  dwFlags;       /* see below */
59     HKEY   hKey;          /* root reg. key under which list is saved */
60     LPCSTR lpszSubKey;    /* reg. subkey */
61     int (CALLBACK *lpfnCompare)(LPCVOID, LPCVOID, DWORD); /* item compare proc */
62 } CREATEMRULISTA, *LPCREATEMRULISTA;
63 
64 /* dwFlags */
65 #define MRUF_STRING_LIST  0 /* list will contain strings */
66 #define MRUF_BINARY_LIST  1 /* list will contain binary data */
67 #define MRUF_DELAYED_SAVE 2 /* only save list order to reg. is FreeMRUList */
68 
69 extern HANDLE WINAPI CreateMRUListA(LPCREATEMRULISTA lpcml);
70 extern VOID WINAPI FreeMRUList(HANDLE hMRUList);
71 extern INT    WINAPI AddMRUData(HANDLE hList, LPCVOID lpData, DWORD cbData);
72 extern INT    WINAPI FindMRUData(HANDLE hList, LPCVOID lpData, DWORD cbData, LPINT lpRegNum);
73 extern INT    WINAPI EnumMRUListA(HANDLE hList, INT nItemPos, LPVOID lpBuffer, DWORD nBufferSize);
74 #endif
75 
76 /*************************************************************************
77  * ParseFieldA					[internal]
78  *
79  * copies a field from a ',' delimited string
80  *
81  * first field is nField = 1
82  */
ParseFieldA(LPCSTR src,DWORD nField,LPSTR dst,DWORD len)83 DWORD WINAPI ParseFieldA(
84 	LPCSTR src,
85 	DWORD nField,
86 	LPSTR dst,
87 	DWORD len)
88 {
89 	WARN("(%s,0x%08x,%p,%d) semi-stub.\n",debugstr_a(src),nField,dst,len);
90 
91 	if (!src || !src[0] || !dst || !len)
92 	  return 0;
93 
94 	/* skip n fields delimited by ',' */
95 	while (nField > 1)
96 	{
97 	  if (*src=='\0') return FALSE;
98 	  if (*(src++)==',') nField--;
99 	}
100 
101 	/* copy part till the next ',' to dst */
102 	while ( *src!='\0' && *src!=',' && (len--)>0 ) *(dst++)=*(src++);
103 
104 	/* finalize the string */
105 	*dst=0x0;
106 
107 	return TRUE;
108 }
109 
110 /*************************************************************************
111  * ParseFieldW			[internal]
112  *
113  * copies a field from a ',' delimited string
114  *
115  * first field is nField = 1
116  */
ParseFieldW(LPCWSTR src,DWORD nField,LPWSTR dst,DWORD len)117 DWORD WINAPI ParseFieldW(LPCWSTR src, DWORD nField, LPWSTR dst, DWORD len)
118 {
119 	WARN("(%s,0x%08x,%p,%d) semi-stub.\n", debugstr_w(src), nField, dst, len);
120 
121 	if (!src || !src[0] || !dst || !len)
122 	  return 0;
123 
124 	/* skip n fields delimited by ',' */
125 	while (nField > 1)
126 	{
127 	  if (*src == 0x0) return FALSE;
128 	  if (*src++ == ',') nField--;
129 	}
130 
131 	/* copy part till the next ',' to dst */
132 	while ( *src != 0x0 && *src != ',' && (len--)>0 ) *(dst++) = *(src++);
133 
134 	/* finalize the string */
135 	*dst = 0x0;
136 
137 	return TRUE;
138 }
139 
140 /*************************************************************************
141  * ParseField			[SHELL32.58]
142  */
ParseFieldAW(LPCVOID src,DWORD nField,LPVOID dst,DWORD len)143 DWORD WINAPI ParseFieldAW(LPCVOID src, DWORD nField, LPVOID dst, DWORD len)
144 {
145 	if (SHELL_OsIsUnicode())
146 	  return ParseFieldW(src, nField, dst, len);
147 	return ParseFieldA(src, nField, dst, len);
148 }
149 
150 /*************************************************************************
151  * GetFileNameFromBrowse            [SHELL32.63]
152  *
153  */
GetFileNameFromBrowse(HWND hwndOwner,LPWSTR lpstrFile,UINT nMaxFile,LPCWSTR lpstrInitialDir,LPCWSTR lpstrDefExt,LPCWSTR lpstrFilter,LPCWSTR lpstrTitle)154 BOOL WINAPI GetFileNameFromBrowse(
155     HWND hwndOwner,
156     LPWSTR lpstrFile,
157     UINT nMaxFile,
158     LPCWSTR lpstrInitialDir,
159     LPCWSTR lpstrDefExt,
160     LPCWSTR lpstrFilter,
161     LPCWSTR lpstrTitle)
162 {
163 typedef BOOL (WINAPI *GetOpenFileNameProc)(OPENFILENAMEW *ofn);
164     HMODULE hmodule;
165     GetOpenFileNameProc pGetOpenFileNameW;
166     OPENFILENAMEW ofn;
167     BOOL ret;
168 
169     TRACE("%p, %s, %d, %s, %s, %s, %s)\n",
170       hwndOwner, debugstr_w(lpstrFile), nMaxFile, lpstrInitialDir, lpstrDefExt,
171       lpstrFilter, lpstrTitle);
172 
173     hmodule = LoadLibraryW(L"comdlg32.dll");
174     if(!hmodule) return FALSE;
175     pGetOpenFileNameW = (GetOpenFileNameProc)GetProcAddress(hmodule, "GetOpenFileNameW");
176     if(!pGetOpenFileNameW)
177     {
178     FreeLibrary(hmodule);
179     return FALSE;
180     }
181 
182     memset(&ofn, 0, sizeof(ofn));
183 
184     ofn.lStructSize = sizeof(ofn);
185     ofn.hwndOwner = hwndOwner;
186     ofn.lpstrFilter = lpstrFilter;
187     ofn.lpstrFile = lpstrFile;
188     ofn.nMaxFile = nMaxFile;
189     ofn.lpstrInitialDir = lpstrInitialDir;
190     ofn.lpstrTitle = lpstrTitle;
191     ofn.lpstrDefExt = lpstrDefExt;
192     ofn.Flags = OFN_EXPLORER | OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;
193     ret = pGetOpenFileNameW(&ofn);
194 
195     FreeLibrary(hmodule);
196     return ret;
197 }
198 
199 #ifdef __REACTOS__
SHELL_GlobalCounterChanged(LONG * pCounter,SHELL_GCOUNTER_DECLAREPARAMETERS (handle,id))200 BOOL SHELL_GlobalCounterChanged(LONG *pCounter, SHELL_GCOUNTER_DECLAREPARAMETERS(handle, id))
201 {
202     LONG count = SHELL_GlobalCounterGet(SHELL_GCOUNTER_PARAMETERS(handle, id));
203     if (*pCounter == count)
204         return FALSE;
205     *pCounter = count;
206     return TRUE;
207 }
208 
209 EXTERN_C void SHELL32_GetDefaultShellState(LPSHELLSTATE pss);
210 EXTERN_C BOOL SHELL32_ReadRegShellState(PREGSHELLSTATE prss);
211 EXTERN_C LSTATUS SHELL32_WriteRegShellState(PREGSHELLSTATE prss);
212 SHELL_GCOUNTER_DEFINE_GUID(SHGCGUID_ShellState, 0x7cb834f0, 0x527b, 0x11d2, 0x9d, 0x1f, 0x00, 0x00, 0xf8, 0x05, 0xca, 0x57);
213 SHELL_GCOUNTER_DEFINE_HANDLE(g_hShellState);
214 #define SHELL_GCOUNTER_SHELLSTATE SHELL_GCOUNTER_PARAMETERS(g_hShellState, GLOBALCOUNTER_SHELLSETTINGSCHANGED)
215 static LONG g_ShellStateCounter = 0;
216 static UINT g_CachedSSF = 0;
217 static REGSHELLSTATE g_ShellState;
218 enum { ssf_autocheckselect = 0x00800000, ssf_iconsonly = 0x01000000,
219        ssf_showtypeoverlay = 0x02000000, ssf_showstatusbar = 0x04000000 };
220 #endif //__REACTOS__
221 
222 /*************************************************************************
223  * SHGetSetSettings				[SHELL32.68]
224  */
SHGetSetSettings(LPSHELLSTATE lpss,DWORD dwMask,BOOL bSet)225 VOID WINAPI SHGetSetSettings(LPSHELLSTATE lpss, DWORD dwMask, BOOL bSet)
226 {
227 #ifdef __REACTOS__
228     const DWORD inverted = SSF_SHOWEXTENSIONS;
229     LPSHELLSTATE gpss = &g_ShellState.ss;
230     HKEY hKeyAdv;
231 
232     if (!SHELL_GlobalCounterIsInitialized(g_hShellState))
233     {
234         SHELL_GlobalCounterCreate(&SHGCGUID_ShellState, g_hShellState);
235     }
236 
237     if (!lpss)
238     {
239         SHELL_GlobalCounterIncrement(SHELL_GCOUNTER_SHELLSTATE);
240         return;
241     }
242 
243     hKeyAdv = SHGetShellKey(SHKEY_Root_HKCU | SHKEY_Key_Explorer, L"Advanced", bSet);
244     if (!hKeyAdv && bSet)
245         return;
246 
247 #define SSF_STRUCTONLY (SSF_NOCONFIRMRECYCLE | SSF_DOUBLECLICKINWEBVIEW | SSF_DESKTOPHTML | \
248                         SSF_WIN95CLASSIC | SSF_SORTCOLUMNS | SSF_STARTPANELON)
249 #define SHGSS_GetSetStruct(getsetmacro) \
250     do { \
251         getsetmacro(fNoConfirmRecycle, SSF_NOCONFIRMRECYCLE); \
252         getsetmacro(fDoubleClickInWebView, SSF_DOUBLECLICKINWEBVIEW); \
253         getsetmacro(fDesktopHTML, SSF_DESKTOPHTML); \
254         getsetmacro(fWin95Classic, SSF_WIN95CLASSIC); \
255         getsetmacro(lParamSort, SSF_SORTCOLUMNS); \
256         getsetmacro(iSortDirection, SSF_SORTCOLUMNS); \
257         getsetmacro(fStartPanelOn, SSF_STARTPANELON); \
258     } while (0)
259 #define SHGSS_GetSetAdv(getsetmacro) \
260     do { \
261         getsetmacro(L"HideFileExt", fShowExtensions, SSF_SHOWEXTENSIONS); \
262         getsetmacro(L"ShowCompColor", fShowCompColor, SSF_SHOWCOMPCOLOR); \
263         getsetmacro(L"DontPrettyPath", fDontPrettyPath, SSF_DONTPRETTYPATH); \
264         getsetmacro(L"ShowAttribCol", fShowAttribCol, SSF_SHOWATTRIBCOL); \
265         getsetmacro(L"MapNetDrvBtn", fMapNetDrvBtn, SSF_MAPNETDRVBUTTON); \
266         getsetmacro(L"ShowInfoTip", fShowInfoTip, SSF_SHOWINFOTIP); \
267         getsetmacro(L"HideIcons", fHideIcons, SSF_HIDEICONS); \
268         getsetmacro(L"WebView", fWebView, SSF_WEBVIEW); \
269         getsetmacro(L"Filter", fFilter, SSF_FILTER); \
270         getsetmacro(L"ShowSuperHidden", fShowSuperHidden, SSF_SHOWSUPERHIDDEN); \
271         getsetmacro(L"NoNetCrawling", fNoNetCrawling, SSF_NONETCRAWLING); \
272         getsetmacro(L"SeparateProcess", fSepProcess, SSF_SEPPROCESS); \
273         getsetmacro(L"AutoCheckSelect", fAutoCheckSelect, ssf_autocheckselect); \
274         getsetmacro(L"IconsOnly", fIconsOnly, ssf_iconsonly); \
275         getsetmacro(L"ShowTypeOverlay", fShowTypeOverlay, ssf_showtypeoverlay); \
276         getsetmacro(L"ShowStatusBar", fShowStatusBar, ssf_showstatusbar); \
277     } while (0)
278 
279     if (bSet)
280     {
281         DWORD changed = 0;
282 
283 #define SHGSS_WriteAdv(name, value, SSF) \
284     do { \
285         DWORD val = (value), cb = sizeof(DWORD); \
286         if (SHSetValueW(hKeyAdv, NULL, (name), REG_DWORD, &val, cb) == ERROR_SUCCESS) \
287         { \
288             ++changed; \
289         } \
290     } while (0)
291 #define SHGSS_SetAdv(name, field, SSF) \
292     do { \
293         if ((dwMask & (SSF)) && gpss->field != lpss->field) \
294         { \
295             const DWORD bitval = (gpss->field = lpss->field); \
296             SHGSS_WriteAdv((name), ((SSF) & inverted) ? !bitval : !!bitval, (SSF)); \
297         } \
298     } while (0)
299 #define SHGSS_SetStruct(field, SSF) \
300     do { \
301         if ((dwMask & (SSF)) && gpss->field != lpss->field) \
302         { \
303             gpss->field = lpss->field; \
304             ++changed; \
305         } \
306     } while (0)
307 
308         if ((dwMask & SSF_SHOWALLOBJECTS) && gpss->fShowAllObjects != lpss->fShowAllObjects)
309         {
310             gpss->fShowAllObjects = lpss->fShowAllObjects;
311             SHGSS_WriteAdv(L"Hidden", lpss->fShowAllObjects ? 1 : 2, SSF_SHOWALLOBJECTS);
312         }
313         SHGSS_SetStruct(fShowSysFiles, SSF_SHOWSYSFILES);
314         SHGSS_GetSetAdv(SHGSS_SetAdv);
315         SHGSS_GetSetStruct(SHGSS_SetStruct);
316         if (changed)
317         {
318             if ((dwMask & SSF_SHOWSUPERHIDDEN) && (DLL_EXPORT_VERSION) < _WIN32_WINNT_VISTA)
319             {
320                 // This is probably a Windows bug but write this alternative name just in case someone reads it
321                 DWORD val = gpss->fShowSuperHidden != FALSE;
322                 SHSetValueW(hKeyAdv, NULL, L"SuperHidden", REG_DWORD, &val, sizeof(val));
323             }
324             SHELL32_WriteRegShellState(&g_ShellState); // Write the new SHELLSTATE
325             SHGetSetSettings(NULL, 0, TRUE); // Invalidate counter
326             SHSendMessageBroadcastW(WM_SETTINGCHANGE, 0, (LPARAM)L"ShellState"); // Notify everyone
327         }
328     }
329     else
330     {
331         DWORD read = 0, data, cb, dummy = 0;
332         if (SHELL_GlobalCounterChanged(&g_ShellStateCounter, SHELL_GCOUNTER_SHELLSTATE))
333             g_CachedSSF = 0;
334 
335 #define SHGSS_ReadAdv(name, SSF) ( \
336     (g_CachedSSF & (SSF)) != (SSF) && (cb = sizeof(DWORD)) != 0 && \
337     SHQueryValueEx(hKeyAdv, (name), NULL, NULL, &data, &cb) == ERROR_SUCCESS && \
338     cb == sizeof(DWORD) && (read |= (SSF)) != 0 )
339 #define SHGSS_GetFieldHelper(field, SSF, src, dst, cachevar) \
340     do { \
341         if (dwMask & (SSF)) \
342         { \
343             (dst)->field = (src)->field; \
344             cachevar |= (SSF); \
345         } \
346     } while (0)
347 #define SHGSS_CacheField(field, SSF) SHGSS_GetFieldHelper(field, (SSF), &rss.ss, gpss, read)
348 #define SHGSS_GetField(field, SSF) SHGSS_GetFieldHelper(field, (SSF), gpss, lpss, dummy)
349 #define SHGSS_GetAdv(name, field, SSF) \
350     do { \
351         if (SHGSS_ReadAdv((name), (SSF))) \
352             gpss->field = ((SSF) & inverted) ? data == FALSE : data != FALSE; \
353         SHGSS_GetFieldHelper(field, (SSF), gpss, lpss, read); \
354     } while (0)
355 
356         if (SHGSS_ReadAdv(L"Hidden", SSF_SHOWALLOBJECTS | SSF_SHOWSYSFILES))
357         {
358             gpss->fShowAllObjects = data == 1;
359             gpss->fShowSysFiles = data > 1;
360         }
361         SHGSS_GetField(fShowAllObjects, SSF_SHOWALLOBJECTS);
362         SHGSS_GetField(fShowSysFiles, SSF_SHOWSYSFILES);
363         SHGSS_GetSetAdv(SHGSS_GetAdv);
364         if (dwMask & ~(read | g_CachedSSF))
365         {
366             REGSHELLSTATE rss;
367             if (SHELL32_ReadRegShellState(&rss))
368             {
369                 SHGSS_GetSetStruct(SHGSS_CacheField); // Copy the requested items to gpss
370             }
371             else
372             {
373                 SHELL32_GetDefaultShellState(gpss);
374                 read = 0; // The advanced items we read are no longer valid in gpss
375                 g_CachedSSF = SSF_STRUCTONLY;
376             }
377         }
378         SHGSS_GetSetStruct(SHGSS_GetField); // Copy requested items from gpss to output
379         g_CachedSSF |= read;
380     }
381     if (hKeyAdv)
382         RegCloseKey(hKeyAdv);
383 #else
384   if(bSet)
385   {
386     FIXME("%p 0x%08x TRUE\n", lpss, dwMask);
387   }
388   else
389   {
390     SHGetSettings((LPSHELLFLAGSTATE)lpss,dwMask);
391   }
392 #endif //__REACTOS__
393 }
394 
395 /*************************************************************************
396  * SHGetSettings				[SHELL32.@]
397  *
398  * NOTES
399  *  the registry path are for win98 (tested)
400  *  and possibly are the same in nt40
401  *
402  */
SHGetSettings(LPSHELLFLAGSTATE lpsfs,DWORD dwMask)403 VOID WINAPI SHGetSettings(LPSHELLFLAGSTATE lpsfs, DWORD dwMask)
404 {
405 #ifdef __REACTOS__
406     SHELLSTATE ss;
407     SHGetSetSettings(&ss, dwMask & ~(SSF_SORTCOLUMNS | SSF_FILTER), FALSE);
408     *lpsfs = *(LPSHELLFLAGSTATE)&ss;
409     if (dwMask & SSF_HIDEICONS)
410         lpsfs->fHideIcons = ss.fHideIcons;
411     if (dwMask & ssf_autocheckselect)
412         lpsfs->fAutoCheckSelect = ss.fAutoCheckSelect;
413     if (dwMask & ssf_iconsonly)
414         lpsfs->fIconsOnly = ss.fIconsOnly;
415 #else
416 	HKEY	hKey;
417 	DWORD	dwData;
418 	DWORD	dwDataSize = sizeof (DWORD);
419 
420 	TRACE("(%p 0x%08x)\n",lpsfs,dwMask);
421 
422 	if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced",
423 				 0, 0, 0, KEY_ALL_ACCESS, 0, &hKey, 0))
424 	  return;
425 
426 	if ( (SSF_SHOWEXTENSIONS & dwMask) && !RegQueryValueExA(hKey, "HideFileExt", 0, 0, (LPBYTE)&dwData, &dwDataSize))
427 	  lpsfs->fShowExtensions  = ((dwData == 0) ?  0 : 1);
428 
429 	if ( (SSF_SHOWINFOTIP & dwMask) && !RegQueryValueExA(hKey, "ShowInfoTip", 0, 0, (LPBYTE)&dwData, &dwDataSize))
430 	  lpsfs->fShowInfoTip  = ((dwData == 0) ?  0 : 1);
431 
432 	if ( (SSF_DONTPRETTYPATH & dwMask) && !RegQueryValueExA(hKey, "DontPrettyPath", 0, 0, (LPBYTE)&dwData, &dwDataSize))
433 	  lpsfs->fDontPrettyPath  = ((dwData == 0) ?  0 : 1);
434 
435 	if ( (SSF_HIDEICONS & dwMask) && !RegQueryValueExA(hKey, "HideIcons", 0, 0, (LPBYTE)&dwData, &dwDataSize))
436 	  lpsfs->fHideIcons  = ((dwData == 0) ?  0 : 1);
437 
438 	if ( (SSF_MAPNETDRVBUTTON & dwMask) && !RegQueryValueExA(hKey, "MapNetDrvBtn", 0, 0, (LPBYTE)&dwData, &dwDataSize))
439 	  lpsfs->fMapNetDrvBtn  = ((dwData == 0) ?  0 : 1);
440 
441 	if ( (SSF_SHOWATTRIBCOL & dwMask) && !RegQueryValueExA(hKey, "ShowAttribCol", 0, 0, (LPBYTE)&dwData, &dwDataSize))
442 	  lpsfs->fShowAttribCol  = ((dwData == 0) ?  0 : 1);
443 
444 	if (((SSF_SHOWALLOBJECTS | SSF_SHOWSYSFILES) & dwMask) && !RegQueryValueExA(hKey, "Hidden", 0, 0, (LPBYTE)&dwData, &dwDataSize))
445 	{ if (dwData == 0)
446 	  { if (SSF_SHOWALLOBJECTS & dwMask)	lpsfs->fShowAllObjects  = 0;
447 	    if (SSF_SHOWSYSFILES & dwMask)	lpsfs->fShowSysFiles  = 0;
448 	  }
449 	  else if (dwData == 1)
450 	  { if (SSF_SHOWALLOBJECTS & dwMask)	lpsfs->fShowAllObjects  = 1;
451 	    if (SSF_SHOWSYSFILES & dwMask)	lpsfs->fShowSysFiles  = 0;
452 	  }
453 	  else if (dwData == 2)
454 	  { if (SSF_SHOWALLOBJECTS & dwMask)	lpsfs->fShowAllObjects  = 0;
455 	    if (SSF_SHOWSYSFILES & dwMask)	lpsfs->fShowSysFiles  = 1;
456 	  }
457 	}
458 	RegCloseKey (hKey);
459 #endif //__REACTOS__
460 	TRACE("-- 0x%04x\n", *(WORD*)lpsfs);
461 }
462 
463 /*************************************************************************
464  * SHShellFolderView_Message			[SHELL32.73]
465  *
466  * Send a message to an explorer cabinet window.
467  *
468  * PARAMS
469  *  hwndCabinet [I] The window containing the shellview to communicate with
470  *  dwMessage   [I] The SFVM message to send
471  *  dwParam     [I] Message parameter
472  *
473  * RETURNS
474  *  fixme.
475  *
476  * NOTES
477  *  Message SFVM_REARRANGE = 1
478  *
479  *    This message gets sent when a column gets clicked to instruct the
480  *    shell view to re-sort the item list. dwParam identifies the column
481  *    that was clicked.
482  */
SHShellFolderView_Message(HWND hwndCabinet,UINT uMessage,LPARAM lParam)483 LRESULT WINAPI SHShellFolderView_Message(
484 	HWND hwndCabinet,
485 	UINT uMessage,
486 	LPARAM lParam)
487 {
488 	FIXME("%p %08x %08lx stub\n",hwndCabinet, uMessage, lParam);
489 	return 0;
490 }
491 
492 /*************************************************************************
493  * RegisterShellHook				[SHELL32.181]
494  *
495  * Register a shell hook.
496  *
497  * PARAMS
498  *      hwnd   [I]  Window handle
499  *      dwType [I]  Type of hook.
500  *
501  * NOTES
502  *     Exported by ordinal
503  */
RegisterShellHook(HWND hWnd,DWORD dwType)504 BOOL WINAPI RegisterShellHook(
505 	HWND hWnd,
506 	DWORD dwType)
507 {
508     if (dwType == 3)
509     {
510         SetTaskmanWindow(hWnd);
511         return RegisterShellHookWindow(hWnd);
512     }
513     else if (dwType == 0)
514     {
515         return DeregisterShellHookWindow(hWnd);
516     }
517 
518     ERR("Unsupported argument");
519     return FALSE;
520 }
521 
522 /*************************************************************************
523  * ShellMessageBoxW				[SHELL32.182]
524  *
525  * See ShellMessageBoxA.
526  *
527  */
528 #ifdef __REACTOS__
529 /*
530  * shell32.ShellMessageBoxW directly redirects to shlwapi.ShellMessageBoxWrapW,
531  * while shell32.ShellMessageBoxA is a copy-paste ANSI adaptation of the
532  * shlwapi.ShellMessageBoxWrapW function.
533  *
534  * From Vista+ onwards, all the implementation of ShellMessageBoxA/W that
535  * were existing in shell32 has been completely moved to shlwapi, so that
536  * shell32.ShellMessageBoxA and shell32.ShellMessageBoxW are redirections
537  * to the corresponding shlwapi functions.
538  *
539  */
540 #else // !__REACTOS__
541 /*
542  * NOTE:
543  * shlwapi.ShellMessageBoxWrapW is a duplicate of shell32.ShellMessageBoxW
544  * because we can't forward to it in the .spec file since it's exported by
545  * ordinal. If you change the implementation here please update the code in
546  * shlwapi as well.
547  */
548 // Wine version, broken.
ShellMessageBoxW(HINSTANCE hInstance,HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType,...)549 int ShellMessageBoxW(
550 	HINSTANCE hInstance,
551 	HWND hWnd,
552 	LPCWSTR lpText,
553 	LPCWSTR lpCaption,
554 	UINT uType,
555 	...)
556 {
557 	WCHAR	szText[100],szTitle[100];
558 	LPCWSTR pszText = szText, pszTitle = szTitle;
559 	LPWSTR  pszTemp;
560 	__ms_va_list args;
561 	int	ret;
562 
563 	__ms_va_start(args, uType);
564 	/* wvsprintfA(buf,fmt, args); */
565 
566 	TRACE("(%p,%p,%p,%p,%08x)\n",
567 	    hInstance,hWnd,lpText,lpCaption,uType);
568 
569 	if (IS_INTRESOURCE(lpCaption))
570 	  LoadStringW(hInstance, LOWORD(lpCaption), szTitle, ARRAY_SIZE(szTitle));
571 	else
572 	  pszTitle = lpCaption;
573 
574 	if (IS_INTRESOURCE(lpText))
575 	  LoadStringW(hInstance, LOWORD(lpText), szText, ARRAY_SIZE(szText));
576 	else
577 	  pszText = lpText;
578 
579 	FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
580 		       pszText, 0, 0, (LPWSTR)&pszTemp, 0, &args);
581 
582 	__ms_va_end(args);
583 
584 	ret = MessageBoxW(hWnd,pszTemp,pszTitle,uType);
585         LocalFree(pszTemp);
586 	return ret;
587 }
588 #endif
589 
590 /*************************************************************************
591  * ShellMessageBoxA				[SHELL32.183]
592  *
593  * Format and output an error message.
594  *
595  * PARAMS
596  *  hInstance [I] Instance handle of message creator
597  *  hWnd      [I] Window handle of message creator
598  *  lpText    [I] Resource Id of title or LPSTR
599  *  lpCaption [I] Resource Id of title or LPSTR
600  *  uType     [I] Type of error message
601  *
602  * RETURNS
603  *  A return value from MessageBoxA().
604  *
605  * NOTES
606  *     Exported by ordinal
607  */
608 #ifdef __REACTOS__
609 /*
610  * Note that we cannot straightforwardly implement ShellMessageBoxA around
611  * ShellMessageBoxW, by converting some parameters from ANSI to UNICODE,
612  * because there may be some variadic ANSI strings, associated with '%s'
613  * printf-like formatters inside the format string, that would also need
614  * to be converted; however there is no way for us to find these and perform
615  * the conversion ourselves.
616  * Therefore, we re-implement ShellMessageBoxA by doing a copy-paste ANSI
617  * adaptation of the shlwapi.ShellMessageBoxWrapW function.
618  */
619 #endif
ShellMessageBoxA(HINSTANCE hInstance,HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType,...)620 int ShellMessageBoxA(
621 	HINSTANCE hInstance,
622 	HWND hWnd,
623 	LPCSTR lpText,
624 	LPCSTR lpCaption,
625 	UINT uType,
626 	...)
627 {
628 #ifdef __REACTOS__
629     CHAR *szText = NULL, szTitle[100];
630     LPCSTR pszText, pszTitle = szTitle;
631     LPSTR pszTemp;
632     __ms_va_list args;
633     int ret;
634 
635     __ms_va_start(args, uType);
636 
637     TRACE("(%p,%p,%p,%p,%08x)\n", hInstance, hWnd, lpText, lpCaption, uType);
638 
639     if (IS_INTRESOURCE(lpCaption))
640         LoadStringA(hInstance, LOWORD(lpCaption), szTitle, ARRAY_SIZE(szTitle));
641     else
642         pszTitle = lpCaption;
643 
644     if (IS_INTRESOURCE(lpText))
645     {
646         /* Retrieve the length of the Unicode string and obtain the maximum
647          * possible length for the corresponding ANSI string (not counting
648          * any possible NULL-terminator). */
649         const WCHAR *ptr;
650         UINT len = LoadStringW(hInstance, LOWORD(lpText), (LPWSTR)&ptr, 0);
651 
652         len = WideCharToMultiByte(CP_ACP, 0, ptr, len,
653                                   NULL, 0, NULL, NULL);
654 
655         if (len)
656         {
657             szText = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(CHAR));
658             if (szText) LoadStringA(hInstance, LOWORD(lpText), szText, len + 1);
659         }
660         pszText = szText;
661         if (!pszText) {
662             WARN("Failed to load id %d\n", LOWORD(lpText));
663             __ms_va_end(args);
664             return 0;
665         }
666     }
667     else
668         pszText = lpText;
669 
670     FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
671                    pszText, 0, 0, (LPSTR)&pszTemp, 0, &args);
672 
673     __ms_va_end(args);
674 
675     ret = MessageBoxA(hWnd, pszTemp, pszTitle, uType | MB_SETFOREGROUND);
676 
677     HeapFree(GetProcessHeap(), 0, szText);
678     LocalFree(pszTemp);
679     return ret;
680 
681 #else // __REACTOS__
682 
683 // Wine version, broken.
684 	char	szText[100],szTitle[100];
685 	LPCSTR  pszText = szText, pszTitle = szTitle;
686 	LPSTR   pszTemp;
687 	__ms_va_list args;
688 	int	ret;
689 
690 	__ms_va_start(args, uType);
691 	/* wvsprintfA(buf,fmt, args); */
692 
693 	TRACE("(%p,%p,%p,%p,%08x)\n",
694 	    hInstance,hWnd,lpText,lpCaption,uType);
695 
696 	if (IS_INTRESOURCE(lpCaption))
697 	  LoadStringA(hInstance, LOWORD(lpCaption), szTitle, sizeof(szTitle));
698 	else
699 	  pszTitle = lpCaption;
700 
701 	if (IS_INTRESOURCE(lpText))
702 	  LoadStringA(hInstance, LOWORD(lpText), szText, sizeof(szText));
703 	else
704 	  pszText = lpText;
705 
706 	FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
707 		       pszText, 0, 0, (LPSTR)&pszTemp, 0, &args);
708 
709 	__ms_va_end(args);
710 
711 	ret = MessageBoxA(hWnd,pszTemp,pszTitle,uType);
712         LocalFree(pszTemp);
713 	return ret;
714 #endif
715 }
716 
717 /*************************************************************************
718  * SHRegisterDragDrop				[SHELL32.86]
719  *
720  * Probably equivalent to RegisterDragDrop but under Windows 95 it could use the
721  * shell32 built-in "mini-COM" without the need to load ole32.dll - see SHLoadOLE
722  * for details. Under Windows 98 this function initializes the true OLE when called
723  * the first time, on XP always returns E_OUTOFMEMORY and it got removed from Vista.
724  *
725  * We follow Windows 98 behaviour.
726  *
727  * NOTES
728  *     exported by ordinal
729  *
730  * SEE ALSO
731  *     RegisterDragDrop, SHLoadOLE
732  */
SHRegisterDragDrop(HWND hWnd,LPDROPTARGET pDropTarget)733 HRESULT WINAPI SHRegisterDragDrop(
734 	HWND hWnd,
735 	LPDROPTARGET pDropTarget)
736 {
737         static BOOL ole_initialized = FALSE;
738         HRESULT hr;
739 
740         TRACE("(%p,%p)\n", hWnd, pDropTarget);
741 
742         if (!ole_initialized)
743         {
744             hr = OleInitialize(NULL);
745             if (FAILED(hr))
746                 return hr;
747             ole_initialized = TRUE;
748         }
749 	return RegisterDragDrop(hWnd, pDropTarget);
750 }
751 
752 /*************************************************************************
753  * SHRevokeDragDrop				[SHELL32.87]
754  *
755  * Probably equivalent to RevokeDragDrop but under Windows 95 it could use the
756  * shell32 built-in "mini-COM" without the need to load ole32.dll - see SHLoadOLE
757  * for details. Function removed from Windows Vista.
758  *
759  * We call ole32 RevokeDragDrop which seems to work even if OleInitialize was
760  * not called.
761  *
762  * NOTES
763  *     exported by ordinal
764  *
765  * SEE ALSO
766  *     RevokeDragDrop, SHLoadOLE
767  */
SHRevokeDragDrop(HWND hWnd)768 HRESULT WINAPI SHRevokeDragDrop(HWND hWnd)
769 {
770     TRACE("(%p)\n", hWnd);
771     return RevokeDragDrop(hWnd);
772 }
773 
774 /*************************************************************************
775  * SHDoDragDrop					[SHELL32.88]
776  *
777  * Probably equivalent to DoDragDrop but under Windows 9x it could use the
778  * shell32 built-in "mini-COM" without the need to load ole32.dll - see SHLoadOLE
779  * for details
780  *
781  * NOTES
782  *     exported by ordinal
783  *
784  * SEE ALSO
785  *     DoDragDrop, SHLoadOLE
786  */
SHDoDragDrop(HWND hWnd,LPDATAOBJECT lpDataObject,LPDROPSOURCE lpDropSource,DWORD dwOKEffect,LPDWORD pdwEffect)787 HRESULT WINAPI SHDoDragDrop(
788 	HWND hWnd,
789 	LPDATAOBJECT lpDataObject,
790 	LPDROPSOURCE lpDropSource,
791 	DWORD dwOKEffect,
792 	LPDWORD pdwEffect)
793 {
794     FIXME("(%p %p %p 0x%08x %p):stub.\n",
795     hWnd, lpDataObject, lpDropSource, dwOKEffect, pdwEffect);
796 	return DoDragDrop(lpDataObject, lpDropSource, dwOKEffect, pdwEffect);
797 }
798 
799 /*************************************************************************
800  * ArrangeWindows				[SHELL32.184]
801  *
802  */
ArrangeWindows(HWND hwndParent,DWORD dwReserved,const RECT * lpRect,WORD cKids,const HWND * lpKids)803 WORD WINAPI ArrangeWindows(HWND hwndParent, DWORD dwReserved, const RECT *lpRect,
804         WORD cKids, const HWND *lpKids)
805 {
806     /* Unimplemented in WinXP SP3 */
807     TRACE("(%p 0x%08x %p 0x%04x %p):stub.\n",
808 	   hwndParent, dwReserved, lpRect, cKids, lpKids);
809     return 0;
810 }
811 
812 /*************************************************************************
813  * SignalFileOpen				[SHELL32.103]
814  *
815  * NOTES
816  *     exported by ordinal
817  */
818 BOOL WINAPI
SignalFileOpen(PCIDLIST_ABSOLUTE pidl)819 SignalFileOpen (PCIDLIST_ABSOLUTE pidl)
820 {
821     FIXME("(%p):stub.\n", pidl);
822 
823     return FALSE;
824 }
825 
826 #ifndef __REACTOS__
827 
828 /*************************************************************************
829  * SHADD_get_policy - helper function for SHAddToRecentDocs
830  *
831  * PARAMETERS
832  *   policy    [IN]  policy name (null termed string) to find
833  *   type      [OUT] ptr to DWORD to receive type
834  *   buffer    [OUT] ptr to area to hold data retrieved
835  *   len       [IN/OUT] ptr to DWORD holding size of buffer and getting
836  *                      length filled
837  *
838  * RETURNS
839  *   result of the SHQueryValueEx call
840  */
SHADD_get_policy(LPCSTR policy,LPDWORD type,LPVOID buffer,LPDWORD len)841 static INT SHADD_get_policy(LPCSTR policy, LPDWORD type, LPVOID buffer, LPDWORD len)
842 {
843     HKEY Policy_basekey;
844     INT ret;
845 
846     /* Get the key for the policies location in the registry
847      */
848     if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,
849 		      "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer",
850 		      0, KEY_READ, &Policy_basekey)) {
851 
852 	if (RegOpenKeyExA(HKEY_CURRENT_USER,
853 			  "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer",
854 			  0, KEY_READ, &Policy_basekey)) {
855 	    TRACE("No Explorer Policies location exists. Policy wanted=%s\n",
856 		  policy);
857 	    *len = 0;
858 	    return ERROR_FILE_NOT_FOUND;
859 	}
860     }
861 
862     /* Retrieve the data if it exists
863      */
864     ret = SHQueryValueExA(Policy_basekey, policy, 0, type, buffer, len);
865     RegCloseKey(Policy_basekey);
866     return ret;
867 }
868 
869 #endif // __REACTOS__
870 
871 /*************************************************************************
872  * SHADD_compare_mru - helper function for SHAddToRecentDocs
873  *
874  * PARAMETERS
875  *   data1     [IN] data being looked for
876  *   data2     [IN] data in MRU
877  *   cbdata    [IN] length from FindMRUData call (not used)
878  *
879  * RETURNS
880  *   position within MRU list that data was added.
881  */
SHADD_compare_mru(LPCVOID data1,LPCVOID data2,DWORD cbData)882 static INT CALLBACK SHADD_compare_mru(LPCVOID data1, LPCVOID data2, DWORD cbData)
883 {
884 #ifdef __REACTOS__
885     LPCWSTR psz1, psz2;
886     INT iCmp = lstrcmpiW(data1, data2);
887     if (iCmp != 0)
888         return iCmp;
889     psz1 = data1;
890     psz2 = data2;
891     psz1 += lstrlenW(psz1) + 1;
892     psz2 += lstrlenW(psz2) + 1;
893     return lstrcmpiW(psz1, psz2);
894 #else
895     return lstrcmpiA(data1, data2);
896 #endif
897 }
898 
899 #ifdef __REACTOS__
900 static BOOL
DoStoreMRUData(LPBYTE pbBuffer,LPDWORD pcbBuffer,LPCWSTR pszTargetTitle,LPCWSTR pszTargetPath,LPCWSTR pszLinkTitle)901 DoStoreMRUData(LPBYTE pbBuffer, LPDWORD pcbBuffer,
902                LPCWSTR pszTargetTitle, LPCWSTR pszTargetPath, LPCWSTR pszLinkTitle)
903 {
904     DWORD ib = 0, cb;
905     INT cchTargetTitle = lstrlenW(pszTargetTitle);
906     INT cchTargetPath = lstrlenW(pszTargetPath);
907     INT cchLinkTitle = lstrlenW(pszLinkTitle);
908 
909     cb = (cchTargetTitle + 1 + cchTargetPath + 1 + cchLinkTitle + 2) * sizeof(WCHAR);
910     if (cb > *pcbBuffer)
911         return FALSE;
912 
913     ZeroMemory(pbBuffer, *pcbBuffer);
914 
915     cb = (cchTargetTitle + 1) * sizeof(WCHAR);
916     if (ib + cb > *pcbBuffer)
917         return FALSE;
918     CopyMemory(&pbBuffer[ib], pszTargetTitle, cb);
919     ib += cb;
920 
921     cb = (cchTargetPath + 1) * sizeof(WCHAR);
922     if (ib + cb > *pcbBuffer)
923         return FALSE;
924     CopyMemory(&pbBuffer[ib], pszTargetPath, cb);
925     ib += cb;
926 
927     cb = (cchLinkTitle + 1) * sizeof(WCHAR);
928     if (ib + cb > *pcbBuffer)
929         return FALSE;
930     CopyMemory(&pbBuffer[ib], pszLinkTitle, cb);
931     ib += cb;
932 
933     *pcbBuffer = ib;
934     return TRUE;
935 }
936 #else
937 /*************************************************************************
938  * SHADD_create_add_mru_data - helper function for SHAddToRecentDocs
939  *
940  * PARAMETERS
941  *   mruhandle    [IN] handle for created MRU list
942  *   doc_name     [IN] null termed pure doc name
943  *   new_lnk_name [IN] null termed path and file name for .lnk file
944  *   buffer       [IN/OUT] 2048 byte area to construct MRU data
945  *   len          [OUT] ptr to int to receive space used in buffer
946  *
947  * RETURNS
948  *   position within MRU list that data was added.
949  */
SHADD_create_add_mru_data(HANDLE mruhandle,LPCSTR doc_name,LPCSTR new_lnk_name,LPSTR buffer,INT * len)950 static INT SHADD_create_add_mru_data(HANDLE mruhandle, LPCSTR doc_name, LPCSTR new_lnk_name,
951                                      LPSTR buffer, INT *len)
952 {
953     LPSTR ptr;
954     INT wlen;
955 
956     /*FIXME: Document:
957      *  RecentDocs MRU data structure seems to be:
958      *    +0h   document file name w/ terminating 0h
959      *    +nh   short int w/ size of remaining
960      *    +n+2h 02h 30h, or 01h 30h, or 00h 30h  -  unknown
961      *    +n+4h 10 bytes zeros  -   unknown
962      *    +n+eh shortcut file name w/ terminating 0h
963      *    +n+e+nh 3 zero bytes  -  unknown
964      */
965 
966     /* Create the MRU data structure for "RecentDocs"
967 	 */
968     ptr = buffer;
969     lstrcpyA(ptr, doc_name);
970     ptr += (lstrlenA(buffer) + 1);
971     wlen= lstrlenA(new_lnk_name) + 1 + 12;
972     *((short int*)ptr) = wlen;
973     ptr += 2;   /* step past the length */
974     *(ptr++) = 0x30;  /* unknown reason */
975     *(ptr++) = 0;     /* unknown, but can be 0x00, 0x01, 0x02 */
976     memset(ptr, 0, 10);
977     ptr += 10;
978     lstrcpyA(ptr, new_lnk_name);
979     ptr += (lstrlenA(new_lnk_name) + 1);
980     memset(ptr, 0, 3);
981     ptr += 3;
982     *len = ptr - buffer;
983 
984     /* Add the new entry into the MRU list
985      */
986     return AddMRUData(mruhandle, buffer, *len);
987 }
988 #endif
989 
990 /*************************************************************************
991  * SHAddToRecentDocs				[SHELL32.@]
992  *
993  * Modify (add/clear) Shell's list of recently used documents.
994  *
995  * PARAMETERS
996  *   uFlags  [IN] SHARD_PATHA, SHARD_PATHW or SHARD_PIDL
997  *   pv      [IN] string or pidl, NULL clears the list
998  *
999  * NOTES
1000  *     exported by name
1001  *
1002  * FIXME
1003  *  convert to unicode
1004  */
SHAddToRecentDocs(UINT uFlags,LPCVOID pv)1005 void WINAPI SHAddToRecentDocs (UINT uFlags,LPCVOID pv)
1006 {
1007 #ifdef __REACTOS__
1008     INT ret;
1009     WCHAR szTargetPath[MAX_PATH], szLinkDir[MAX_PATH], szLinkFile[MAX_PATH], szDescription[80];
1010     WCHAR szPath[MAX_PATH];
1011     DWORD cbBuffer;
1012     HANDLE hFind;
1013     WIN32_FIND_DATAW find;
1014     HKEY hExplorerKey;
1015     LONG error;
1016     LPWSTR pchDotExt, pchTargetTitle, pchLinkTitle;
1017     MRUINFOW mru;
1018     HANDLE hMRUList = NULL;
1019     IShellLinkW *psl = NULL;
1020     IPersistFile *pPf = NULL;
1021     HRESULT hr;
1022     BYTE Buffer[(MAX_PATH + 64) * sizeof(WCHAR)];
1023 
1024     TRACE("%04x %p\n", uFlags, pv);
1025 
1026     /* check policy */
1027     ret = SHRestricted(REST_NORECENTDOCSHISTORY);
1028     TRACE("policy value for NoRecentDocsHistory = %08x\n", ret);
1029     if (ret != 0)
1030         return;
1031 
1032     /* store to szTargetPath */
1033     szTargetPath[0] = 0;
1034     if (pv)
1035     {
1036         switch (uFlags)
1037         {
1038             case SHARD_PATHA:
1039                 MultiByteToWideChar(CP_ACP, 0, pv, -1, szLinkDir, ARRAYSIZE(szLinkDir));
1040                 GetFullPathNameW(szLinkDir, ARRAYSIZE(szTargetPath), szTargetPath, NULL);
1041                 break;
1042 
1043             case SHARD_PATHW:
1044                 GetFullPathNameW(pv, ARRAYSIZE(szTargetPath), szTargetPath, NULL);
1045                 break;
1046 
1047             case SHARD_PIDL:
1048                 SHGetPathFromIDListW(pv, szLinkDir);
1049                 GetFullPathNameW(szLinkDir, ARRAYSIZE(szTargetPath), szTargetPath, NULL);
1050                 break;
1051 
1052             default:
1053                 FIXME("Unsupported flags: %u\n", uFlags);
1054                 return;
1055         }
1056     }
1057 
1058     /* get recent folder */
1059     if (!SHGetSpecialFolderPathW(NULL, szLinkDir, CSIDL_RECENT, FALSE))
1060     {
1061         ERR("serious issues 1\n");
1062         return;
1063     }
1064     TRACE("Users Recent dir %S\n", szLinkDir);
1065 
1066     /* open Explorer key */
1067     error = RegCreateKeyExW(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer",
1068                             0, NULL, 0,
1069                             KEY_READ | KEY_WRITE, NULL, &hExplorerKey, NULL);
1070     if (error)
1071     {
1072         ERR("Failed to RegCreateKeyExW: 0x%08X\n", error);
1073         return;
1074     }
1075 
1076     if (!pv)
1077     {
1078         TRACE("pv is NULL, so delete all shortcut files in %S\n", szLinkDir);
1079 
1080         lstrcpynW(szLinkFile, szLinkDir, ARRAYSIZE(szLinkFile));
1081         PathAppendW(szLinkFile, L"*.lnk");
1082 
1083         hFind = FindFirstFileW(szLinkFile, &find);
1084         if (hFind != INVALID_HANDLE_VALUE)
1085         {
1086             do
1087             {
1088                 lstrcpynW(szLinkFile, szLinkDir, ARRAYSIZE(szLinkFile));
1089                 PathAppendW(szLinkFile, find.cFileName);
1090                 DeleteFileW(szLinkFile);
1091             } while (FindNextFile(hFind, &find));
1092             FindClose(hFind);
1093         }
1094 
1095         SHDeleteKeyW(hExplorerKey, L"RecentDocs");
1096         RegCloseKey(hExplorerKey);
1097         return;
1098     }
1099 
1100     if (szTargetPath[0] == 0 || !PathFileExistsW(szTargetPath) ||
1101         PathIsDirectoryW(szTargetPath))
1102     {
1103         /* path is not normal file */
1104         RegCloseKey(hExplorerKey);
1105         return;
1106     }
1107 
1108     hr = CoInitialize(NULL);
1109     if (FAILED(hr))
1110     {
1111         ERR("CoInitialize: %08X\n", hr);
1112         RegCloseKey(hExplorerKey);
1113         return;
1114     }
1115 
1116     /* check if file is a shortcut */
1117     ret = 0;
1118     pchDotExt = PathFindExtensionW(szTargetPath);
1119     while (lstrcmpiW(pchDotExt, L".lnk") == 0)
1120     {
1121         hr = IShellLink_ConstructFromPath(szTargetPath, &IID_IShellLinkW, (LPVOID*)&psl);
1122         if (FAILED(hr))
1123         {
1124             ERR("IShellLink_ConstructFromPath: 0x%08X\n", hr);
1125             goto Quit;
1126         }
1127 
1128         IShellLinkW_GetPath(psl, szPath, ARRAYSIZE(szPath), NULL, 0);
1129         IShellLinkW_Release(psl);
1130         psl = NULL;
1131 
1132         lstrcpynW(szTargetPath, szPath, ARRAYSIZE(szTargetPath));
1133         pchDotExt = PathFindExtensionW(szTargetPath);
1134 
1135         if (++ret >= 8)
1136         {
1137             ERR("Link loop?\n");
1138             goto Quit;
1139         }
1140     }
1141     if (!lstrcmpiW(pchDotExt, L".exe"))
1142     {
1143         /* executables are not added */
1144         goto Quit;
1145     }
1146 
1147     /* ***  JOB 0: Build strings *** */
1148 
1149     pchTargetTitle = PathFindFileNameW(szTargetPath);
1150 
1151     lstrcpyW(szDescription, L"Shortcut to ");
1152     StrCatBuffW(szDescription, pchTargetTitle, ARRAYSIZE(szDescription));
1153 
1154     lstrcpynW(szLinkFile, szLinkDir, ARRAYSIZE(szLinkFile));
1155     PathAppendW(szLinkFile, pchTargetTitle);
1156     StrCatBuffW(szLinkFile, L".lnk", ARRAYSIZE(szLinkFile));
1157     pchLinkTitle = PathFindFileNameW(szLinkFile);
1158 
1159     /* ***  JOB 1: Update registry for ...\Explorer\RecentDocs list  *** */
1160 
1161     /* store MRU data */
1162     cbBuffer = sizeof(Buffer);
1163     ret = DoStoreMRUData(Buffer, &cbBuffer, pchTargetTitle, szTargetPath, pchLinkTitle);
1164     if (!ret)
1165     {
1166         ERR("DoStoreMRUData failed: %d\n", ret);
1167         goto Quit;
1168     }
1169 
1170     /* create MRU list */
1171     mru.cbSize = sizeof(mru);
1172     mru.uMax = 16;
1173     mru.fFlags = MRU_BINARY | MRU_CACHEWRITE;
1174     mru.hKey = hExplorerKey;
1175     mru.lpszSubKey = L"RecentDocs";
1176     mru.lpfnCompare = (MRUCMPPROCW)SHADD_compare_mru;
1177     hMRUList = CreateMRUListW(&mru);
1178     if (!hMRUList)
1179     {
1180         ERR("CreateMRUListW failed\n");
1181         goto Quit;
1182     }
1183 
1184     /* already exists? */
1185     ret = FindMRUData(hMRUList, Buffer, cbBuffer, NULL);
1186     if (ret >= 0)
1187     {
1188         /* Just touch for speed */
1189         HANDLE hFile;
1190         hFile = CreateFileW(szLinkFile, GENERIC_READ | GENERIC_WRITE,
1191                             FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
1192         if (hFile != INVALID_HANDLE_VALUE)
1193         {
1194             TRACE("Just touch file '%S'.\n", szLinkFile);
1195             CloseHandle(hFile);
1196             goto Quit;
1197         }
1198     }
1199 
1200     /* add MRU data */
1201     ret = AddMRUData(hMRUList, Buffer, cbBuffer);
1202     if (ret < 0)
1203     {
1204         ERR("AddMRUData failed: %d\n", ret);
1205         goto Quit;
1206     }
1207 
1208     /* ***  JOB 2: Create shortcut in user's "Recent" directory  *** */
1209 
1210     hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
1211                           &IID_IShellLinkW, (LPVOID *)&psl);
1212     if (FAILED(hr))
1213     {
1214         ERR("CoInitialize for IID_IShellLinkW: %08X\n", hr);
1215         goto Quit;
1216     }
1217 
1218     hr = IShellLinkW_QueryInterface(psl, &IID_IPersistFile, (LPVOID *)&pPf);
1219     if (FAILED(hr))
1220     {
1221         ERR("IShellLinkW_QueryInterface: %08X\n", hr);
1222         goto Quit;
1223     }
1224 
1225     if (uFlags == SHARD_PIDL)
1226         hr = IShellLinkW_SetIDList(psl, pv);
1227     else
1228         hr = IShellLinkW_SetPath(psl, pv);
1229 
1230     IShellLinkW_SetDescription(psl, szDescription);
1231 
1232     hr = IPersistFile_Save(pPf, szLinkFile, TRUE);
1233     if (FAILED(hr))
1234     {
1235         ERR("IPersistFile_Save: 0x%08X\n", hr);
1236     }
1237 
1238     hr = IPersistFile_SaveCompleted(pPf, szLinkFile);
1239     if (FAILED(hr))
1240     {
1241         ERR("IPersistFile_SaveCompleted: 0x%08X\n", hr);
1242     }
1243 
1244 Quit:
1245     if (hMRUList)
1246         FreeMRUList(hMRUList);
1247     if (pPf)
1248         IPersistFile_Release(pPf);
1249     if (psl)
1250         IShellLinkW_Release(psl);
1251     CoUninitialize();
1252     RegCloseKey(hExplorerKey);
1253 #else
1254 /* If list is a string list lpfnCompare has the following prototype
1255  * int CALLBACK MRUCompareString(LPCSTR s1, LPCSTR s2)
1256  * for binary lists the prototype is
1257  * int CALLBACK MRUCompareBinary(LPCVOID data1, LPCVOID data2, DWORD cbData)
1258  * where cbData is the no. of bytes to compare.
1259  * Need to check what return value means identical - 0?
1260  */
1261 
1262 
1263     UINT olderrormode;
1264     HKEY HCUbasekey;
1265     CHAR doc_name[MAX_PATH];
1266     CHAR link_dir[MAX_PATH];
1267     CHAR new_lnk_filepath[MAX_PATH];
1268     CHAR new_lnk_name[MAX_PATH];
1269     CHAR * ext;
1270     IMalloc *ppM;
1271     LPITEMIDLIST pidl;
1272     HWND hwnd = 0;       /* FIXME:  get real window handle */
1273     INT ret;
1274     DWORD data[64], datalen, type;
1275 
1276     TRACE("%04x %p\n", uFlags, pv);
1277 
1278     /*FIXME: Document:
1279      *  RecentDocs MRU data structure seems to be:
1280      *    +0h   document file name w/ terminating 0h
1281      *    +nh   short int w/ size of remaining
1282      *    +n+2h 02h 30h, or 01h 30h, or 00h 30h  -  unknown
1283      *    +n+4h 10 bytes zeros  -   unknown
1284      *    +n+eh shortcut file name w/ terminating 0h
1285      *    +n+e+nh 3 zero bytes  -  unknown
1286      */
1287 
1288     /* See if we need to do anything.
1289      */
1290     datalen = 64;
1291     ret=SHADD_get_policy( "NoRecentDocsHistory", &type, data, &datalen);
1292     if ((ret > 0) && (ret != ERROR_FILE_NOT_FOUND)) {
1293 	ERR("Error %d getting policy \"NoRecentDocsHistory\"\n", ret);
1294 	return;
1295     }
1296     if (ret == ERROR_SUCCESS) {
1297 	if (!( (type == REG_DWORD) ||
1298 	       ((type == REG_BINARY) && (datalen == 4)) )) {
1299 	    ERR("Error policy data for \"NoRecentDocsHistory\" not formatted correctly, type=%d, len=%d\n",
1300 		type, datalen);
1301 	    return;
1302 	}
1303 
1304 	TRACE("policy value for NoRecentDocsHistory = %08x\n", data[0]);
1305 	/* now test the actual policy value */
1306 	if ( data[0] != 0)
1307 	    return;
1308     }
1309 
1310     /* Open key to where the necessary info is
1311      */
1312     /* FIXME: This should be done during DLL PROCESS_ATTACH (or THREAD_ATTACH)
1313      *        and the close should be done during the _DETACH. The resulting
1314      *        key is stored in the DLL global data.
1315      */
1316     if (RegCreateKeyExA(HKEY_CURRENT_USER,
1317 			"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
1318 			0, 0, 0, KEY_READ, 0, &HCUbasekey, 0)) {
1319 	ERR("Failed to create 'Software\\Microsoft\\Windows\\CurrentVersion\\Explorer'\n");
1320 	return;
1321     }
1322 
1323     /* Get path to user's "Recent" directory
1324      */
1325     if(SUCCEEDED(SHGetMalloc(&ppM))) {
1326 	if (SUCCEEDED(SHGetSpecialFolderLocation(hwnd, CSIDL_RECENT,
1327 						 &pidl))) {
1328 	    SHGetPathFromIDListA(pidl, link_dir);
1329 	    IMalloc_Free(ppM, pidl);
1330 	}
1331 	else {
1332 	    /* serious issues */
1333 	    link_dir[0] = 0;
1334 	    ERR("serious issues 1\n");
1335 	}
1336 	IMalloc_Release(ppM);
1337     }
1338     else {
1339 	/* serious issues */
1340 	link_dir[0] = 0;
1341 	ERR("serious issues 2\n");
1342     }
1343     TRACE("Users Recent dir %s\n", link_dir);
1344 
1345     /* If no input, then go clear the lists */
1346     if (!pv) {
1347 	/* clear user's Recent dir
1348 	 */
1349 
1350 	/* FIXME: delete all files in "link_dir"
1351 	 *
1352 	 * while( more files ) {
1353 	 *    lstrcpyA(old_lnk_name, link_dir);
1354 	 *    PathAppendA(old_lnk_name, filenam);
1355 	 *    DeleteFileA(old_lnk_name);
1356 	 * }
1357 	 */
1358 	FIXME("should delete all files in %s\\\n", link_dir);
1359 
1360 	/* clear MRU list
1361 	 */
1362 	/* MS Bug ?? v4.72.3612.1700 of shell32 does the delete against
1363 	 *  HKEY_LOCAL_MACHINE version of ...CurrentVersion\Explorer
1364 	 *  and naturally it fails w/ rc=2. It should do it against
1365 	 *  HKEY_CURRENT_USER which is where it is stored, and where
1366 	 *  the MRU routines expect it!!!!
1367 	 */
1368 	RegDeleteKeyA(HCUbasekey, "RecentDocs");
1369 	RegCloseKey(HCUbasekey);
1370 	return;
1371     }
1372 
1373     /* Have data to add, the jobs to be done:
1374      *   1. Add document to MRU list in registry "HKCU\Software\
1375      *      Microsoft\Windows\CurrentVersion\Explorer\RecentDocs".
1376      *   2. Add shortcut to document in the user's Recent directory
1377      *      (CSIDL_RECENT).
1378      *   3. Add shortcut to Start menu's Documents submenu.
1379      */
1380 
1381     /* Get the pure document name from the input
1382      */
1383     switch (uFlags)
1384     {
1385     case SHARD_PIDL:
1386         if (!SHGetPathFromIDListA(pv, doc_name))
1387         {
1388             WARN("can't get path from PIDL\n");
1389             return;
1390         }
1391         break;
1392 
1393     case SHARD_PATHA:
1394         lstrcpynA(doc_name, pv, MAX_PATH);
1395         break;
1396 
1397     case SHARD_PATHW:
1398         WideCharToMultiByte(CP_ACP, 0, pv, -1, doc_name, MAX_PATH, NULL, NULL);
1399         break;
1400 
1401     default:
1402         FIXME("Unsupported flags: %u\n", uFlags);
1403         return;
1404     }
1405 
1406     TRACE("full document name %s\n", debugstr_a(doc_name));
1407 
1408     PathStripPathA(doc_name);
1409     TRACE("stripped document name %s\n", debugstr_a(doc_name));
1410 
1411 
1412     /* ***  JOB 1: Update registry for ...\Explorer\RecentDocs list  *** */
1413 
1414     {  /* on input needs:
1415 	*      doc_name    -  pure file-spec, no path
1416 	*      link_dir    -  path to the user's Recent directory
1417 	*      HCUbasekey  -  key of ...Windows\CurrentVersion\Explorer" node
1418 	* creates:
1419 	*      new_lnk_name-  pure file-spec, no path for new .lnk file
1420 	*      new_lnk_filepath
1421 	*                  -  path and file name of new .lnk file
1422 	*/
1423 	CREATEMRULISTA mymru;
1424 	HANDLE mruhandle;
1425 	INT len, pos, bufused, err;
1426 	INT i;
1427 	DWORD attr;
1428 	CHAR buffer[2048];
1429 	CHAR *ptr;
1430 	CHAR old_lnk_name[MAX_PATH];
1431 	short int slen;
1432 
1433 	mymru.cbSize = sizeof(CREATEMRULISTA);
1434 	mymru.nMaxItems = 15;
1435 	mymru.dwFlags = MRUF_BINARY_LIST | MRUF_DELAYED_SAVE;
1436 	mymru.hKey = HCUbasekey;
1437 	mymru.lpszSubKey = "RecentDocs";
1438         mymru.lpfnCompare = SHADD_compare_mru;
1439 	mruhandle = CreateMRUListA(&mymru);
1440 	if (!mruhandle) {
1441 	    /* MRU failed */
1442 	    ERR("MRU processing failed, handle zero\n");
1443 	    RegCloseKey(HCUbasekey);
1444 	    return;
1445 	}
1446 	len = lstrlenA(doc_name);
1447 	pos = FindMRUData(mruhandle, doc_name, len, 0);
1448 
1449 	/* Now get the MRU entry that will be replaced
1450 	 * and delete the .lnk file for it
1451 	 */
1452 	if ((bufused = EnumMRUListA(mruhandle, (pos == -1) ? 14 : pos,
1453                                     buffer, 2048)) != -1) {
1454 	    ptr = buffer;
1455 	    ptr += (lstrlenA(buffer) + 1);
1456 	    slen = *((short int*)ptr);
1457 	    ptr += 2;  /* skip the length area */
1458 	    if (bufused >= slen + (ptr-buffer)) {
1459 		/* buffer size looks good */
1460 		ptr += 12; /* get to string */
1461 		len = bufused - (ptr-buffer);  /* get length of buf remaining */
1462                 if (ptr[0] && (lstrlenA(ptr) <= len-1)) {
1463 		    /* appears to be good string */
1464 		    lstrcpyA(old_lnk_name, link_dir);
1465 		    PathAppendA(old_lnk_name, ptr);
1466 		    if (!DeleteFileA(old_lnk_name)) {
1467 			if ((attr = GetFileAttributesA(old_lnk_name)) == INVALID_FILE_ATTRIBUTES) {
1468 			    if ((err = GetLastError()) != ERROR_FILE_NOT_FOUND) {
1469 				ERR("Delete for %s failed, err=%d, attr=%08x\n",
1470 				    old_lnk_name, err, attr);
1471 			    }
1472 			    else {
1473 				TRACE("old .lnk file %s did not exist\n",
1474 				      old_lnk_name);
1475 			    }
1476 			}
1477 			else {
1478 			    ERR("Delete for %s failed, attr=%08x\n",
1479 				old_lnk_name, attr);
1480 			}
1481 		    }
1482 		    else {
1483 			TRACE("deleted old .lnk file %s\n", old_lnk_name);
1484 		    }
1485 		}
1486 	    }
1487 	}
1488 
1489 	/* Create usable .lnk file name for the "Recent" directory
1490 	 */
1491 	wsprintfA(new_lnk_name, "%s.lnk", doc_name);
1492 	lstrcpyA(new_lnk_filepath, link_dir);
1493 	PathAppendA(new_lnk_filepath, new_lnk_name);
1494 	i = 1;
1495 	olderrormode = SetErrorMode(SEM_FAILCRITICALERRORS);
1496 	while (GetFileAttributesA(new_lnk_filepath) != INVALID_FILE_ATTRIBUTES) {
1497 	    i++;
1498 	    wsprintfA(new_lnk_name, "%s (%u).lnk", doc_name, i);
1499 	    lstrcpyA(new_lnk_filepath, link_dir);
1500 	    PathAppendA(new_lnk_filepath, new_lnk_name);
1501 	}
1502 	SetErrorMode(olderrormode);
1503 	TRACE("new shortcut will be %s\n", new_lnk_filepath);
1504 
1505 	/* Now add the new MRU entry and data
1506 	 */
1507 	pos = SHADD_create_add_mru_data(mruhandle, doc_name, new_lnk_name,
1508 					buffer, &len);
1509 	FreeMRUList(mruhandle);
1510 	TRACE("Updated MRU list, new doc is position %d\n", pos);
1511     }
1512 
1513     /* ***  JOB 2: Create shortcut in user's "Recent" directory  *** */
1514 
1515     {  /* on input needs:
1516 	*      doc_name    -  pure file-spec, no path
1517 	*      new_lnk_filepath
1518 	*                  -  path and file name of new .lnk file
1519  	*      uFlags[in]  -  flags on call to SHAddToRecentDocs
1520 	*      pv[in]      -  document path/pidl on call to SHAddToRecentDocs
1521 	*/
1522 	IShellLinkA *psl = NULL;
1523 	IPersistFile *pPf = NULL;
1524 	HRESULT hres;
1525 	CHAR desc[MAX_PATH];
1526 	WCHAR widelink[MAX_PATH];
1527 
1528 	CoInitialize(0);
1529 
1530 	hres = CoCreateInstance( &CLSID_ShellLink,
1531 				 NULL,
1532 				 CLSCTX_INPROC_SERVER,
1533 				 &IID_IShellLinkA,
1534 				 (LPVOID )&psl);
1535 	if(SUCCEEDED(hres)) {
1536 
1537 	    hres = IShellLinkA_QueryInterface(psl, &IID_IPersistFile,
1538 					     (LPVOID *)&pPf);
1539 	    if(FAILED(hres)) {
1540 		/* bombed */
1541 		ERR("failed QueryInterface for IPersistFile %08x\n", hres);
1542 		goto fail;
1543 	    }
1544 
1545 	    /* Set the document path or pidl */
1546 	    if (uFlags == SHARD_PIDL) {
1547                 hres = IShellLinkA_SetIDList(psl, pv);
1548 	    } else {
1549                 hres = IShellLinkA_SetPath(psl, pv);
1550 	    }
1551 	    if(FAILED(hres)) {
1552 		/* bombed */
1553 		ERR("failed Set{IDList|Path} %08x\n", hres);
1554 		goto fail;
1555 	    }
1556 
1557 	    lstrcpyA(desc, "Shortcut to ");
1558 	    lstrcatA(desc, doc_name);
1559 	    hres = IShellLinkA_SetDescription(psl, desc);
1560 	    if(FAILED(hres)) {
1561 		/* bombed */
1562 		ERR("failed SetDescription %08x\n", hres);
1563 		goto fail;
1564 	    }
1565 
1566 	    MultiByteToWideChar(CP_ACP, 0, new_lnk_filepath, -1,
1567 				widelink, MAX_PATH);
1568 	    /* create the short cut */
1569 	    hres = IPersistFile_Save(pPf, widelink, TRUE);
1570 	    if(FAILED(hres)) {
1571 		/* bombed */
1572 		ERR("failed IPersistFile::Save %08x\n", hres);
1573 		IPersistFile_Release(pPf);
1574 		IShellLinkA_Release(psl);
1575 		goto fail;
1576 	    }
1577 	    hres = IPersistFile_SaveCompleted(pPf, widelink);
1578 	    IPersistFile_Release(pPf);
1579 	    IShellLinkA_Release(psl);
1580 	    TRACE("shortcut %s has been created, result=%08x\n",
1581 		  new_lnk_filepath, hres);
1582 	}
1583 	else {
1584 	    ERR("CoCreateInstance failed, hres=%08x\n", hres);
1585 	}
1586     }
1587 
1588  fail:
1589     CoUninitialize();
1590 
1591     /* all done */
1592     RegCloseKey(HCUbasekey);
1593     return;
1594 #endif
1595 }
1596 
1597 /*************************************************************************
1598  * SHCreateShellFolderViewEx			[SHELL32.174]
1599  *
1600  * Create a new instance of the default Shell folder view object.
1601  *
1602  * RETURNS
1603  *  Success: S_OK
1604  *  Failure: error value
1605  *
1606  * NOTES
1607  *  see IShellFolder::CreateViewObject
1608  */
1609  #ifndef __REACTOS__
1610 
SHCreateShellFolderViewEx(LPCSFV psvcbi,IShellView ** ppv)1611 HRESULT WINAPI SHCreateShellFolderViewEx(
1612 	LPCSFV psvcbi,    /* [in] shelltemplate struct */
1613 	IShellView **ppv) /* [out] IShellView pointer */
1614 {
1615 	IShellView * psf;
1616 	HRESULT hRes;
1617 
1618 	TRACE("sf=%p pidl=%p cb=%p mode=0x%08x parm=%p\n",
1619 	  psvcbi->pshf, psvcbi->pidl, psvcbi->pfnCallback,
1620 	  psvcbi->fvm, psvcbi->psvOuter);
1621 
1622 	*ppv = NULL;
1623     hRes = IShellView_Constructor(psvcbi->pshf, &psf);
1624 
1625     if (FAILED(hRes))
1626         return hRes;
1627 
1628 	hRes = IShellView_QueryInterface(psf, &IID_IShellView, (LPVOID *)ppv);
1629 	IShellView_Release(psf);
1630 
1631 	return hRes;
1632 }
1633 #endif
1634 
1635 /*************************************************************************
1636  *  SHWinHelp					[SHELL32.127]
1637  *
1638  */
SHWinHelp(HWND hwnd,LPCWSTR pszHelp,UINT uCommand,ULONG_PTR dwData)1639 HRESULT WINAPI SHWinHelp(HWND hwnd, LPCWSTR pszHelp, UINT uCommand, ULONG_PTR dwData)
1640 {
1641     TRACE("(%p, %s, 0x%08x, %p)\n", hwnd, debugstr_w(pszHelp), uCommand, dwData);
1642     if (!WinHelpW(hwnd, pszHelp, uCommand, dwData))
1643     {
1644 #if 0
1645         ShellMessageBoxW(shell32_hInstance, hwnd, MAKEINTRESOURCEW(9115),
1646                          MAKEINTRESOURCEW(9116), MB_ICONSTOP);
1647 #endif
1648         return FALSE;
1649     }
1650     return TRUE;
1651 }
1652 /*************************************************************************
1653  *  SHRunControlPanel [SHELL32.161]
1654  *
1655  */
SHRunControlPanel(_In_ LPCWSTR commandLine,_In_opt_ HWND parent)1656 BOOL WINAPI SHRunControlPanel (_In_ LPCWSTR commandLine, _In_opt_ HWND parent)
1657 {
1658 #ifdef __REACTOS__
1659     /*
1660      * TODO: Run in-process when possible, using
1661      * HKLM\Software\Microsoft\Windows\CurrentVersion\Explorer\ControlPanel\InProcCPLs
1662      * and possibly some extra rules.
1663      * See also https://docs.microsoft.com/en-us/windows/win32/api/shlobj/nf-shlobj-shruncontrolpanel
1664      * "If the specified Control Panel item is already running, SHRunControlPanel
1665      *  attempts to switch to that instance rather than opening a new instance."
1666      * This function is not supported as of Windows Vista, where it always returns FALSE.
1667      * However we need to keep it "alive" even when ReactOS is compliled as NT6+
1668      * in order to keep control panel elements launch commands.
1669      */
1670     WCHAR parameters[MAX_PATH] = L"shell32.dll,Control_RunDLL ";
1671     TRACE("(%s, %p)n", debugstr_w(commandLine), parent);
1672     wcscat(parameters, commandLine);
1673 
1674     return ((INT_PTR)ShellExecuteW(parent, L"open", L"rundll32.exe", parameters, NULL, SW_SHOWNORMAL) > 32);
1675 #else
1676 	FIXME("(%s, %p): stub\n", debugstr_w(commandLine), parent);
1677 	return FALSE;
1678 #endif
1679 }
1680 
1681 static LPUNKNOWN SHELL32_IExplorerInterface=0;
1682 /*************************************************************************
1683  * SHSetInstanceExplorer			[SHELL32.176]
1684  *
1685  * NOTES
1686  *  Sets the interface
1687  */
SHSetInstanceExplorer(LPUNKNOWN lpUnknown)1688 VOID WINAPI SHSetInstanceExplorer (LPUNKNOWN lpUnknown)
1689 {	TRACE("%p\n", lpUnknown);
1690 	SHELL32_IExplorerInterface = lpUnknown;
1691 }
1692 /*************************************************************************
1693  * SHGetInstanceExplorer			[SHELL32.@]
1694  *
1695  * NOTES
1696  *  gets the interface pointer of the explorer and a reference
1697  */
SHGetInstanceExplorer(IUnknown ** lpUnknown)1698 HRESULT WINAPI SHGetInstanceExplorer (IUnknown **lpUnknown)
1699 {	TRACE("%p\n", lpUnknown);
1700 
1701 	*lpUnknown = SHELL32_IExplorerInterface;
1702 
1703 	if (!SHELL32_IExplorerInterface)
1704 	  return E_FAIL;
1705 
1706 	IUnknown_AddRef(SHELL32_IExplorerInterface);
1707 	return S_OK;
1708 }
1709 /*************************************************************************
1710  * SHFreeUnusedLibraries			[SHELL32.123]
1711  *
1712  * Probably equivalent to CoFreeUnusedLibraries but under Windows 9x it could use
1713  * the shell32 built-in "mini-COM" without the need to load ole32.dll - see SHLoadOLE
1714  * for details
1715  *
1716  * NOTES
1717  *     exported by ordinal
1718  *
1719  * SEE ALSO
1720  *     CoFreeUnusedLibraries, SHLoadOLE
1721  */
SHFreeUnusedLibraries(void)1722 void WINAPI SHFreeUnusedLibraries (void)
1723 {
1724 	FIXME("stub\n");
1725 	CoFreeUnusedLibraries();
1726 }
1727 /*************************************************************************
1728  * DAD_AutoScroll				[SHELL32.129]
1729  *
1730  */
DAD_AutoScroll(HWND hwnd,AUTO_SCROLL_DATA * samples,const POINT * pt)1731 BOOL WINAPI DAD_AutoScroll(HWND hwnd, AUTO_SCROLL_DATA *samples, const POINT * pt)
1732 {
1733     FIXME("hwnd = %p %p %p\n",hwnd,samples,pt);
1734     return FALSE;
1735 }
1736 /*************************************************************************
1737  * DAD_DragEnter				[SHELL32.130]
1738  *
1739  */
DAD_DragEnter(HWND hwnd)1740 BOOL WINAPI DAD_DragEnter(HWND hwnd)
1741 {
1742     FIXME("hwnd = %p\n",hwnd);
1743     return FALSE;
1744 }
1745 /*************************************************************************
1746  * DAD_DragEnterEx				[SHELL32.131]
1747  *
1748  */
DAD_DragEnterEx(HWND hwnd,POINT p)1749 BOOL WINAPI DAD_DragEnterEx(HWND hwnd, POINT p)
1750 {
1751     FIXME("hwnd = %p (%d,%d)\n",hwnd,p.x,p.y);
1752     return FALSE;
1753 }
1754 /*************************************************************************
1755  * DAD_DragMove				[SHELL32.134]
1756  *
1757  */
DAD_DragMove(POINT p)1758 BOOL WINAPI DAD_DragMove(POINT p)
1759 {
1760     FIXME("(%d,%d)\n",p.x,p.y);
1761     return FALSE;
1762 }
1763 /*************************************************************************
1764  * DAD_DragLeave				[SHELL32.132]
1765  *
1766  */
DAD_DragLeave(VOID)1767 BOOL WINAPI DAD_DragLeave(VOID)
1768 {
1769     FIXME("\n");
1770     return FALSE;
1771 }
1772 /*************************************************************************
1773  * DAD_SetDragImage				[SHELL32.136]
1774  *
1775  * NOTES
1776  *  exported by name
1777  */
DAD_SetDragImage(HIMAGELIST himlTrack,LPPOINT lppt)1778 BOOL WINAPI DAD_SetDragImage(
1779 	HIMAGELIST himlTrack,
1780 	LPPOINT lppt)
1781 {
1782     FIXME("%p %p stub\n",himlTrack, lppt);
1783     return FALSE;
1784 }
1785 /*************************************************************************
1786  * DAD_ShowDragImage				[SHELL32.137]
1787  *
1788  * NOTES
1789  *  exported by name
1790  */
DAD_ShowDragImage(BOOL bShow)1791 BOOL WINAPI DAD_ShowDragImage(BOOL bShow)
1792 {
1793     FIXME("0x%08x stub\n",bShow);
1794     return FALSE;
1795 }
1796 
1797 /*************************************************************************
1798  * ReadCabinetState				[SHELL32.651] NT 4.0
1799  *
1800  */
ReadCabinetState(CABINETSTATE * cs,int length)1801 BOOL WINAPI ReadCabinetState(CABINETSTATE *cs, int length)
1802 {
1803 	HKEY hkey = 0;
1804 	DWORD type, r;
1805 	C_ASSERT(sizeof(*cs) == FIELD_OFFSET(CABINETSTATE, fMenuEnumFilter) + sizeof(UINT));
1806 
1807 	TRACE("%p %d\n", cs, length);
1808 
1809 	if( (cs == NULL) || (length < (int)sizeof(*cs))  )
1810 		return FALSE;
1811 
1812 	r = RegOpenKeyW( HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CabinetState", &hkey );
1813 	if( r == ERROR_SUCCESS )
1814 	{
1815 		type = REG_BINARY;
1816 		r = RegQueryValueExW( hkey, L"Settings",
1817 			NULL, &type, (LPBYTE)cs, (LPDWORD)&length );
1818 		RegCloseKey( hkey );
1819 
1820 	}
1821 
1822 	/* if we can't read from the registry, create default values */
1823 	if ( (r != ERROR_SUCCESS) || (cs->cLength < sizeof(*cs)) ||
1824 		(cs->cLength != length) )
1825 	{
1826 		SHELLSTATE shellstate;
1827 		shellstate.fWin95Classic = FALSE;
1828 		SHGetSetSettings(&shellstate, SSF_WIN95CLASSIC, FALSE);
1829 
1830 		TRACE("Initializing shell cabinet settings\n");
1831 		memset(cs, 0, sizeof(*cs));
1832 		cs->cLength          = sizeof(*cs);
1833 		cs->nVersion         = 2;
1834 		cs->fFullPathTitle   = FALSE;
1835 		cs->fSaveLocalView   = TRUE;
1836 		cs->fNotShell        = FALSE;
1837 		cs->fSimpleDefault   = TRUE;
1838 		cs->fDontShowDescBar = FALSE;
1839 		cs->fNewWindowMode   = shellstate.fWin95Classic;
1840 		cs->fShowCompColor   = FALSE;
1841 		cs->fDontPrettyNames = FALSE;
1842 		cs->fAdminsCreateCommonGroups = TRUE;
1843 		cs->fMenuEnumFilter  = SHCONTF_FOLDERS | SHCONTF_NONFOLDERS;
1844 	}
1845 
1846 	return TRUE;
1847 }
1848 
1849 /*************************************************************************
1850  * WriteCabinetState				[SHELL32.652] NT 4.0
1851  *
1852  */
WriteCabinetState(CABINETSTATE * cs)1853 BOOL WINAPI WriteCabinetState(CABINETSTATE *cs)
1854 {
1855 	DWORD r;
1856 	HKEY hkey = 0;
1857 
1858 	TRACE("%p\n",cs);
1859 
1860 	if( cs == NULL )
1861 		return FALSE;
1862 
1863 	r = RegCreateKeyExW( HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CabinetState", 0,
1864 		 NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1865 	if( r == ERROR_SUCCESS )
1866 	{
1867 		r = RegSetValueExW( hkey, L"Settings", 0,
1868 			REG_BINARY, (LPBYTE) cs, cs->cLength);
1869 
1870 		RegCloseKey( hkey );
1871 	}
1872 
1873 #ifdef __REACTOS__
1874 	/* TODO: if (r==ERROR_SUCCESS) Increment GLOBALCOUNTER_FOLDERSETTINGSCHANGE */
1875 #endif
1876 	return (r==ERROR_SUCCESS);
1877 }
1878 
1879 /*************************************************************************
1880  * FileIconInit 				[SHELL32.660]
1881  *
1882  */
FileIconInit(BOOL bFullInit)1883 BOOL WINAPI FileIconInit(BOOL bFullInit)
1884 {
1885     return SIC_Initialize();
1886 }
1887 
1888 /*************************************************************************
1889  * SetAppStartingCursor				[SHELL32.99]
1890  */
SetAppStartingCursor(HWND u,DWORD v)1891 HRESULT WINAPI SetAppStartingCursor(HWND u, DWORD v)
1892 {	FIXME("hwnd=%p 0x%04x stub\n",u,v );
1893 	return 0;
1894 }
1895 
1896 /*************************************************************************
1897  * SHLoadOLE					[SHELL32.151]
1898  *
1899  * To reduce the memory usage of Windows 95, its shell32 contained an
1900  * internal implementation of a part of COM (see e.g. SHGetMalloc, SHCoCreateInstance,
1901  * SHRegisterDragDrop etc.) that allowed to use in-process STA objects without
1902  * the need to load OLE32.DLL. If OLE32.DLL was already loaded, the SH* function
1903  * would just call the Co* functions.
1904  *
1905  * The SHLoadOLE was called when OLE32.DLL was being loaded to transfer all the
1906  * information from the shell32 "mini-COM" to ole32.dll.
1907  *
1908  * See http://blogs.msdn.com/oldnewthing/archive/2004/07/05/173226.aspx for a
1909  * detailed description.
1910  *
1911  * Under wine ole32.dll is always loaded as it is imported by shlwapi.dll which is
1912  * imported by shell32 and no "mini-COM" is used (except for the "LoadWithoutCOM"
1913  * hack in SHCoCreateInstance)
1914  */
SHLoadOLE(LPARAM lParam)1915 HRESULT WINAPI SHLoadOLE(LPARAM lParam)
1916 {	FIXME("0x%08lx stub\n",lParam);
1917 	return S_OK;
1918 }
1919 /*************************************************************************
1920  * DriveType					[SHELL32.64]
1921  *
1922  */
DriveType(int DriveType)1923 int WINAPI DriveType(int DriveType)
1924 {
1925     WCHAR root[] = L"A:\\";
1926     root[0] = L'A' + DriveType;
1927     return GetDriveTypeW(root);
1928 }
1929 /*************************************************************************
1930  * InvalidateDriveType            [SHELL32.65]
1931  * Unimplemented in XP SP3
1932  */
InvalidateDriveType(int u)1933 int WINAPI InvalidateDriveType(int u)
1934 {
1935     TRACE("0x%08x stub\n",u);
1936     return 0;
1937 }
1938 /*************************************************************************
1939  * SHAbortInvokeCommand				[SHELL32.198]
1940  *
1941  */
SHAbortInvokeCommand(void)1942 HRESULT WINAPI SHAbortInvokeCommand(void)
1943 {	FIXME("stub\n");
1944 	return 1;
1945 }
1946 /*************************************************************************
1947  * SHOutOfMemoryMessageBox			[SHELL32.126]
1948  *
1949  */
SHOutOfMemoryMessageBox(HWND hwndOwner,LPCSTR lpCaption,UINT uType)1950 int WINAPI SHOutOfMemoryMessageBox(
1951 	HWND hwndOwner,
1952 	LPCSTR lpCaption,
1953 	UINT uType)
1954 {
1955 	FIXME("%p %s 0x%08x stub\n",hwndOwner, lpCaption, uType);
1956 	return 0;
1957 }
1958 /*************************************************************************
1959  * SHFlushClipboard				[SHELL32.121]
1960  *
1961  */
SHFlushClipboard(void)1962 HRESULT WINAPI SHFlushClipboard(void)
1963 {
1964     return OleFlushClipboard();
1965 }
1966 
1967 /*************************************************************************
1968  * SHWaitForFileToOpen				[SHELL32.97]
1969  *
1970  */
SHWaitForFileToOpen(LPCITEMIDLIST pidl,DWORD dwFlags,DWORD dwTimeout)1971 BOOL WINAPI SHWaitForFileToOpen(
1972 	LPCITEMIDLIST pidl,
1973 	DWORD dwFlags,
1974 	DWORD dwTimeout)
1975 {
1976 	FIXME("%p 0x%08x 0x%08x stub\n", pidl, dwFlags, dwTimeout);
1977 	return FALSE;
1978 }
1979 
1980 /************************************************************************
1981  *	RLBuildListOfPaths			[SHELL32.146]
1982  *
1983  * NOTES
1984  *   builds a DPA
1985  */
RLBuildListOfPaths(void)1986 DWORD WINAPI RLBuildListOfPaths (void)
1987 {	FIXME("stub\n");
1988 	return 0;
1989 }
1990 /************************************************************************
1991  *	SHValidateUNC				[SHELL32.173]
1992  *
1993  */
SHValidateUNC(HWND hwndOwner,PWSTR pszFile,UINT fConnect)1994 BOOL WINAPI SHValidateUNC (HWND hwndOwner, PWSTR pszFile, UINT fConnect)
1995 {
1996 	FIXME("(%p, %s, 0x%08x): stub\n", hwndOwner, debugstr_w(pszFile), fConnect);
1997 	return FALSE;
1998 }
1999 
2000 /************************************************************************
2001  * DoEnvironmentSubstA [SHELL32.@]
2002  *
2003  * See DoEnvironmentSubstW.
2004  */
DoEnvironmentSubstA(LPSTR pszString,UINT cchString)2005 DWORD WINAPI DoEnvironmentSubstA(LPSTR pszString, UINT cchString)
2006 {
2007     LPSTR dst;
2008     BOOL res = FALSE;
2009     DWORD len = cchString;
2010 
2011     TRACE("(%s, %d)\n", debugstr_a(pszString), cchString);
2012     if (pszString == NULL) /* Really return 0? */
2013         return 0;
2014     if ((dst = (LPSTR)HeapAlloc(GetProcessHeap(), 0, cchString * sizeof(CHAR))))
2015     {
2016         len = ExpandEnvironmentStringsA(pszString, dst, cchString);
2017         /* len includes the terminating 0 */
2018         if (len && len < cchString)
2019         {
2020             res = TRUE;
2021             memcpy(pszString, dst, len);
2022         }
2023         else
2024             len = cchString;
2025 
2026         HeapFree(GetProcessHeap(), 0, dst);
2027     }
2028     return MAKELONG(len, res);
2029 }
2030 
2031 /************************************************************************
2032  * DoEnvironmentSubstW [SHELL32.@]
2033  *
2034  * Replace all %KEYWORD% in the string with the value of the named
2035  * environment variable. If the buffer is too small, the string is not modified.
2036  *
2037  * PARAMS
2038  *  pszString  [I] '\0' terminated string with %keyword%.
2039  *             [O] '\0' terminated string with %keyword% substituted.
2040  *  cchString  [I] size of str.
2041  *
2042  * RETURNS
2043  *  Success:  The string in the buffer is updated
2044  *            HIWORD: TRUE
2045  *            LOWORD: characters used in the buffer, including space for the terminating 0
2046  *  Failure:  buffer too small. The string is not modified.
2047  *            HIWORD: FALSE
2048  *            LOWORD: provided size of the buffer in characters
2049  */
DoEnvironmentSubstW(LPWSTR pszString,UINT cchString)2050 DWORD WINAPI DoEnvironmentSubstW(LPWSTR pszString, UINT cchString)
2051 {
2052     LPWSTR dst;
2053     BOOL res = FALSE;
2054     DWORD len = cchString;
2055 
2056     TRACE("(%s, %d)\n", debugstr_w(pszString), cchString);
2057 
2058     if ((cchString < MAXLONG) && (dst = HeapAlloc(GetProcessHeap(), 0, cchString * sizeof(WCHAR))))
2059     {
2060         len = ExpandEnvironmentStringsW(pszString, dst, cchString);
2061         /* len includes the terminating 0 */
2062         if (len && len <= cchString)
2063         {
2064             res = TRUE;
2065             memcpy(pszString, dst, len * sizeof(WCHAR));
2066         }
2067         else
2068             len = cchString;
2069 
2070         HeapFree(GetProcessHeap(), 0, dst);
2071     }
2072     return MAKELONG(len, res);
2073 }
2074 
2075 /************************************************************************
2076  *	DoEnvironmentSubst			[SHELL32.53]
2077  *
2078  * See DoEnvironmentSubstA.
2079  */
DoEnvironmentSubstAW(LPVOID x,UINT y)2080 DWORD WINAPI DoEnvironmentSubstAW(LPVOID x, UINT y)
2081 {
2082     if (SHELL_OsIsUnicode())
2083         return DoEnvironmentSubstW(x, y);
2084     return DoEnvironmentSubstA(x, y);
2085 }
2086 
2087 /*************************************************************************
2088  *      GUIDFromStringA   [SHELL32.703]
2089  */
GUIDFromStringA(LPCSTR str,LPGUID guid)2090 BOOL WINAPI GUIDFromStringA(LPCSTR str, LPGUID guid)
2091 {
2092     ANSI_STRING ansi_str;
2093     WCHAR szWide[40];
2094     UNICODE_STRING guid_str = { 0, sizeof(szWide), szWide };
2095     if (*str != '{')
2096         return FALSE;
2097     RtlInitAnsiString(&ansi_str, str);
2098     return !RtlAnsiStringToUnicodeString(&guid_str, &ansi_str, FALSE) &&
2099            !RtlGUIDFromString(&guid_str, guid);
2100 }
2101 
2102 /*************************************************************************
2103  *      GUIDFromStringW   [SHELL32.704]
2104  */
GUIDFromStringW(LPCWSTR str,LPGUID guid)2105 BOOL WINAPI GUIDFromStringW(LPCWSTR str, LPGUID guid)
2106 {
2107     UNICODE_STRING guid_str;
2108     if (!str || *str != L'{')
2109         return FALSE;
2110     RtlInitUnicodeString(&guid_str, str);
2111     return !RtlGUIDFromString(&guid_str, guid);
2112 }
2113 
2114 /*************************************************************************
2115  *      PathIsTemporaryA    [SHELL32.713]
2116  */
2117 #ifdef __REACTOS__
2118 /** @see https://undoc.airesoft.co.uk/shell32.dll/PathIsTemporaryA.php */
PathIsTemporaryA(_In_ LPCSTR Str)2119 BOOL WINAPI PathIsTemporaryA(_In_ LPCSTR Str)
2120 #else
2121 BOOL WINAPI PathIsTemporaryA(LPSTR Str)
2122 #endif
2123 {
2124 #ifdef __REACTOS__
2125     WCHAR szWide[MAX_PATH];
2126 
2127     TRACE("(%s)\n", debugstr_a(Str));
2128 
2129     SHAnsiToUnicode(Str, szWide, _countof(szWide));
2130     return PathIsTemporaryW(szWide);
2131 #else
2132     FIXME("(%s)stub\n", debugstr_a(Str));
2133     return FALSE;
2134 #endif
2135 }
2136 
2137 /*************************************************************************
2138  *      PathIsTemporaryW    [SHELL32.714]
2139  */
2140 #ifdef __REACTOS__
2141 /** @see https://undoc.airesoft.co.uk/shell32.dll/PathIsTemporaryW.php */
PathIsTemporaryW(_In_ LPCWSTR Str)2142 BOOL WINAPI PathIsTemporaryW(_In_ LPCWSTR Str)
2143 #else
2144 BOOL WINAPI PathIsTemporaryW(LPWSTR Str)
2145 #endif
2146 {
2147 #ifdef __REACTOS__
2148     WCHAR szLongPath[MAX_PATH], szTempPath[MAX_PATH];
2149     DWORD attrs;
2150     LPCWSTR pszTarget = Str;
2151 
2152     TRACE("(%s)\n", debugstr_w(Str));
2153 
2154     attrs = GetFileAttributesW(Str);
2155     if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_TEMPORARY))
2156         return TRUE;
2157 
2158     if (!GetTempPathW(_countof(szTempPath), szTempPath) ||
2159         !GetLongPathNameW(szTempPath, szTempPath, _countof(szTempPath)))
2160     {
2161         return FALSE;
2162     }
2163 
2164     if (GetLongPathNameW(Str, szLongPath, _countof(szLongPath)))
2165         pszTarget = szLongPath;
2166 
2167     return (PathIsEqualOrSubFolder(szTempPath, pszTarget) ||
2168             PathIsEqualOrSubFolder(UlongToPtr(CSIDL_INTERNET_CACHE), pszTarget) ||
2169             PathIsEqualOrSubFolder(UlongToPtr(CSIDL_CDBURN_AREA), pszTarget));
2170 #else
2171     FIXME("(%s)stub\n", debugstr_w(Str));
2172     return FALSE;
2173 #endif
2174 }
2175 
2176 typedef struct _PSXA
2177 {
2178     UINT uiCount;
2179     UINT uiAllocated;
2180     IShellPropSheetExt *pspsx[1];
2181 } PSXA, *PPSXA;
2182 
2183 typedef struct _PSXA_CALL
2184 {
2185     LPFNADDPROPSHEETPAGE lpfnAddReplaceWith;
2186     LPARAM lParam;
2187     BOOL bCalled;
2188     BOOL bMultiple;
2189     UINT uiCount;
2190 } PSXA_CALL, *PPSXA_CALL;
2191 
PsxaCall(HPROPSHEETPAGE hpage,LPARAM lParam)2192 static BOOL CALLBACK PsxaCall(HPROPSHEETPAGE hpage, LPARAM lParam)
2193 {
2194     PPSXA_CALL Call = (PPSXA_CALL)lParam;
2195 
2196     if (Call != NULL)
2197     {
2198         if ((Call->bMultiple || !Call->bCalled) &&
2199             Call->lpfnAddReplaceWith(hpage, Call->lParam))
2200         {
2201             Call->bCalled = TRUE;
2202             Call->uiCount++;
2203             return TRUE;
2204         }
2205     }
2206 
2207     return FALSE;
2208 }
2209 
2210 /*************************************************************************
2211  *      SHAddFromPropSheetExtArray	[SHELL32.167]
2212  */
SHAddFromPropSheetExtArray(HPSXA hpsxa,LPFNADDPROPSHEETPAGE lpfnAddPage,LPARAM lParam)2213 UINT WINAPI SHAddFromPropSheetExtArray(HPSXA hpsxa, LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam)
2214 {
2215     PSXA_CALL Call;
2216     UINT i;
2217     PPSXA psxa = (PPSXA)hpsxa;
2218 
2219     TRACE("(%p,%p,%08lx)\n", hpsxa, lpfnAddPage, lParam);
2220 
2221     if (psxa)
2222     {
2223         ZeroMemory(&Call, sizeof(Call));
2224         Call.lpfnAddReplaceWith = lpfnAddPage;
2225         Call.lParam = lParam;
2226         Call.bMultiple = TRUE;
2227 
2228         /* Call the AddPage method of all registered IShellPropSheetExt interfaces */
2229         for (i = 0; i != psxa->uiCount; i++)
2230         {
2231             psxa->pspsx[i]->lpVtbl->AddPages(psxa->pspsx[i], PsxaCall, (LPARAM)&Call);
2232         }
2233 
2234         return Call.uiCount;
2235     }
2236 
2237     return 0;
2238 }
2239 
2240 /*************************************************************************
2241  *      SHCreatePropSheetExtArray	[SHELL32.168]
2242  */
SHCreatePropSheetExtArray(HKEY hKey,LPCWSTR pszSubKey,UINT max_iface)2243 HPSXA WINAPI SHCreatePropSheetExtArray(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface)
2244 {
2245     return SHCreatePropSheetExtArrayEx(hKey, pszSubKey, max_iface, NULL);
2246 }
2247 
2248 /*************************************************************************
2249  *      SHCreatePropSheetExtArrayEx	[SHELL32.194]
2250  */
SHCreatePropSheetExtArrayEx(HKEY hKey,LPCWSTR pszSubKey,UINT max_iface,LPDATAOBJECT pDataObj)2251 HPSXA WINAPI SHCreatePropSheetExtArrayEx(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface, LPDATAOBJECT pDataObj)
2252 {
2253     WCHAR szHandler[64];
2254     DWORD dwHandlerLen;
2255     WCHAR szClsidHandler[39];
2256     DWORD dwClsidSize;
2257     CLSID clsid;
2258     LONG lRet;
2259     DWORD dwIndex;
2260     IShellExtInit *psxi;
2261     IShellPropSheetExt *pspsx;
2262     HKEY hkBase, hkPropSheetHandlers;
2263     PPSXA psxa = NULL;
2264 
2265     TRACE("(%p,%s,%u)\n", hKey, debugstr_w(pszSubKey), max_iface);
2266 
2267     if (max_iface == 0)
2268         return NULL;
2269 
2270     /* Open the registry key */
2271     lRet = RegOpenKeyW(hKey, pszSubKey, &hkBase);
2272     if (lRet != ERROR_SUCCESS)
2273         return NULL;
2274 
2275     lRet = RegOpenKeyExW(hkBase, L"shellex\\PropertySheetHandlers", 0, KEY_ENUMERATE_SUB_KEYS, &hkPropSheetHandlers);
2276     RegCloseKey(hkBase);
2277     if (lRet == ERROR_SUCCESS)
2278     {
2279         /* Create and initialize the Property Sheet Extensions Array */
2280         psxa = LocalAlloc(LMEM_FIXED, FIELD_OFFSET(PSXA, pspsx[max_iface]));
2281         if (psxa)
2282         {
2283             ZeroMemory(psxa, FIELD_OFFSET(PSXA, pspsx[max_iface]));
2284             psxa->uiAllocated = max_iface;
2285 
2286             /* Enumerate all subkeys and attempt to load the shell extensions */
2287             dwIndex = 0;
2288             do
2289             {
2290                 dwHandlerLen = sizeof(szHandler) / sizeof(szHandler[0]);
2291                 lRet = RegEnumKeyExW(hkPropSheetHandlers, dwIndex++, szHandler, &dwHandlerLen, NULL, NULL, NULL, NULL);
2292                 if (lRet != ERROR_SUCCESS)
2293                 {
2294                     if (lRet == ERROR_MORE_DATA)
2295                         continue;
2296 
2297                     if (lRet == ERROR_NO_MORE_ITEMS)
2298                         lRet = ERROR_SUCCESS;
2299                     break;
2300                 }
2301 
2302                 /* The CLSID is stored either in the key itself or in its default value. */
2303                 if (FAILED(lRet = SHCLSIDFromStringW(szHandler, &clsid)))
2304                 {
2305                     dwClsidSize = sizeof(szClsidHandler);
2306                     if (SHGetValueW(hkPropSheetHandlers, szHandler, NULL, NULL, szClsidHandler, &dwClsidSize) == ERROR_SUCCESS)
2307                     {
2308                         /* Force a NULL-termination and convert the string */
2309                         szClsidHandler[(sizeof(szClsidHandler) / sizeof(szClsidHandler[0])) - 1] = 0;
2310                         lRet = SHCLSIDFromStringW(szClsidHandler, &clsid);
2311                     }
2312                 }
2313 
2314                 if (SUCCEEDED(lRet))
2315                 {
2316                     /* Attempt to get an IShellPropSheetExt and an IShellExtInit instance.
2317                        Only if both interfaces are supported it's a real shell extension.
2318                        Then call IShellExtInit's Initialize method. */
2319                     if (SUCCEEDED(CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER/* | CLSCTX_NO_CODE_DOWNLOAD */, &IID_IShellPropSheetExt, (LPVOID *)&pspsx)))
2320                     {
2321                         if (SUCCEEDED(pspsx->lpVtbl->QueryInterface(pspsx, &IID_IShellExtInit, (PVOID *)&psxi)))
2322                         {
2323                             if (SUCCEEDED(psxi->lpVtbl->Initialize(psxi, NULL, pDataObj, hKey)))
2324                             {
2325                                 /* Add the IShellPropSheetExt instance to the array */
2326                                 psxa->pspsx[psxa->uiCount++] = pspsx;
2327                             }
2328                             else
2329                             {
2330                                 psxi->lpVtbl->Release(psxi);
2331                                 pspsx->lpVtbl->Release(pspsx);
2332                             }
2333                         }
2334                         else
2335                             pspsx->lpVtbl->Release(pspsx);
2336                     }
2337                 }
2338 
2339             } while (psxa->uiCount != psxa->uiAllocated);
2340         }
2341         else
2342             lRet = ERROR_NOT_ENOUGH_MEMORY;
2343 
2344         RegCloseKey(hkPropSheetHandlers);
2345     }
2346 
2347     if (lRet != ERROR_SUCCESS && psxa)
2348     {
2349         SHDestroyPropSheetExtArray((HPSXA)psxa);
2350         psxa = NULL;
2351     }
2352 
2353     return (HPSXA)psxa;
2354 }
2355 
2356 /*************************************************************************
2357  *      SHReplaceFromPropSheetExtArray	[SHELL32.170]
2358  */
SHReplaceFromPropSheetExtArray(HPSXA hpsxa,UINT uPageID,LPFNADDPROPSHEETPAGE lpfnReplaceWith,LPARAM lParam)2359 UINT WINAPI SHReplaceFromPropSheetExtArray(HPSXA hpsxa, UINT uPageID, LPFNADDPROPSHEETPAGE lpfnReplaceWith, LPARAM lParam)
2360 {
2361     PSXA_CALL Call;
2362     UINT i;
2363     PPSXA psxa = (PPSXA)hpsxa;
2364 
2365     TRACE("(%p,%u,%p,%08lx)\n", hpsxa, uPageID, lpfnReplaceWith, lParam);
2366 
2367     if (psxa)
2368     {
2369         ZeroMemory(&Call, sizeof(Call));
2370         Call.lpfnAddReplaceWith = lpfnReplaceWith;
2371         Call.lParam = lParam;
2372 
2373         /* Call the ReplacePage method of all registered IShellPropSheetExt interfaces.
2374            Each shell extension is only allowed to call the callback once during the callback. */
2375         for (i = 0; i != psxa->uiCount; i++)
2376         {
2377             Call.bCalled = FALSE;
2378             psxa->pspsx[i]->lpVtbl->ReplacePage(psxa->pspsx[i], uPageID, PsxaCall, (LPARAM)&Call);
2379         }
2380 
2381         return Call.uiCount;
2382     }
2383 
2384     return 0;
2385 }
2386 
2387 /*************************************************************************
2388  *      SHDestroyPropSheetExtArray	[SHELL32.169]
2389  */
SHDestroyPropSheetExtArray(HPSXA hpsxa)2390 void WINAPI SHDestroyPropSheetExtArray(HPSXA hpsxa)
2391 {
2392     UINT i;
2393     PPSXA psxa = (PPSXA)hpsxa;
2394 
2395     TRACE("(%p)\n", hpsxa);
2396 
2397     if (psxa)
2398     {
2399         for (i = 0; i != psxa->uiCount; i++)
2400         {
2401             psxa->pspsx[i]->lpVtbl->Release(psxa->pspsx[i]);
2402         }
2403 
2404         LocalFree(psxa);
2405     }
2406 }
2407 
2408 /*************************************************************************
2409  *      CIDLData_CreateFromIDArray	[SHELL32.83]
2410  *
2411  *  Create IDataObject from PIDLs??
2412  */
CIDLData_CreateFromIDArray(PCIDLIST_ABSOLUTE pidlFolder,UINT cpidlFiles,PCUIDLIST_RELATIVE_ARRAY lppidlFiles,LPDATAOBJECT * ppdataObject)2413 HRESULT WINAPI CIDLData_CreateFromIDArray(
2414 	PCIDLIST_ABSOLUTE pidlFolder,
2415     UINT cpidlFiles,
2416 	PCUIDLIST_RELATIVE_ARRAY lppidlFiles,
2417 	LPDATAOBJECT *ppdataObject)
2418 {
2419     UINT i;
2420     HWND hwnd = 0;   /*FIXME: who should be hwnd of owner? set to desktop */
2421     HRESULT hResult;
2422 
2423     TRACE("(%p, %d, %p, %p)\n", pidlFolder, cpidlFiles, lppidlFiles, ppdataObject);
2424     if (TRACE_ON(pidl))
2425     {
2426 	pdump (pidlFolder);
2427 	for (i=0; i<cpidlFiles; i++) pdump (lppidlFiles[i]);
2428     }
2429     hResult = IDataObject_Constructor(hwnd, pidlFolder, lppidlFiles, cpidlFiles, FALSE, ppdataObject);
2430     return hResult;
2431 }
2432 
2433 /*************************************************************************
2434  * SHCreateStdEnumFmtEtc			[SHELL32.74]
2435  *
2436  * NOTES
2437  *
2438  */
SHCreateStdEnumFmtEtc(UINT cFormats,const FORMATETC * lpFormats,LPENUMFORMATETC * ppenumFormatetc)2439 HRESULT WINAPI SHCreateStdEnumFmtEtc(
2440     UINT cFormats,
2441 	const FORMATETC *lpFormats,
2442 	LPENUMFORMATETC *ppenumFormatetc)
2443 {
2444 	IEnumFORMATETC *pef;
2445 	HRESULT hRes;
2446 	TRACE("cf=%d fe=%p pef=%p\n", cFormats, lpFormats, ppenumFormatetc);
2447 
2448     hRes = IEnumFORMATETC_Constructor(cFormats, lpFormats, &pef);
2449     if (FAILED(hRes))
2450         return hRes;
2451 
2452 	IEnumFORMATETC_AddRef(pef);
2453 	hRes = IEnumFORMATETC_QueryInterface(pef, &IID_IEnumFORMATETC, (LPVOID*)ppenumFormatetc);
2454 	IEnumFORMATETC_Release(pef);
2455 
2456 	return hRes;
2457 }
2458 
2459 /*************************************************************************
2460  *		SHFindFiles (SHELL32.90)
2461  */
SHFindFiles(PCIDLIST_ABSOLUTE pidlFolder,PCIDLIST_ABSOLUTE pidlSaveFile)2462 BOOL WINAPI SHFindFiles( PCIDLIST_ABSOLUTE pidlFolder, PCIDLIST_ABSOLUTE pidlSaveFile )
2463 {
2464     FIXME("params ignored: %p %p\n", pidlFolder, pidlSaveFile);
2465     if (SHRestricted(REST_NOFIND))
2466     {
2467         return FALSE;
2468     }
2469     /* Open the search results folder */
2470     /* FIXME: CSearchBar should be opened as well */
2471     return ShellExecuteW(NULL, NULL, L"explorer.exe", L"::{E17D4FC0-5564-11D1-83F2-00A0C90DC849}", NULL, SW_SHOWNORMAL) > (HINSTANCE)32;
2472 }
2473 
2474 /*************************************************************************
2475  *		SHUpdateImageW (SHELL32.192)
2476  *
2477  * Notifies the shell that an icon in the system image list has been changed.
2478  *
2479  * PARAMS
2480  *  pszHashItem [I] Path to file that contains the icon.
2481  *  iIndex      [I] Zero-based index of the icon in the file.
2482  *  uFlags      [I] Flags determining the icon attributes. See notes.
2483  *  iImageIndex [I] Index of the icon in the system image list.
2484  *
2485  * RETURNS
2486  *  Nothing
2487  *
2488  * NOTES
2489  *  uFlags can be one or more of the following flags:
2490  *  GIL_NOTFILENAME - pszHashItem is not a file name.
2491  *  GIL_SIMULATEDOC - Create a document icon using the specified icon.
2492  */
SHUpdateImageW(LPCWSTR pszHashItem,int iIndex,UINT uFlags,int iImageIndex)2493 void WINAPI SHUpdateImageW(LPCWSTR pszHashItem, int iIndex, UINT uFlags, int iImageIndex)
2494 {
2495     FIXME("%s, %d, 0x%x, %d - stub\n", debugstr_w(pszHashItem), iIndex, uFlags, iImageIndex);
2496 }
2497 
2498 /*************************************************************************
2499  *		SHUpdateImageA (SHELL32.191)
2500  *
2501  * See SHUpdateImageW.
2502  */
SHUpdateImageA(LPCSTR pszHashItem,INT iIndex,UINT uFlags,INT iImageIndex)2503 VOID WINAPI SHUpdateImageA(LPCSTR pszHashItem, INT iIndex, UINT uFlags, INT iImageIndex)
2504 {
2505     FIXME("%s, %d, 0x%x, %d - stub\n", debugstr_a(pszHashItem), iIndex, uFlags, iImageIndex);
2506 }
2507 
SHHandleUpdateImage(PCIDLIST_ABSOLUTE pidlExtra)2508 INT WINAPI SHHandleUpdateImage(PCIDLIST_ABSOLUTE pidlExtra)
2509 {
2510     FIXME("%p - stub\n", pidlExtra);
2511 
2512     return -1;
2513 }
2514 
SHObjectProperties(HWND hwnd,DWORD dwType,LPCWSTR szObject,LPCWSTR szPage)2515 BOOL WINAPI SHObjectProperties(HWND hwnd, DWORD dwType, LPCWSTR szObject, LPCWSTR szPage)
2516 {
2517     LPITEMIDLIST pidl = NULL;
2518     switch (dwType)
2519     {
2520         case SHOP_FILEPATH:
2521             pidl = ILCreateFromPathW(szObject);
2522             break;
2523     }
2524     if (pidl)
2525     {
2526         SHELLEXECUTEINFOW sei = { sizeof(sei), SEE_MASK_INVOKEIDLIST, hwnd, L"properties",
2527                                   NULL, szPage, NULL, SW_SHOWNORMAL, NULL, pidl };
2528         BOOL result = ShellExecuteExW(&sei);
2529         ILFree(pidl);
2530         return result;
2531     }
2532 
2533     FIXME("%p, 0x%08x, %s, %s - stub\n", hwnd, dwType, debugstr_w(szObject), debugstr_w(szPage));
2534 
2535     return TRUE;
2536 }
2537 
SHGetNewLinkInfoA(LPCSTR pszLinkTo,LPCSTR pszDir,LPSTR pszName,BOOL * pfMustCopy,UINT uFlags)2538 BOOL WINAPI SHGetNewLinkInfoA(LPCSTR pszLinkTo, LPCSTR pszDir, LPSTR pszName, BOOL *pfMustCopy,
2539                               UINT uFlags)
2540 {
2541     WCHAR wszLinkTo[MAX_PATH];
2542     WCHAR wszDir[MAX_PATH];
2543     WCHAR wszName[MAX_PATH];
2544     BOOL res;
2545 
2546     MultiByteToWideChar(CP_ACP, 0, pszLinkTo, -1, wszLinkTo, MAX_PATH);
2547     MultiByteToWideChar(CP_ACP, 0, pszDir, -1, wszDir, MAX_PATH);
2548 
2549     res = SHGetNewLinkInfoW(wszLinkTo, wszDir, wszName, pfMustCopy, uFlags);
2550 
2551     if (res)
2552         WideCharToMultiByte(CP_ACP, 0, wszName, -1, pszName, MAX_PATH, NULL, NULL);
2553 
2554     return res;
2555 }
2556 
SHGetNewLinkInfoW(LPCWSTR pszLinkTo,LPCWSTR pszDir,LPWSTR pszName,BOOL * pfMustCopy,UINT uFlags)2557 BOOL WINAPI SHGetNewLinkInfoW(LPCWSTR pszLinkTo, LPCWSTR pszDir, LPWSTR pszName, BOOL *pfMustCopy,
2558                               UINT uFlags)
2559 {
2560     const WCHAR *basename;
2561     WCHAR *dst_basename;
2562     int i=2;
2563 
2564     TRACE("(%s, %s, %p, %p, 0x%08x)\n", debugstr_w(pszLinkTo), debugstr_w(pszDir),
2565           pszName, pfMustCopy, uFlags);
2566 
2567     *pfMustCopy = FALSE;
2568 
2569     if (uFlags & SHGNLI_PIDL)
2570     {
2571         FIXME("SHGNLI_PIDL flag unsupported\n");
2572         return FALSE;
2573     }
2574 
2575     if (uFlags)
2576         FIXME("ignoring flags: 0x%08x\n", uFlags);
2577 
2578     /* FIXME: should test if the file is a shortcut or DOS program */
2579     if (GetFileAttributesW(pszLinkTo) == INVALID_FILE_ATTRIBUTES)
2580         return FALSE;
2581 
2582     basename = strrchrW(pszLinkTo, '\\');
2583     if (basename)
2584         basename = basename+1;
2585     else
2586         basename = pszLinkTo;
2587 
2588     lstrcpynW(pszName, pszDir, MAX_PATH);
2589     if (!PathAddBackslashW(pszName))
2590         return FALSE;
2591 
2592     dst_basename = pszName + strlenW(pszName);
2593 
2594     snprintfW(dst_basename, pszName + MAX_PATH - dst_basename, L"%s.lnk", basename);
2595 
2596     while (GetFileAttributesW(pszName) != INVALID_FILE_ATTRIBUTES)
2597     {
2598         snprintfW(dst_basename, pszName + MAX_PATH - dst_basename, L"%s (%d).lnk", basename, i);
2599         i++;
2600     }
2601 
2602     return TRUE;
2603 }
2604 
SHStartNetConnectionDialog(HWND hwnd,LPCSTR pszRemoteName,DWORD dwType)2605 HRESULT WINAPI SHStartNetConnectionDialog(HWND hwnd, LPCSTR pszRemoteName, DWORD dwType)
2606 {
2607 #ifdef __REACTOS__
2608     if (SHELL_OsIsUnicode())
2609         return SHStartNetConnectionDialogW(hwnd, (LPCWSTR)pszRemoteName, dwType);
2610     return SHStartNetConnectionDialogA(hwnd, pszRemoteName, dwType);
2611 #else
2612     FIXME("%p, %s, 0x%08x - stub\n", hwnd, debugstr_a(pszRemoteName), dwType);
2613 
2614     return S_OK;
2615 #endif
2616 }
2617 /*************************************************************************
2618  *              SHSetLocalizedName (SHELL32.@)
2619  */
SHSetLocalizedName(LPCWSTR pszPath,LPCWSTR pszResModule,int idsRes)2620 HRESULT WINAPI SHSetLocalizedName(LPCWSTR pszPath, LPCWSTR pszResModule, int idsRes)
2621 {
2622     FIXME("%p, %s, %d - stub\n", pszPath, debugstr_w(pszResModule), idsRes);
2623 
2624     return S_OK;
2625 }
2626 
2627 /*************************************************************************
2628  *              LinkWindow_RegisterClass (SHELL32.258)
2629  */
LinkWindow_RegisterClass(void)2630 BOOL WINAPI LinkWindow_RegisterClass(void)
2631 {
2632     FIXME("()\n");
2633     return TRUE;
2634 }
2635 
2636 /*************************************************************************
2637  *              LinkWindow_UnregisterClass (SHELL32.259)
2638  */
LinkWindow_UnregisterClass(DWORD dwUnused)2639 BOOL WINAPI LinkWindow_UnregisterClass(DWORD dwUnused)
2640 {
2641     FIXME("()\n");
2642     return TRUE;
2643 }
2644 
2645 /*************************************************************************
2646  *              SHFlushSFCache (SHELL32.526)
2647  *
2648  * Notifies the shell that a user-specified special folder location has changed.
2649  *
2650  * NOTES
2651  *   In Wine, the shell folder registry values are not cached, so this function
2652  *   has no effect.
2653  */
SHFlushSFCache(void)2654 void WINAPI SHFlushSFCache(void)
2655 {
2656 }
2657 
2658 /*************************************************************************
2659  *              SHGetImageList (SHELL32.727)
2660  *
2661  * Returns a copy of a shell image list.
2662  *
2663  * NOTES
2664  *   Windows XP features 4 sizes of image list, and Vista 5. Wine currently
2665  *   only supports the traditional small and large image lists, so requests
2666  *   for the others will currently fail.
2667  */
SHGetImageList(int iImageList,REFIID riid,void ** ppv)2668 HRESULT WINAPI SHGetImageList(int iImageList, REFIID riid, void **ppv)
2669 {
2670     HIMAGELIST hLarge, hSmall;
2671     HIMAGELIST hNew;
2672     HRESULT ret = E_FAIL;
2673 
2674     /* Wine currently only maintains large and small image lists */
2675     if ((iImageList != SHIL_LARGE) && (iImageList != SHIL_SMALL) && (iImageList != SHIL_SYSSMALL))
2676     {
2677         FIXME("Unsupported image list %i requested\n", iImageList);
2678         return E_FAIL;
2679     }
2680 
2681     Shell_GetImageLists(&hLarge, &hSmall);
2682 #ifndef __REACTOS__
2683     hNew = ImageList_Duplicate(iImageList == SHIL_LARGE ? hLarge : hSmall);
2684 
2685     /* Get the interface for the new image list */
2686     if (hNew)
2687     {
2688         ret = HIMAGELIST_QueryInterface(hNew, riid, ppv);
2689         ImageList_Destroy(hNew);
2690     }
2691 #else
2692     /* Duplicating the imagelist causes the start menu items not to draw on
2693      * the first show. Was the Duplicate necessary for some reason? I believe
2694      * Windows returns the raw pointer here. */
2695     hNew = (iImageList == SHIL_LARGE ? hLarge : hSmall);
2696     ret = IImageList2_QueryInterface((IImageList2 *) hNew, riid, ppv);
2697 #endif
2698 
2699     return ret;
2700 }
2701 
2702 #ifndef __REACTOS__
2703 
2704 /*************************************************************************
2705  * SHCreateShellFolderView			[SHELL32.256]
2706  *
2707  * Create a new instance of the default Shell folder view object.
2708  *
2709  * RETURNS
2710  *  Success: S_OK
2711  *  Failure: error value
2712  *
2713  * NOTES
2714  *  see IShellFolder::CreateViewObject
2715  */
SHCreateShellFolderView(const SFV_CREATE * pcsfv,IShellView ** ppsv)2716 HRESULT WINAPI SHCreateShellFolderView(const SFV_CREATE *pcsfv,
2717                         IShellView **ppsv)
2718 {
2719 	IShellView * psf;
2720 	HRESULT hRes;
2721 
2722 	*ppsv = NULL;
2723 	if (!pcsfv || pcsfv->cbSize != sizeof(*pcsfv))
2724 	  return E_INVALIDARG;
2725 
2726 	TRACE("sf=%p outer=%p callback=%p\n",
2727 	  pcsfv->pshf, pcsfv->psvOuter, pcsfv->psfvcb);
2728 
2729     hRes = IShellView_Constructor(pcsfv->pshf, &psf);
2730     if (FAILED(hRes))
2731         return hRes;
2732 
2733 	hRes = IShellView_QueryInterface(psf, &IID_IShellView, (LPVOID *)ppsv);
2734 	IShellView_Release(psf);
2735 
2736 	return hRes;
2737 }
2738 #endif
2739 
2740 
2741 /*************************************************************************
2742  * SHTestTokenMembership    [SHELL32.245]
2743  *
2744  * Checks whether a given token is a mamber of a local group with the
2745  * specified RID.
2746  *
2747  */
2748 EXTERN_C BOOL
2749 WINAPI
SHTestTokenMembership(HANDLE TokenHandle,ULONG ulRID)2750 SHTestTokenMembership(HANDLE TokenHandle, ULONG ulRID)
2751 {
2752     SID_IDENTIFIER_AUTHORITY ntAuth = {SECURITY_NT_AUTHORITY};
2753     DWORD nSubAuthority0, nSubAuthority1;
2754     DWORD nSubAuthorityCount;
2755     PSID SidToCheck;
2756     BOOL IsMember = FALSE;
2757 
2758     if ((ulRID == SECURITY_SERVICE_RID) || ulRID == SECURITY_LOCAL_SYSTEM_RID)
2759     {
2760         nSubAuthority0 = ulRID;
2761         nSubAuthority1 = 0;
2762         nSubAuthorityCount= 1;
2763     }
2764     else
2765     {
2766         nSubAuthority0 = SECURITY_BUILTIN_DOMAIN_RID;
2767         nSubAuthority1 = ulRID;
2768         nSubAuthorityCount= 2;
2769     }
2770 
2771     if (!AllocateAndInitializeSid(&ntAuth,
2772                                   nSubAuthorityCount,
2773                                   nSubAuthority0,
2774                                   nSubAuthority1,
2775                                   0, 0, 0, 0, 0, 0,
2776                                   &SidToCheck))
2777     {
2778         return FALSE;
2779     }
2780 
2781     if (!CheckTokenMembership(TokenHandle, SidToCheck, &IsMember))
2782     {
2783         IsMember = FALSE;
2784     }
2785 
2786     FreeSid(SidToCheck);
2787     return IsMember;
2788 }
2789 
2790 /*************************************************************************
2791  * IsUserAnAdmin    [SHELL32.680] NT 4.0
2792  *
2793  * Checks whether the current user is a member of the Administrators group.
2794  *
2795  * PARAMS
2796  *     None
2797  *
2798  * RETURNS
2799  *     Success: TRUE
2800  *     Failure: FALSE
2801  */
IsUserAnAdmin(VOID)2802 BOOL WINAPI IsUserAnAdmin(VOID)
2803 {
2804     return SHTestTokenMembership(NULL, DOMAIN_ALIAS_RID_ADMINS);
2805 }
2806 
2807 /*************************************************************************
2808  *              SHLimitInputEdit(SHELL32.@)
2809  */
2810 
2811 /* TODO: Show baloon popup window with TTS_BALLOON */
2812 
2813 typedef struct UxSubclassInfo
2814 {
2815     HWND hwnd;
2816     WNDPROC fnWndProc;
2817     LPWSTR pwszValidChars;
2818     LPWSTR pwszInvalidChars;
2819 } UxSubclassInfo;
2820 
2821 static void
UxSubclassInfo_Destroy(UxSubclassInfo * pInfo)2822 UxSubclassInfo_Destroy(UxSubclassInfo *pInfo)
2823 {
2824     if (!pInfo)
2825         return;
2826 
2827     RemovePropW(pInfo->hwnd, L"UxSubclassInfo");
2828 
2829     CoTaskMemFree(pInfo->pwszValidChars);
2830     CoTaskMemFree(pInfo->pwszInvalidChars);
2831 
2832     SetWindowLongPtrW(pInfo->hwnd, GWLP_WNDPROC, (LONG_PTR)pInfo->fnWndProc);
2833 
2834     HeapFree(GetProcessHeap(), 0, pInfo);
2835 }
2836 
2837 static BOOL
DoSanitizeText(LPWSTR pszSanitized,LPCWSTR pszInvalidChars,LPCWSTR pszValidChars)2838 DoSanitizeText(LPWSTR pszSanitized, LPCWSTR pszInvalidChars, LPCWSTR pszValidChars)
2839 {
2840     LPWSTR pch1, pch2;
2841     BOOL bFound = FALSE;
2842 
2843     for (pch1 = pch2 = pszSanitized; *pch1; ++pch1)
2844     {
2845         if (pszInvalidChars)
2846         {
2847             if (wcschr(pszInvalidChars, *pch1) != NULL)
2848             {
2849                 bFound = TRUE;
2850                 continue;
2851             }
2852         }
2853         else if (pszValidChars)
2854         {
2855             if (wcschr(pszValidChars, *pch1) == NULL)
2856             {
2857                 bFound = TRUE;
2858                 continue;
2859             }
2860         }
2861 
2862         *pch2 = *pch1;
2863         ++pch2;
2864     }
2865     *pch2 = 0;
2866 
2867     return bFound;
2868 }
2869 
2870 static void
DoSanitizeClipboard(HWND hwnd,UxSubclassInfo * pInfo)2871 DoSanitizeClipboard(HWND hwnd, UxSubclassInfo *pInfo)
2872 {
2873     HGLOBAL hData;
2874     LPWSTR pszText, pszSanitized;
2875     DWORD cbData;
2876 
2877     if (GetWindowLongPtrW(hwnd, GWL_STYLE) & ES_READONLY)
2878         return;
2879     if (!OpenClipboard(hwnd))
2880         return;
2881 
2882     hData = GetClipboardData(CF_UNICODETEXT);
2883     pszText = GlobalLock(hData);
2884     if (!pszText)
2885     {
2886         CloseClipboard();
2887         return;
2888     }
2889     SHStrDupW(pszText, &pszSanitized);
2890     GlobalUnlock(hData);
2891 
2892     if (pszSanitized &&
2893         DoSanitizeText(pszSanitized, pInfo->pwszInvalidChars, pInfo->pwszValidChars))
2894     {
2895         MessageBeep(0xFFFFFFFF);
2896 
2897         /* Update clipboard text */
2898         cbData = (lstrlenW(pszSanitized) + 1) * sizeof(WCHAR);
2899         hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, cbData);
2900         pszText = GlobalLock(hData);
2901         if (pszText)
2902         {
2903             CopyMemory(pszText, pszSanitized, cbData);
2904             GlobalUnlock(hData);
2905 
2906             SetClipboardData(CF_UNICODETEXT, hData);
2907         }
2908     }
2909 
2910     CoTaskMemFree(pszSanitized);
2911     CloseClipboard();
2912 }
2913 
2914 static LRESULT CALLBACK
LimitEditWindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)2915 LimitEditWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2916 {
2917     WNDPROC fnWndProc;
2918     WCHAR wch;
2919     UxSubclassInfo *pInfo = GetPropW(hwnd, L"UxSubclassInfo");
2920     if (!pInfo)
2921         return DefWindowProcW(hwnd, uMsg, wParam, lParam);
2922 
2923     fnWndProc = pInfo->fnWndProc;
2924 
2925     switch (uMsg)
2926     {
2927         case WM_KEYDOWN:
2928             if (GetKeyState(VK_SHIFT) < 0 && wParam == VK_INSERT)
2929                 DoSanitizeClipboard(hwnd, pInfo);
2930             else if (GetKeyState(VK_CONTROL) < 0 && wParam == L'V')
2931                 DoSanitizeClipboard(hwnd, pInfo);
2932 
2933             return CallWindowProcW(fnWndProc, hwnd, uMsg, wParam, lParam);
2934 
2935         case WM_PASTE:
2936             DoSanitizeClipboard(hwnd, pInfo);
2937             return CallWindowProcW(fnWndProc, hwnd, uMsg, wParam, lParam);
2938 
2939         case WM_CHAR:
2940             if (GetKeyState(VK_CONTROL) < 0 && wParam == L'V')
2941                 break;
2942 
2943             if (pInfo->pwszInvalidChars)
2944             {
2945                 if (wcschr(pInfo->pwszInvalidChars, (WCHAR)wParam) != NULL)
2946                 {
2947                     MessageBeep(0xFFFFFFFF);
2948                     break;
2949                 }
2950             }
2951             else if (pInfo->pwszValidChars)
2952             {
2953                 if (wcschr(pInfo->pwszValidChars, (WCHAR)wParam) == NULL)
2954                 {
2955                     MessageBeep(0xFFFFFFFF);
2956                     break;
2957                 }
2958             }
2959             return CallWindowProcW(fnWndProc, hwnd, uMsg, wParam, lParam);
2960 
2961         case WM_UNICHAR:
2962             if (wParam == UNICODE_NOCHAR)
2963                 return TRUE;
2964 
2965             /* FALL THROUGH */
2966 
2967         case WM_IME_CHAR:
2968             wch = (WCHAR)wParam;
2969             if (GetKeyState(VK_CONTROL) < 0 && wch == L'V')
2970                 break;
2971 
2972             if (!IsWindowUnicode(hwnd) && HIBYTE(wch) != 0)
2973             {
2974                 CHAR data[] = {HIBYTE(wch), LOBYTE(wch)};
2975                 MultiByteToWideChar(CP_ACP, 0, data, 2, &wch, 1);
2976             }
2977 
2978             if (pInfo->pwszInvalidChars)
2979             {
2980                 if (wcschr(pInfo->pwszInvalidChars, wch) != NULL)
2981                 {
2982                     MessageBeep(0xFFFFFFFF);
2983                     break;
2984                 }
2985             }
2986             else if (pInfo->pwszValidChars)
2987             {
2988                 if (wcschr(pInfo->pwszValidChars, wch) == NULL)
2989                 {
2990                     MessageBeep(0xFFFFFFFF);
2991                     break;
2992                 }
2993             }
2994             return CallWindowProcW(fnWndProc, hwnd, uMsg, wParam, lParam);
2995 
2996         case WM_NCDESTROY:
2997             UxSubclassInfo_Destroy(pInfo);
2998             return CallWindowProcW(fnWndProc, hwnd, uMsg, wParam, lParam);
2999 
3000         default:
3001             return CallWindowProcW(fnWndProc, hwnd, uMsg, wParam, lParam);
3002     }
3003 
3004     return 0;
3005 }
3006 
3007 static UxSubclassInfo *
UxSubclassInfo_Create(HWND hwnd,LPWSTR valid,LPWSTR invalid)3008 UxSubclassInfo_Create(HWND hwnd, LPWSTR valid, LPWSTR invalid)
3009 {
3010     UxSubclassInfo *pInfo;
3011     pInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(UxSubclassInfo));
3012     if (!pInfo)
3013     {
3014         ERR("HeapAlloc failed.\n");
3015         CoTaskMemFree(valid);
3016         CoTaskMemFree(invalid);
3017         return NULL;
3018     }
3019 
3020     pInfo->fnWndProc = (WNDPROC)SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)LimitEditWindowProc);
3021     if (!pInfo->fnWndProc)
3022     {
3023         ERR("SetWindowLongPtrW failed\n");
3024         CoTaskMemFree(valid);
3025         CoTaskMemFree(invalid);
3026         HeapFree(GetProcessHeap(), 0, pInfo);
3027         return NULL;
3028     }
3029 
3030     pInfo->hwnd = hwnd;
3031     pInfo->pwszValidChars = valid;
3032     pInfo->pwszInvalidChars = invalid;
3033     if (!SetPropW(hwnd, L"UxSubclassInfo", pInfo))
3034     {
3035         UxSubclassInfo_Destroy(pInfo);
3036         pInfo = NULL;
3037     }
3038     return pInfo;
3039 }
3040 
3041 HRESULT WINAPI
SHLimitInputEdit(HWND hWnd,IShellFolder * psf)3042 SHLimitInputEdit(HWND hWnd, IShellFolder *psf)
3043 {
3044     IItemNameLimits *pLimits;
3045     HRESULT hr;
3046     LPWSTR pwszValidChars, pwszInvalidChars;
3047     UxSubclassInfo *pInfo;
3048 
3049     pInfo = GetPropW(hWnd, L"UxSubclassInfo");
3050     if (pInfo)
3051     {
3052         UxSubclassInfo_Destroy(pInfo);
3053         pInfo = NULL;
3054     }
3055 
3056     hr = psf->lpVtbl->QueryInterface(psf, &IID_IItemNameLimits, (LPVOID *)&pLimits);
3057     if (FAILED(hr))
3058     {
3059         ERR("hr: %x\n", hr);
3060         return hr;
3061     }
3062 
3063     pwszValidChars = pwszInvalidChars = NULL;
3064     hr = pLimits->lpVtbl->GetValidCharacters(pLimits, &pwszValidChars, &pwszInvalidChars);
3065     if (FAILED(hr))
3066     {
3067         ERR("hr: %x\n", hr);
3068         pLimits->lpVtbl->Release(pLimits);
3069         return hr;
3070     }
3071 
3072     pInfo = UxSubclassInfo_Create(hWnd, pwszValidChars, pwszInvalidChars);
3073     if (!pInfo)
3074         hr = E_FAIL;
3075 
3076     pLimits->lpVtbl->Release(pLimits);
3077 
3078     return hr;
3079 }
3080 
3081 #ifdef __REACTOS__
3082 /*************************************************************************
3083  *  SHLimitInputCombo [SHELL32.748]
3084  *
3085  * Sets limits on valid characters for a combobox control.
3086  * This function works like SHLimitInputEdit, but the target is a combobox
3087  * instead of a textbox.
3088  */
3089 HRESULT WINAPI
SHLimitInputCombo(HWND hWnd,IShellFolder * psf)3090 SHLimitInputCombo(HWND hWnd, IShellFolder *psf)
3091 {
3092     HWND hwndEdit;
3093 
3094     TRACE("%p %p\n", hWnd, psf);
3095 
3096     hwndEdit = GetTopWindow(hWnd);
3097     if (!hwndEdit)
3098         return E_FAIL;
3099 
3100     return SHLimitInputEdit(hwndEdit, psf);
3101 }
3102 #endif
3103