xref: /reactos/dll/win32/shell32/wine/shellord.c (revision 50cf16b3)
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 /* FIXME: !!! move CREATEMRULIST and flags to header file !!! */
49 /*        !!! it is in both here and comctl32undoc.c      !!! */
50 typedef struct tagCREATEMRULIST
51 {
52     DWORD  cbSize;        /* size of struct */
53     DWORD  nMaxItems;     /* max no. of items in list */
54     DWORD  dwFlags;       /* see below */
55     HKEY   hKey;          /* root reg. key under which list is saved */
56     LPCSTR lpszSubKey;    /* reg. subkey */
57     int (CALLBACK *lpfnCompare)(LPCVOID, LPCVOID, DWORD); /* item compare proc */
58 } CREATEMRULISTA, *LPCREATEMRULISTA;
59 
60 /* dwFlags */
61 #define MRUF_STRING_LIST  0 /* list will contain strings */
62 #define MRUF_BINARY_LIST  1 /* list will contain binary data */
63 #define MRUF_DELAYED_SAVE 2 /* only save list order to reg. is FreeMRUList */
64 
65 extern HANDLE WINAPI CreateMRUListA(LPCREATEMRULISTA lpcml);
66 extern VOID WINAPI FreeMRUList(HANDLE hMRUList);
67 extern INT    WINAPI AddMRUData(HANDLE hList, LPCVOID lpData, DWORD cbData);
68 extern INT    WINAPI FindMRUData(HANDLE hList, LPCVOID lpData, DWORD cbData, LPINT lpRegNum);
69 extern INT    WINAPI EnumMRUListA(HANDLE hList, INT nItemPos, LPVOID lpBuffer, DWORD nBufferSize);
70 
71 
72 /*************************************************************************
73  * ParseFieldA					[internal]
74  *
75  * copies a field from a ',' delimited string
76  *
77  * first field is nField = 1
78  */
79 DWORD WINAPI ParseFieldA(
80 	LPCSTR src,
81 	DWORD nField,
82 	LPSTR dst,
83 	DWORD len)
84 {
85 	WARN("(%s,0x%08x,%p,%d) semi-stub.\n",debugstr_a(src),nField,dst,len);
86 
87 	if (!src || !src[0] || !dst || !len)
88 	  return 0;
89 
90 	/* skip n fields delimited by ',' */
91 	while (nField > 1)
92 	{
93 	  if (*src=='\0') return FALSE;
94 	  if (*(src++)==',') nField--;
95 	}
96 
97 	/* copy part till the next ',' to dst */
98 	while ( *src!='\0' && *src!=',' && (len--)>0 ) *(dst++)=*(src++);
99 
100 	/* finalize the string */
101 	*dst=0x0;
102 
103 	return TRUE;
104 }
105 
106 /*************************************************************************
107  * ParseFieldW			[internal]
108  *
109  * copies a field from a ',' delimited string
110  *
111  * first field is nField = 1
112  */
113 DWORD WINAPI ParseFieldW(LPCWSTR src, DWORD nField, LPWSTR dst, DWORD len)
114 {
115 	WARN("(%s,0x%08x,%p,%d) semi-stub.\n", debugstr_w(src), nField, dst, len);
116 
117 	if (!src || !src[0] || !dst || !len)
118 	  return 0;
119 
120 	/* skip n fields delimited by ',' */
121 	while (nField > 1)
122 	{
123 	  if (*src == 0x0) return FALSE;
124 	  if (*src++ == ',') nField--;
125 	}
126 
127 	/* copy part till the next ',' to dst */
128 	while ( *src != 0x0 && *src != ',' && (len--)>0 ) *(dst++) = *(src++);
129 
130 	/* finalize the string */
131 	*dst = 0x0;
132 
133 	return TRUE;
134 }
135 
136 /*************************************************************************
137  * ParseField			[SHELL32.58]
138  */
139 DWORD WINAPI ParseFieldAW(LPCVOID src, DWORD nField, LPVOID dst, DWORD len)
140 {
141 	if (SHELL_OsIsUnicode())
142 	  return ParseFieldW(src, nField, dst, len);
143 	return ParseFieldA(src, nField, dst, len);
144 }
145 
146 /*************************************************************************
147  * GetFileNameFromBrowse            [SHELL32.63]
148  *
149  */
150 BOOL WINAPI GetFileNameFromBrowse(
151     HWND hwndOwner,
152     LPWSTR lpstrFile,
153     UINT nMaxFile,
154     LPCWSTR lpstrInitialDir,
155     LPCWSTR lpstrDefExt,
156     LPCWSTR lpstrFilter,
157     LPCWSTR lpstrTitle)
158 {
159 typedef BOOL (WINAPI *GetOpenFileNameProc)(OPENFILENAMEW *ofn);
160     HMODULE hmodule;
161     GetOpenFileNameProc pGetOpenFileNameW;
162     OPENFILENAMEW ofn;
163     BOOL ret;
164 
165     TRACE("%p, %s, %d, %s, %s, %s, %s)\n",
166       hwndOwner, debugstr_w(lpstrFile), nMaxFile, lpstrInitialDir, lpstrDefExt,
167       lpstrFilter, lpstrTitle);
168 
169     hmodule = LoadLibraryW(L"comdlg32.dll");
170     if(!hmodule) return FALSE;
171     pGetOpenFileNameW = (GetOpenFileNameProc)GetProcAddress(hmodule, "GetOpenFileNameW");
172     if(!pGetOpenFileNameW)
173     {
174     FreeLibrary(hmodule);
175     return FALSE;
176     }
177 
178     memset(&ofn, 0, sizeof(ofn));
179 
180     ofn.lStructSize = sizeof(ofn);
181     ofn.hwndOwner = hwndOwner;
182     ofn.lpstrFilter = lpstrFilter;
183     ofn.lpstrFile = lpstrFile;
184     ofn.nMaxFile = nMaxFile;
185     ofn.lpstrInitialDir = lpstrInitialDir;
186     ofn.lpstrTitle = lpstrTitle;
187     ofn.lpstrDefExt = lpstrDefExt;
188     ofn.Flags = OFN_EXPLORER | OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;
189     ret = pGetOpenFileNameW(&ofn);
190 
191     FreeLibrary(hmodule);
192     return ret;
193 }
194 
195 /*************************************************************************
196  * SHGetSetSettings				[SHELL32.68]
197  */
198 VOID WINAPI SHGetSetSettings(LPSHELLSTATE lpss, DWORD dwMask, BOOL bSet)
199 {
200   if(bSet)
201   {
202     FIXME("%p 0x%08x TRUE\n", lpss, dwMask);
203   }
204   else
205   {
206     SHGetSettings((LPSHELLFLAGSTATE)lpss,dwMask);
207   }
208 }
209 
210 /*************************************************************************
211  * SHGetSettings				[SHELL32.@]
212  *
213  * NOTES
214  *  the registry path are for win98 (tested)
215  *  and possibly are the same in nt40
216  *
217  */
218 VOID WINAPI SHGetSettings(LPSHELLFLAGSTATE lpsfs, DWORD dwMask)
219 {
220 	HKEY	hKey;
221 	DWORD	dwData;
222 	DWORD	dwDataSize = sizeof (DWORD);
223 
224 	TRACE("(%p 0x%08x)\n",lpsfs,dwMask);
225 
226 	if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced",
227 				 0, 0, 0, KEY_ALL_ACCESS, 0, &hKey, 0))
228 	  return;
229 
230 	if ( (SSF_SHOWEXTENSIONS & dwMask) && !RegQueryValueExA(hKey, "HideFileExt", 0, 0, (LPBYTE)&dwData, &dwDataSize))
231 	  lpsfs->fShowExtensions  = ((dwData == 0) ?  0 : 1);
232 
233 	if ( (SSF_SHOWINFOTIP & dwMask) && !RegQueryValueExA(hKey, "ShowInfoTip", 0, 0, (LPBYTE)&dwData, &dwDataSize))
234 	  lpsfs->fShowInfoTip  = ((dwData == 0) ?  0 : 1);
235 
236 	if ( (SSF_DONTPRETTYPATH & dwMask) && !RegQueryValueExA(hKey, "DontPrettyPath", 0, 0, (LPBYTE)&dwData, &dwDataSize))
237 	  lpsfs->fDontPrettyPath  = ((dwData == 0) ?  0 : 1);
238 
239 	if ( (SSF_HIDEICONS & dwMask) && !RegQueryValueExA(hKey, "HideIcons", 0, 0, (LPBYTE)&dwData, &dwDataSize))
240 	  lpsfs->fHideIcons  = ((dwData == 0) ?  0 : 1);
241 
242 	if ( (SSF_MAPNETDRVBUTTON & dwMask) && !RegQueryValueExA(hKey, "MapNetDrvBtn", 0, 0, (LPBYTE)&dwData, &dwDataSize))
243 	  lpsfs->fMapNetDrvBtn  = ((dwData == 0) ?  0 : 1);
244 
245 	if ( (SSF_SHOWATTRIBCOL & dwMask) && !RegQueryValueExA(hKey, "ShowAttribCol", 0, 0, (LPBYTE)&dwData, &dwDataSize))
246 	  lpsfs->fShowAttribCol  = ((dwData == 0) ?  0 : 1);
247 
248 	if (((SSF_SHOWALLOBJECTS | SSF_SHOWSYSFILES) & dwMask) && !RegQueryValueExA(hKey, "Hidden", 0, 0, (LPBYTE)&dwData, &dwDataSize))
249 	{ if (dwData == 0)
250 	  { if (SSF_SHOWALLOBJECTS & dwMask)	lpsfs->fShowAllObjects  = 0;
251 	    if (SSF_SHOWSYSFILES & dwMask)	lpsfs->fShowSysFiles  = 0;
252 	  }
253 	  else if (dwData == 1)
254 	  { if (SSF_SHOWALLOBJECTS & dwMask)	lpsfs->fShowAllObjects  = 1;
255 	    if (SSF_SHOWSYSFILES & dwMask)	lpsfs->fShowSysFiles  = 0;
256 	  }
257 	  else if (dwData == 2)
258 	  { if (SSF_SHOWALLOBJECTS & dwMask)	lpsfs->fShowAllObjects  = 0;
259 	    if (SSF_SHOWSYSFILES & dwMask)	lpsfs->fShowSysFiles  = 1;
260 	  }
261 	}
262 	RegCloseKey (hKey);
263 
264 	TRACE("-- 0x%04x\n", *(WORD*)lpsfs);
265 }
266 
267 /*************************************************************************
268  * SHShellFolderView_Message			[SHELL32.73]
269  *
270  * Send a message to an explorer cabinet window.
271  *
272  * PARAMS
273  *  hwndCabinet [I] The window containing the shellview to communicate with
274  *  dwMessage   [I] The SFVM message to send
275  *  dwParam     [I] Message parameter
276  *
277  * RETURNS
278  *  fixme.
279  *
280  * NOTES
281  *  Message SFVM_REARRANGE = 1
282  *
283  *    This message gets sent when a column gets clicked to instruct the
284  *    shell view to re-sort the item list. dwParam identifies the column
285  *    that was clicked.
286  */
287 LRESULT WINAPI SHShellFolderView_Message(
288 	HWND hwndCabinet,
289 	UINT uMessage,
290 	LPARAM lParam)
291 {
292 	FIXME("%p %08x %08lx stub\n",hwndCabinet, uMessage, lParam);
293 	return 0;
294 }
295 
296 /*************************************************************************
297  * RegisterShellHook				[SHELL32.181]
298  *
299  * Register a shell hook.
300  *
301  * PARAMS
302  *      hwnd   [I]  Window handle
303  *      dwType [I]  Type of hook.
304  *
305  * NOTES
306  *     Exported by ordinal
307  */
308 BOOL WINAPI RegisterShellHook(
309 	HWND hWnd,
310 	DWORD dwType)
311 {
312     if (dwType == 3)
313     {
314         SetTaskmanWindow(hWnd);
315         return RegisterShellHookWindow(hWnd);
316     }
317     else if (dwType == 0)
318     {
319         return DeregisterShellHookWindow(hWnd);
320     }
321 
322     ERR("Unsupported argument");
323     return FALSE;
324 }
325 
326 /*************************************************************************
327  * ShellMessageBoxW				[SHELL32.182]
328  *
329  * See ShellMessageBoxA.
330  *
331  * NOTE:
332  * shlwapi.ShellMessageBoxWrapW is a duplicate of shell32.ShellMessageBoxW
333  * because we can't forward to it in the .spec file since it's exported by
334  * ordinal. If you change the implementation here please update the code in
335  * shlwapi as well.
336  */
337 int ShellMessageBoxW(
338 	HINSTANCE hInstance,
339 	HWND hWnd,
340 	LPCWSTR lpText,
341 	LPCWSTR lpCaption,
342 	UINT uType,
343 	...)
344 {
345 	WCHAR	szText[100],szTitle[100];
346 	LPCWSTR pszText = szText, pszTitle = szTitle;
347 	LPWSTR  pszTemp;
348 	__ms_va_list args;
349 	int	ret;
350 
351 	__ms_va_start(args, uType);
352 	/* wvsprintfA(buf,fmt, args); */
353 
354 	TRACE("(%p,%p,%p,%p,%08x)\n",
355 	    hInstance,hWnd,lpText,lpCaption,uType);
356 
357 	if (IS_INTRESOURCE(lpCaption))
358 	  LoadStringW(hInstance, LOWORD(lpCaption), szTitle, sizeof(szTitle)/sizeof(szTitle[0]));
359 	else
360 	  pszTitle = lpCaption;
361 
362 	if (IS_INTRESOURCE(lpText))
363 	  LoadStringW(hInstance, LOWORD(lpText), szText, sizeof(szText)/sizeof(szText[0]));
364 	else
365 	  pszText = lpText;
366 
367 	FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
368 		       pszText, 0, 0, (LPWSTR)&pszTemp, 0, &args);
369 
370 	__ms_va_end(args);
371 
372 	ret = MessageBoxW(hWnd,pszTemp,pszTitle,uType);
373         LocalFree(pszTemp);
374 	return ret;
375 }
376 
377 /*************************************************************************
378  * ShellMessageBoxA				[SHELL32.183]
379  *
380  * Format and output an error message.
381  *
382  * PARAMS
383  *  hInstance [I] Instance handle of message creator
384  *  hWnd      [I] Window handle of message creator
385  *  lpText    [I] Resource Id of title or LPSTR
386  *  lpCaption [I] Resource Id of title or LPSTR
387  *  uType     [I] Type of error message
388  *
389  * RETURNS
390  *  A return value from MessageBoxA().
391  *
392  * NOTES
393  *     Exported by ordinal
394  */
395 int ShellMessageBoxA(
396 	HINSTANCE hInstance,
397 	HWND hWnd,
398 	LPCSTR lpText,
399 	LPCSTR lpCaption,
400 	UINT uType,
401 	...)
402 {
403 	char	szText[100],szTitle[100];
404 	LPCSTR  pszText = szText, pszTitle = szTitle;
405 	LPSTR   pszTemp;
406 	__ms_va_list args;
407 	int	ret;
408 
409 	__ms_va_start(args, uType);
410 	/* wvsprintfA(buf,fmt, args); */
411 
412 	TRACE("(%p,%p,%p,%p,%08x)\n",
413 	    hInstance,hWnd,lpText,lpCaption,uType);
414 
415 	if (IS_INTRESOURCE(lpCaption))
416 	  LoadStringA(hInstance, LOWORD(lpCaption), szTitle, sizeof(szTitle));
417 	else
418 	  pszTitle = lpCaption;
419 
420 	if (IS_INTRESOURCE(lpText))
421 	  LoadStringA(hInstance, LOWORD(lpText), szText, sizeof(szText));
422 	else
423 	  pszText = lpText;
424 
425 	FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
426 		       pszText, 0, 0, (LPSTR)&pszTemp, 0, &args);
427 
428 	__ms_va_end(args);
429 
430 	ret = MessageBoxA(hWnd,pszTemp,pszTitle,uType);
431         LocalFree(pszTemp);
432 	return ret;
433 }
434 
435 /*************************************************************************
436  * SHRegisterDragDrop				[SHELL32.86]
437  *
438  * Probably equivalent to RegisterDragDrop but under Windows 95 it could use the
439  * shell32 built-in "mini-COM" without the need to load ole32.dll - see SHLoadOLE
440  * for details. Under Windows 98 this function initializes the true OLE when called
441  * the first time, on XP always returns E_OUTOFMEMORY and it got removed from Vista.
442  *
443  * We follow Windows 98 behaviour.
444  *
445  * NOTES
446  *     exported by ordinal
447  *
448  * SEE ALSO
449  *     RegisterDragDrop, SHLoadOLE
450  */
451 HRESULT WINAPI SHRegisterDragDrop(
452 	HWND hWnd,
453 	LPDROPTARGET pDropTarget)
454 {
455         static BOOL ole_initialized = FALSE;
456         HRESULT hr;
457 
458         TRACE("(%p,%p)\n", hWnd, pDropTarget);
459 
460         if (!ole_initialized)
461         {
462             hr = OleInitialize(NULL);
463             if (FAILED(hr))
464                 return hr;
465             ole_initialized = TRUE;
466         }
467 	return RegisterDragDrop(hWnd, pDropTarget);
468 }
469 
470 /*************************************************************************
471  * SHRevokeDragDrop				[SHELL32.87]
472  *
473  * Probably equivalent to RevokeDragDrop but under Windows 95 it could use the
474  * shell32 built-in "mini-COM" without the need to load ole32.dll - see SHLoadOLE
475  * for details. Function removed from Windows Vista.
476  *
477  * We call ole32 RevokeDragDrop which seems to work even if OleInitialize was
478  * not called.
479  *
480  * NOTES
481  *     exported by ordinal
482  *
483  * SEE ALSO
484  *     RevokeDragDrop, SHLoadOLE
485  */
486 HRESULT WINAPI SHRevokeDragDrop(HWND hWnd)
487 {
488     TRACE("(%p)\n", hWnd);
489     return RevokeDragDrop(hWnd);
490 }
491 
492 /*************************************************************************
493  * SHDoDragDrop					[SHELL32.88]
494  *
495  * Probably equivalent to DoDragDrop but under Windows 9x it could use the
496  * shell32 built-in "mini-COM" without the need to load ole32.dll - see SHLoadOLE
497  * for details
498  *
499  * NOTES
500  *     exported by ordinal
501  *
502  * SEE ALSO
503  *     DoDragDrop, SHLoadOLE
504  */
505 HRESULT WINAPI SHDoDragDrop(
506 	HWND hWnd,
507 	LPDATAOBJECT lpDataObject,
508 	LPDROPSOURCE lpDropSource,
509 	DWORD dwOKEffect,
510 	LPDWORD pdwEffect)
511 {
512     FIXME("(%p %p %p 0x%08x %p):stub.\n",
513     hWnd, lpDataObject, lpDropSource, dwOKEffect, pdwEffect);
514 	return DoDragDrop(lpDataObject, lpDropSource, dwOKEffect, pdwEffect);
515 }
516 
517 /*************************************************************************
518  * ArrangeWindows				[SHELL32.184]
519  *
520  */
521 WORD WINAPI ArrangeWindows(HWND hwndParent, DWORD dwReserved, const RECT *lpRect,
522         WORD cKids, const HWND *lpKids)
523 {
524     /* Unimplemented in WinXP SP3 */
525     TRACE("(%p 0x%08x %p 0x%04x %p):stub.\n",
526 	   hwndParent, dwReserved, lpRect, cKids, lpKids);
527     return 0;
528 }
529 
530 /*************************************************************************
531  * SignalFileOpen				[SHELL32.103]
532  *
533  * NOTES
534  *     exported by ordinal
535  */
536 BOOL WINAPI
537 SignalFileOpen (PCIDLIST_ABSOLUTE pidl)
538 {
539     FIXME("(%p):stub.\n", pidl);
540 
541     return FALSE;
542 }
543 
544 /*************************************************************************
545  * SHADD_get_policy - helper function for SHAddToRecentDocs
546  *
547  * PARAMETERS
548  *   policy    [IN]  policy name (null termed string) to find
549  *   type      [OUT] ptr to DWORD to receive type
550  *   buffer    [OUT] ptr to area to hold data retrieved
551  *   len       [IN/OUT] ptr to DWORD holding size of buffer and getting
552  *                      length filled
553  *
554  * RETURNS
555  *   result of the SHQueryValueEx call
556  */
557 static INT SHADD_get_policy(LPCSTR policy, LPDWORD type, LPVOID buffer, LPDWORD len)
558 {
559     HKEY Policy_basekey;
560     INT ret;
561 
562     /* Get the key for the policies location in the registry
563      */
564     if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,
565 		      "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer",
566 		      0, KEY_READ, &Policy_basekey)) {
567 
568 	if (RegOpenKeyExA(HKEY_CURRENT_USER,
569 			  "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer",
570 			  0, KEY_READ, &Policy_basekey)) {
571 	    TRACE("No Explorer Policies location exists. Policy wanted=%s\n",
572 		  policy);
573 	    *len = 0;
574 	    return ERROR_FILE_NOT_FOUND;
575 	}
576     }
577 
578     /* Retrieve the data if it exists
579      */
580     ret = SHQueryValueExA(Policy_basekey, policy, 0, type, buffer, len);
581     RegCloseKey(Policy_basekey);
582     return ret;
583 }
584 
585 
586 /*************************************************************************
587  * SHADD_compare_mru - helper function for SHAddToRecentDocs
588  *
589  * PARAMETERS
590  *   data1     [IN] data being looked for
591  *   data2     [IN] data in MRU
592  *   cbdata    [IN] length from FindMRUData call (not used)
593  *
594  * RETURNS
595  *   position within MRU list that data was added.
596  */
597 static INT CALLBACK SHADD_compare_mru(LPCVOID data1, LPCVOID data2, DWORD cbData)
598 {
599     return lstrcmpiA(data1, data2);
600 }
601 
602 /*************************************************************************
603  * SHADD_create_add_mru_data - helper function for SHAddToRecentDocs
604  *
605  * PARAMETERS
606  *   mruhandle    [IN] handle for created MRU list
607  *   doc_name     [IN] null termed pure doc name
608  *   new_lnk_name [IN] null termed path and file name for .lnk file
609  *   buffer       [IN/OUT] 2048 byte area to construct MRU data
610  *   len          [OUT] ptr to int to receive space used in buffer
611  *
612  * RETURNS
613  *   position within MRU list that data was added.
614  */
615 static INT SHADD_create_add_mru_data(HANDLE mruhandle, LPCSTR doc_name, LPCSTR new_lnk_name,
616                                      LPSTR buffer, INT *len)
617 {
618     LPSTR ptr;
619     INT wlen;
620 
621     /*FIXME: Document:
622      *  RecentDocs MRU data structure seems to be:
623      *    +0h   document file name w/ terminating 0h
624      *    +nh   short int w/ size of remaining
625      *    +n+2h 02h 30h, or 01h 30h, or 00h 30h  -  unknown
626      *    +n+4h 10 bytes zeros  -   unknown
627      *    +n+eh shortcut file name w/ terminating 0h
628      *    +n+e+nh 3 zero bytes  -  unknown
629      */
630 
631     /* Create the MRU data structure for "RecentDocs"
632 	 */
633     ptr = buffer;
634     lstrcpyA(ptr, doc_name);
635     ptr += (lstrlenA(buffer) + 1);
636     wlen= lstrlenA(new_lnk_name) + 1 + 12;
637     *((short int*)ptr) = wlen;
638     ptr += 2;   /* step past the length */
639     *(ptr++) = 0x30;  /* unknown reason */
640     *(ptr++) = 0;     /* unknown, but can be 0x00, 0x01, 0x02 */
641     memset(ptr, 0, 10);
642     ptr += 10;
643     lstrcpyA(ptr, new_lnk_name);
644     ptr += (lstrlenA(new_lnk_name) + 1);
645     memset(ptr, 0, 3);
646     ptr += 3;
647     *len = ptr - buffer;
648 
649     /* Add the new entry into the MRU list
650      */
651     return AddMRUData(mruhandle, buffer, *len);
652 }
653 
654 /*************************************************************************
655  * SHAddToRecentDocs				[SHELL32.@]
656  *
657  * Modify (add/clear) Shell's list of recently used documents.
658  *
659  * PARAMETERS
660  *   uFlags  [IN] SHARD_PATHA, SHARD_PATHW or SHARD_PIDL
661  *   pv      [IN] string or pidl, NULL clears the list
662  *
663  * NOTES
664  *     exported by name
665  *
666  * FIXME
667  *  convert to unicode
668  */
669 void WINAPI SHAddToRecentDocs (UINT uFlags,LPCVOID pv)
670 {
671 /* If list is a string list lpfnCompare has the following prototype
672  * int CALLBACK MRUCompareString(LPCSTR s1, LPCSTR s2)
673  * for binary lists the prototype is
674  * int CALLBACK MRUCompareBinary(LPCVOID data1, LPCVOID data2, DWORD cbData)
675  * where cbData is the no. of bytes to compare.
676  * Need to check what return value means identical - 0?
677  */
678 
679 
680     UINT olderrormode;
681     HKEY HCUbasekey;
682     CHAR doc_name[MAX_PATH];
683     CHAR link_dir[MAX_PATH];
684     CHAR new_lnk_filepath[MAX_PATH];
685     CHAR new_lnk_name[MAX_PATH];
686     CHAR * ext;
687     IMalloc *ppM;
688     LPITEMIDLIST pidl;
689     HWND hwnd = 0;       /* FIXME:  get real window handle */
690     INT ret;
691     DWORD data[64], datalen, type;
692 
693     TRACE("%04x %p\n", uFlags, pv);
694 
695     /*FIXME: Document:
696      *  RecentDocs MRU data structure seems to be:
697      *    +0h   document file name w/ terminating 0h
698      *    +nh   short int w/ size of remaining
699      *    +n+2h 02h 30h, or 01h 30h, or 00h 30h  -  unknown
700      *    +n+4h 10 bytes zeros  -   unknown
701      *    +n+eh shortcut file name w/ terminating 0h
702      *    +n+e+nh 3 zero bytes  -  unknown
703      */
704 
705     /* See if we need to do anything.
706      */
707     datalen = 64;
708     ret=SHADD_get_policy( "NoRecentDocsHistory", &type, data, &datalen);
709     if ((ret > 0) && (ret != ERROR_FILE_NOT_FOUND)) {
710 	ERR("Error %d getting policy \"NoRecentDocsHistory\"\n", ret);
711 	return;
712     }
713     if (ret == ERROR_SUCCESS) {
714 	if (!( (type == REG_DWORD) ||
715 	       ((type == REG_BINARY) && (datalen == 4)) )) {
716 	    ERR("Error policy data for \"NoRecentDocsHistory\" not formatted correctly, type=%d, len=%d\n",
717 		type, datalen);
718 	    return;
719 	}
720 
721 	TRACE("policy value for NoRecentDocsHistory = %08x\n", data[0]);
722 	/* now test the actual policy value */
723 	if ( data[0] != 0)
724 	    return;
725     }
726 
727     /* Open key to where the necessary info is
728      */
729     /* FIXME: This should be done during DLL PROCESS_ATTACH (or THREAD_ATTACH)
730      *        and the close should be done during the _DETACH. The resulting
731      *        key is stored in the DLL global data.
732      */
733     if (RegCreateKeyExA(HKEY_CURRENT_USER,
734 			"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
735 			0, 0, 0, KEY_READ, 0, &HCUbasekey, 0)) {
736 	ERR("Failed to create 'Software\\Microsoft\\Windows\\CurrentVersion\\Explorer'\n");
737 	return;
738     }
739 
740     /* Get path to user's "Recent" directory
741      */
742     if(SUCCEEDED(SHGetMalloc(&ppM))) {
743 	if (SUCCEEDED(SHGetSpecialFolderLocation(hwnd, CSIDL_RECENT,
744 						 &pidl))) {
745 	    SHGetPathFromIDListA(pidl, link_dir);
746 	    IMalloc_Free(ppM, pidl);
747 	}
748 	else {
749 	    /* serious issues */
750 	    link_dir[0] = 0;
751 	    ERR("serious issues 1\n");
752 	}
753 	IMalloc_Release(ppM);
754     }
755     else {
756 	/* serious issues */
757 	link_dir[0] = 0;
758 	ERR("serious issues 2\n");
759     }
760     TRACE("Users Recent dir %s\n", link_dir);
761 
762     /* If no input, then go clear the lists */
763     if (!pv) {
764 	/* clear user's Recent dir
765 	 */
766 
767 	/* FIXME: delete all files in "link_dir"
768 	 *
769 	 * while( more files ) {
770 	 *    lstrcpyA(old_lnk_name, link_dir);
771 	 *    PathAppendA(old_lnk_name, filenam);
772 	 *    DeleteFileA(old_lnk_name);
773 	 * }
774 	 */
775 	FIXME("should delete all files in %s\\\n", link_dir);
776 
777 	/* clear MRU list
778 	 */
779 	/* MS Bug ?? v4.72.3612.1700 of shell32 does the delete against
780 	 *  HKEY_LOCAL_MACHINE version of ...CurrentVersion\Explorer
781 	 *  and naturally it fails w/ rc=2. It should do it against
782 	 *  HKEY_CURRENT_USER which is where it is stored, and where
783 	 *  the MRU routines expect it!!!!
784 	 */
785 	RegDeleteKeyA(HCUbasekey, "RecentDocs");
786 	RegCloseKey(HCUbasekey);
787 	return;
788     }
789 
790     /* Have data to add, the jobs to be done:
791      *   1. Add document to MRU list in registry "HKCU\Software\
792      *      Microsoft\Windows\CurrentVersion\Explorer\RecentDocs".
793      *   2. Add shortcut to document in the user's Recent directory
794      *      (CSIDL_RECENT).
795      *   3. Add shortcut to Start menu's Documents submenu.
796      */
797 
798     /* Get the pure document name from the input
799      */
800     switch (uFlags)
801     {
802     case SHARD_PIDL:
803         if (!SHGetPathFromIDListA(pv, doc_name))
804         {
805             WARN("can't get path from PIDL\n");
806             return;
807         }
808         break;
809 
810     case SHARD_PATHA:
811         lstrcpynA(doc_name, pv, MAX_PATH);
812         break;
813 
814     case SHARD_PATHW:
815         WideCharToMultiByte(CP_ACP, 0, pv, -1, doc_name, MAX_PATH, NULL, NULL);
816         break;
817 
818     default:
819         FIXME("Unsupported flags: %u\n", uFlags);
820         return;
821     }
822 
823     TRACE("full document name %s\n", debugstr_a(doc_name));
824 
825 #ifdef __REACTOS__
826     /* check if file is a shortcut */
827     ext = strrchr(doc_name, '.');
828     if (!lstrcmpiA(ext, ".lnk"))
829     {
830         WCHAR doc_nameW[MAX_PATH];
831         IShellLinkA* ShellLink;
832         int nLength = MultiByteToWideChar(CP_ACP, 0, doc_name, -1, doc_nameW, MAX_PATH);
833         if (nLength == 0)
834             return;
835 
836         IShellLink_ConstructFromPath(doc_nameW, &IID_IShellLinkA, (LPVOID*)&ShellLink);
837         IShellLinkA_GetPath(ShellLink, doc_name, MAX_PATH, NULL, 0);
838         IShellLinkA_Release(ShellLink);
839     }
840 
841     ext = strrchr(doc_name, '.');
842     if (!lstrcmpiA(ext, ".exe"))
843     {
844         /* executables are not added */
845         return;
846     }
847 #endif
848 
849     PathStripPathA(doc_name);
850     TRACE("stripped document name %s\n", debugstr_a(doc_name));
851 
852 
853     /* ***  JOB 1: Update registry for ...\Explorer\RecentDocs list  *** */
854 
855     {  /* on input needs:
856 	*      doc_name    -  pure file-spec, no path
857 	*      link_dir    -  path to the user's Recent directory
858 	*      HCUbasekey  -  key of ...Windows\CurrentVersion\Explorer" node
859 	* creates:
860 	*      new_lnk_name-  pure file-spec, no path for new .lnk file
861 	*      new_lnk_filepath
862 	*                  -  path and file name of new .lnk file
863 	*/
864 	CREATEMRULISTA mymru;
865 	HANDLE mruhandle;
866 	INT len, pos, bufused, err;
867 	INT i;
868 	DWORD attr;
869 	CHAR buffer[2048];
870 	CHAR *ptr;
871 	CHAR old_lnk_name[MAX_PATH];
872 	short int slen;
873 
874 	mymru.cbSize = sizeof(CREATEMRULISTA);
875 	mymru.nMaxItems = 15;
876 	mymru.dwFlags = MRUF_BINARY_LIST | MRUF_DELAYED_SAVE;
877 	mymru.hKey = HCUbasekey;
878 	mymru.lpszSubKey = "RecentDocs";
879         mymru.lpfnCompare = SHADD_compare_mru;
880 	mruhandle = CreateMRUListA(&mymru);
881 	if (!mruhandle) {
882 	    /* MRU failed */
883 	    ERR("MRU processing failed, handle zero\n");
884 	    RegCloseKey(HCUbasekey);
885 	    return;
886 	}
887 	len = lstrlenA(doc_name);
888 	pos = FindMRUData(mruhandle, doc_name, len, 0);
889 
890 	/* Now get the MRU entry that will be replaced
891 	 * and delete the .lnk file for it
892 	 */
893 	if ((bufused = EnumMRUListA(mruhandle, (pos == -1) ? 14 : pos,
894                                     buffer, 2048)) != -1) {
895 	    ptr = buffer;
896 	    ptr += (lstrlenA(buffer) + 1);
897 	    slen = *((short int*)ptr);
898 	    ptr += 2;  /* skip the length area */
899 	    if (bufused >= slen + (ptr-buffer)) {
900 		/* buffer size looks good */
901 		ptr += 12; /* get to string */
902 		len = bufused - (ptr-buffer);  /* get length of buf remaining */
903                 if (ptr[0] && (lstrlenA(ptr) <= len-1)) {
904 		    /* appears to be good string */
905 		    lstrcpyA(old_lnk_name, link_dir);
906 		    PathAppendA(old_lnk_name, ptr);
907 		    if (!DeleteFileA(old_lnk_name)) {
908 			if ((attr = GetFileAttributesA(old_lnk_name)) == INVALID_FILE_ATTRIBUTES) {
909 			    if ((err = GetLastError()) != ERROR_FILE_NOT_FOUND) {
910 				ERR("Delete for %s failed, err=%d, attr=%08x\n",
911 				    old_lnk_name, err, attr);
912 			    }
913 			    else {
914 				TRACE("old .lnk file %s did not exist\n",
915 				      old_lnk_name);
916 			    }
917 			}
918 			else {
919 			    ERR("Delete for %s failed, attr=%08x\n",
920 				old_lnk_name, attr);
921 			}
922 		    }
923 		    else {
924 			TRACE("deleted old .lnk file %s\n", old_lnk_name);
925 		    }
926 		}
927 	    }
928 	}
929 
930 	/* Create usable .lnk file name for the "Recent" directory
931 	 */
932 	wsprintfA(new_lnk_name, "%s.lnk", doc_name);
933 	lstrcpyA(new_lnk_filepath, link_dir);
934 	PathAppendA(new_lnk_filepath, new_lnk_name);
935 	i = 1;
936 	olderrormode = SetErrorMode(SEM_FAILCRITICALERRORS);
937 	while (GetFileAttributesA(new_lnk_filepath) != INVALID_FILE_ATTRIBUTES) {
938 	    i++;
939 	    wsprintfA(new_lnk_name, "%s (%u).lnk", doc_name, i);
940 	    lstrcpyA(new_lnk_filepath, link_dir);
941 	    PathAppendA(new_lnk_filepath, new_lnk_name);
942 	}
943 	SetErrorMode(olderrormode);
944 	TRACE("new shortcut will be %s\n", new_lnk_filepath);
945 
946 	/* Now add the new MRU entry and data
947 	 */
948 	pos = SHADD_create_add_mru_data(mruhandle, doc_name, new_lnk_name,
949 					buffer, &len);
950 	FreeMRUList(mruhandle);
951 	TRACE("Updated MRU list, new doc is position %d\n", pos);
952     }
953 
954     /* ***  JOB 2: Create shortcut in user's "Recent" directory  *** */
955 
956     {  /* on input needs:
957 	*      doc_name    -  pure file-spec, no path
958 	*      new_lnk_filepath
959 	*                  -  path and file name of new .lnk file
960  	*      uFlags[in]  -  flags on call to SHAddToRecentDocs
961 	*      pv[in]      -  document path/pidl on call to SHAddToRecentDocs
962 	*/
963 	IShellLinkA *psl = NULL;
964 	IPersistFile *pPf = NULL;
965 	HRESULT hres;
966 	CHAR desc[MAX_PATH];
967 	WCHAR widelink[MAX_PATH];
968 
969 	CoInitialize(0);
970 
971 	hres = CoCreateInstance( &CLSID_ShellLink,
972 				 NULL,
973 				 CLSCTX_INPROC_SERVER,
974 				 &IID_IShellLinkA,
975 				 (LPVOID )&psl);
976 	if(SUCCEEDED(hres)) {
977 
978 	    hres = IShellLinkA_QueryInterface(psl, &IID_IPersistFile,
979 					     (LPVOID *)&pPf);
980 	    if(FAILED(hres)) {
981 		/* bombed */
982 		ERR("failed QueryInterface for IPersistFile %08x\n", hres);
983 		goto fail;
984 	    }
985 
986 	    /* Set the document path or pidl */
987 	    if (uFlags == SHARD_PIDL) {
988                 hres = IShellLinkA_SetIDList(psl, pv);
989 	    } else {
990                 hres = IShellLinkA_SetPath(psl, pv);
991 	    }
992 	    if(FAILED(hres)) {
993 		/* bombed */
994 		ERR("failed Set{IDList|Path} %08x\n", hres);
995 		goto fail;
996 	    }
997 
998 	    lstrcpyA(desc, "Shortcut to ");
999 	    lstrcatA(desc, doc_name);
1000 	    hres = IShellLinkA_SetDescription(psl, desc);
1001 	    if(FAILED(hres)) {
1002 		/* bombed */
1003 		ERR("failed SetDescription %08x\n", hres);
1004 		goto fail;
1005 	    }
1006 
1007 	    MultiByteToWideChar(CP_ACP, 0, new_lnk_filepath, -1,
1008 				widelink, MAX_PATH);
1009 	    /* create the short cut */
1010 	    hres = IPersistFile_Save(pPf, widelink, TRUE);
1011 	    if(FAILED(hres)) {
1012 		/* bombed */
1013 		ERR("failed IPersistFile::Save %08x\n", hres);
1014 		IPersistFile_Release(pPf);
1015 		IShellLinkA_Release(psl);
1016 		goto fail;
1017 	    }
1018 	    hres = IPersistFile_SaveCompleted(pPf, widelink);
1019 	    IPersistFile_Release(pPf);
1020 	    IShellLinkA_Release(psl);
1021 	    TRACE("shortcut %s has been created, result=%08x\n",
1022 		  new_lnk_filepath, hres);
1023 	}
1024 	else {
1025 	    ERR("CoCreateInstance failed, hres=%08x\n", hres);
1026 	}
1027     }
1028 
1029  fail:
1030     CoUninitialize();
1031 
1032     /* all done */
1033     RegCloseKey(HCUbasekey);
1034     return;
1035 }
1036 
1037 /*************************************************************************
1038  * SHCreateShellFolderViewEx			[SHELL32.174]
1039  *
1040  * Create a new instance of the default Shell folder view object.
1041  *
1042  * RETURNS
1043  *  Success: S_OK
1044  *  Failure: error value
1045  *
1046  * NOTES
1047  *  see IShellFolder::CreateViewObject
1048  */
1049  #ifndef __REACTOS__
1050 
1051 HRESULT WINAPI SHCreateShellFolderViewEx(
1052 	LPCSFV psvcbi,    /* [in] shelltemplate struct */
1053 	IShellView **ppv) /* [out] IShellView pointer */
1054 {
1055 	IShellView * psf;
1056 	HRESULT hRes;
1057 
1058 	TRACE("sf=%p pidl=%p cb=%p mode=0x%08x parm=%p\n",
1059 	  psvcbi->pshf, psvcbi->pidl, psvcbi->pfnCallback,
1060 	  psvcbi->fvm, psvcbi->psvOuter);
1061 
1062 	*ppv = NULL;
1063     hRes = IShellView_Constructor(psvcbi->pshf, &psf);
1064 
1065     if (FAILED(hRes))
1066         return hRes;
1067 
1068 	hRes = IShellView_QueryInterface(psf, &IID_IShellView, (LPVOID *)ppv);
1069 	IShellView_Release(psf);
1070 
1071 	return hRes;
1072 }
1073 #endif
1074 
1075 /*************************************************************************
1076  *  SHWinHelp					[SHELL32.127]
1077  *
1078  */
1079 HRESULT WINAPI SHWinHelp (DWORD v, DWORD w, DWORD x, DWORD z)
1080 {	FIXME("0x%08x 0x%08x 0x%08x 0x%08x stub\n",v,w,x,z);
1081 	return 0;
1082 }
1083 /*************************************************************************
1084  *  SHRunControlPanel [SHELL32.161]
1085  *
1086  */
1087 BOOL WINAPI SHRunControlPanel (LPCWSTR commandLine, HWND parent)
1088 {
1089 	FIXME("(%s, %p): stub\n", debugstr_w(commandLine), parent);
1090 	return FALSE;
1091 }
1092 
1093 static LPUNKNOWN SHELL32_IExplorerInterface=0;
1094 /*************************************************************************
1095  * SHSetInstanceExplorer			[SHELL32.176]
1096  *
1097  * NOTES
1098  *  Sets the interface
1099  */
1100 VOID WINAPI SHSetInstanceExplorer (LPUNKNOWN lpUnknown)
1101 {	TRACE("%p\n", lpUnknown);
1102 	SHELL32_IExplorerInterface = lpUnknown;
1103 }
1104 /*************************************************************************
1105  * SHGetInstanceExplorer			[SHELL32.@]
1106  *
1107  * NOTES
1108  *  gets the interface pointer of the explorer and a reference
1109  */
1110 HRESULT WINAPI SHGetInstanceExplorer (IUnknown **lpUnknown)
1111 {	TRACE("%p\n", lpUnknown);
1112 
1113 	*lpUnknown = SHELL32_IExplorerInterface;
1114 
1115 	if (!SHELL32_IExplorerInterface)
1116 	  return E_FAIL;
1117 
1118 	IUnknown_AddRef(SHELL32_IExplorerInterface);
1119 	return S_OK;
1120 }
1121 /*************************************************************************
1122  * SHFreeUnusedLibraries			[SHELL32.123]
1123  *
1124  * Probably equivalent to CoFreeUnusedLibraries but under Windows 9x it could use
1125  * the shell32 built-in "mini-COM" without the need to load ole32.dll - see SHLoadOLE
1126  * for details
1127  *
1128  * NOTES
1129  *     exported by ordinal
1130  *
1131  * SEE ALSO
1132  *     CoFreeUnusedLibraries, SHLoadOLE
1133  */
1134 void WINAPI SHFreeUnusedLibraries (void)
1135 {
1136 	FIXME("stub\n");
1137 	CoFreeUnusedLibraries();
1138 }
1139 /*************************************************************************
1140  * DAD_AutoScroll				[SHELL32.129]
1141  *
1142  */
1143 BOOL WINAPI DAD_AutoScroll(HWND hwnd, AUTO_SCROLL_DATA *samples, const POINT * pt)
1144 {
1145     FIXME("hwnd = %p %p %p\n",hwnd,samples,pt);
1146     return FALSE;
1147 }
1148 /*************************************************************************
1149  * DAD_DragEnter				[SHELL32.130]
1150  *
1151  */
1152 BOOL WINAPI DAD_DragEnter(HWND hwnd)
1153 {
1154     FIXME("hwnd = %p\n",hwnd);
1155     return FALSE;
1156 }
1157 /*************************************************************************
1158  * DAD_DragEnterEx				[SHELL32.131]
1159  *
1160  */
1161 BOOL WINAPI DAD_DragEnterEx(HWND hwnd, POINT p)
1162 {
1163     FIXME("hwnd = %p (%d,%d)\n",hwnd,p.x,p.y);
1164     return FALSE;
1165 }
1166 /*************************************************************************
1167  * DAD_DragMove				[SHELL32.134]
1168  *
1169  */
1170 BOOL WINAPI DAD_DragMove(POINT p)
1171 {
1172     FIXME("(%d,%d)\n",p.x,p.y);
1173     return FALSE;
1174 }
1175 /*************************************************************************
1176  * DAD_DragLeave				[SHELL32.132]
1177  *
1178  */
1179 BOOL WINAPI DAD_DragLeave(VOID)
1180 {
1181     FIXME("\n");
1182     return FALSE;
1183 }
1184 /*************************************************************************
1185  * DAD_SetDragImage				[SHELL32.136]
1186  *
1187  * NOTES
1188  *  exported by name
1189  */
1190 BOOL WINAPI DAD_SetDragImage(
1191 	HIMAGELIST himlTrack,
1192 	LPPOINT lppt)
1193 {
1194     FIXME("%p %p stub\n",himlTrack, lppt);
1195     return FALSE;
1196 }
1197 /*************************************************************************
1198  * DAD_ShowDragImage				[SHELL32.137]
1199  *
1200  * NOTES
1201  *  exported by name
1202  */
1203 BOOL WINAPI DAD_ShowDragImage(BOOL bShow)
1204 {
1205     FIXME("0x%08x stub\n",bShow);
1206     return FALSE;
1207 }
1208 
1209 static const WCHAR szwCabLocation[] = {
1210   'S','o','f','t','w','a','r','e','\\',
1211   'M','i','c','r','o','s','o','f','t','\\',
1212   'W','i','n','d','o','w','s','\\',
1213   'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1214   'E','x','p','l','o','r','e','r','\\',
1215   'C','a','b','i','n','e','t','S','t','a','t','e',0
1216 };
1217 
1218 static const WCHAR szwSettings[] = { 'S','e','t','t','i','n','g','s',0 };
1219 
1220 /*************************************************************************
1221  * ReadCabinetState				[SHELL32.651] NT 4.0
1222  *
1223  */
1224 BOOL WINAPI ReadCabinetState(CABINETSTATE *cs, int length)
1225 {
1226 	HKEY hkey = 0;
1227 	DWORD type, r;
1228 
1229 	TRACE("%p %d\n", cs, length);
1230 
1231 	if( (cs == NULL) || (length < (int)sizeof(*cs))  )
1232 		return FALSE;
1233 
1234 	r = RegOpenKeyW( HKEY_CURRENT_USER, szwCabLocation, &hkey );
1235 	if( r == ERROR_SUCCESS )
1236 	{
1237 		type = REG_BINARY;
1238 		r = RegQueryValueExW( hkey, szwSettings,
1239 			NULL, &type, (LPBYTE)cs, (LPDWORD)&length );
1240 		RegCloseKey( hkey );
1241 
1242 	}
1243 
1244 	/* if we can't read from the registry, create default values */
1245 	if ( (r != ERROR_SUCCESS) || (cs->cLength < sizeof(*cs)) ||
1246 		(cs->cLength != length) )
1247 	{
1248 		TRACE("Initializing shell cabinet settings\n");
1249 		memset(cs, 0, sizeof(*cs));
1250 		cs->cLength          = sizeof(*cs);
1251 		cs->nVersion         = 2;
1252 		cs->fFullPathTitle   = FALSE;
1253 		cs->fSaveLocalView   = TRUE;
1254 		cs->fNotShell        = FALSE;
1255 		cs->fSimpleDefault   = TRUE;
1256 		cs->fDontShowDescBar = FALSE;
1257 		cs->fNewWindowMode   = FALSE;
1258 		cs->fShowCompColor   = FALSE;
1259 		cs->fDontPrettyNames = FALSE;
1260 		cs->fAdminsCreateCommonGroups = TRUE;
1261 		cs->fMenuEnumFilter  = 96;
1262 	}
1263 
1264 	return TRUE;
1265 }
1266 
1267 /*************************************************************************
1268  * WriteCabinetState				[SHELL32.652] NT 4.0
1269  *
1270  */
1271 BOOL WINAPI WriteCabinetState(CABINETSTATE *cs)
1272 {
1273 	DWORD r;
1274 	HKEY hkey = 0;
1275 
1276 	TRACE("%p\n",cs);
1277 
1278 	if( cs == NULL )
1279 		return FALSE;
1280 
1281 	r = RegCreateKeyExW( HKEY_CURRENT_USER, szwCabLocation, 0,
1282 		 NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1283 	if( r == ERROR_SUCCESS )
1284 	{
1285 		r = RegSetValueExW( hkey, szwSettings, 0,
1286 			REG_BINARY, (LPBYTE) cs, cs->cLength);
1287 
1288 		RegCloseKey( hkey );
1289 	}
1290 
1291 	return (r==ERROR_SUCCESS);
1292 }
1293 
1294 /*************************************************************************
1295  * FileIconInit 				[SHELL32.660]
1296  *
1297  */
1298 BOOL WINAPI FileIconInit(BOOL bFullInit)
1299 {
1300     return SIC_Initialize();
1301 }
1302 
1303 /*************************************************************************
1304  * SetAppStartingCursor				[SHELL32.99]
1305  */
1306 HRESULT WINAPI SetAppStartingCursor(HWND u, DWORD v)
1307 {	FIXME("hwnd=%p 0x%04x stub\n",u,v );
1308 	return 0;
1309 }
1310 
1311 /*************************************************************************
1312  * SHLoadOLE					[SHELL32.151]
1313  *
1314  * To reduce the memory usage of Windows 95, its shell32 contained an
1315  * internal implementation of a part of COM (see e.g. SHGetMalloc, SHCoCreateInstance,
1316  * SHRegisterDragDrop etc.) that allowed to use in-process STA objects without
1317  * the need to load OLE32.DLL. If OLE32.DLL was already loaded, the SH* function
1318  * would just call the Co* functions.
1319  *
1320  * The SHLoadOLE was called when OLE32.DLL was being loaded to transfer all the
1321  * information from the shell32 "mini-COM" to ole32.dll.
1322  *
1323  * See http://blogs.msdn.com/oldnewthing/archive/2004/07/05/173226.aspx for a
1324  * detailed description.
1325  *
1326  * Under wine ole32.dll is always loaded as it is imported by shlwapi.dll which is
1327  * imported by shell32 and no "mini-COM" is used (except for the "LoadWithoutCOM"
1328  * hack in SHCoCreateInstance)
1329  */
1330 HRESULT WINAPI SHLoadOLE(LPARAM lParam)
1331 {	FIXME("0x%08lx stub\n",lParam);
1332 	return S_OK;
1333 }
1334 /*************************************************************************
1335  * DriveType					[SHELL32.64]
1336  *
1337  */
1338 int WINAPI DriveType(int DriveType)
1339 {
1340     WCHAR root[] = L"A:\\";
1341     root[0] = L'A' + DriveType;
1342     return GetDriveTypeW(root);
1343 }
1344 /*************************************************************************
1345  * InvalidateDriveType            [SHELL32.65]
1346  * Unimplemented in XP SP3
1347  */
1348 int WINAPI InvalidateDriveType(int u)
1349 {
1350     TRACE("0x%08x stub\n",u);
1351     return 0;
1352 }
1353 /*************************************************************************
1354  * SHAbortInvokeCommand				[SHELL32.198]
1355  *
1356  */
1357 HRESULT WINAPI SHAbortInvokeCommand(void)
1358 {	FIXME("stub\n");
1359 	return 1;
1360 }
1361 /*************************************************************************
1362  * SHOutOfMemoryMessageBox			[SHELL32.126]
1363  *
1364  */
1365 int WINAPI SHOutOfMemoryMessageBox(
1366 	HWND hwndOwner,
1367 	LPCSTR lpCaption,
1368 	UINT uType)
1369 {
1370 	FIXME("%p %s 0x%08x stub\n",hwndOwner, lpCaption, uType);
1371 	return 0;
1372 }
1373 /*************************************************************************
1374  * SHFlushClipboard				[SHELL32.121]
1375  *
1376  */
1377 HRESULT WINAPI SHFlushClipboard(void)
1378 {
1379     return OleFlushClipboard();
1380 }
1381 
1382 /*************************************************************************
1383  * SHWaitForFileToOpen				[SHELL32.97]
1384  *
1385  */
1386 BOOL WINAPI SHWaitForFileToOpen(
1387 	LPCITEMIDLIST pidl,
1388 	DWORD dwFlags,
1389 	DWORD dwTimeout)
1390 {
1391 	FIXME("%p 0x%08x 0x%08x stub\n", pidl, dwFlags, dwTimeout);
1392 	return FALSE;
1393 }
1394 
1395 /************************************************************************
1396  *	RLBuildListOfPaths			[SHELL32.146]
1397  *
1398  * NOTES
1399  *   builds a DPA
1400  */
1401 DWORD WINAPI RLBuildListOfPaths (void)
1402 {	FIXME("stub\n");
1403 	return 0;
1404 }
1405 /************************************************************************
1406  *	SHValidateUNC				[SHELL32.173]
1407  *
1408  */
1409 BOOL WINAPI SHValidateUNC (HWND hwndOwner, PWSTR pszFile, UINT fConnect)
1410 {
1411 	FIXME("(%p, %s, 0x%08x): stub\n", hwndOwner, debugstr_w(pszFile), fConnect);
1412 	return FALSE;
1413 }
1414 
1415 /************************************************************************
1416  * DoEnvironmentSubstA [SHELL32.@]
1417  *
1418  * See DoEnvironmentSubstW.
1419  */
1420 DWORD WINAPI DoEnvironmentSubstA(LPSTR pszString, UINT cchString)
1421 {
1422     LPSTR dst;
1423     BOOL res = FALSE;
1424     DWORD len = cchString;
1425 
1426     TRACE("(%s, %d)\n", debugstr_a(pszString), cchString);
1427     if (pszString == NULL) /* Really return 0? */
1428         return 0;
1429     if ((dst = (LPSTR)HeapAlloc(GetProcessHeap(), 0, cchString * sizeof(CHAR))))
1430     {
1431         len = ExpandEnvironmentStringsA(pszString, dst, cchString);
1432         /* len includes the terminating 0 */
1433         if (len && len < cchString)
1434         {
1435             res = TRUE;
1436             memcpy(pszString, dst, len);
1437         }
1438         else
1439             len = cchString;
1440 
1441         HeapFree(GetProcessHeap(), 0, dst);
1442     }
1443     return MAKELONG(len, res);
1444 }
1445 
1446 /************************************************************************
1447  * DoEnvironmentSubstW [SHELL32.@]
1448  *
1449  * Replace all %KEYWORD% in the string with the value of the named
1450  * environment variable. If the buffer is too small, the string is not modified.
1451  *
1452  * PARAMS
1453  *  pszString  [I] '\0' terminated string with %keyword%.
1454  *             [O] '\0' terminated string with %keyword% substituted.
1455  *  cchString  [I] size of str.
1456  *
1457  * RETURNS
1458  *  Success:  The string in the buffer is updated
1459  *            HIWORD: TRUE
1460  *            LOWORD: characters used in the buffer, including space for the terminating 0
1461  *  Failure:  buffer too small. The string is not modified.
1462  *            HIWORD: FALSE
1463  *            LOWORD: provided size of the buffer in characters
1464  */
1465 DWORD WINAPI DoEnvironmentSubstW(LPWSTR pszString, UINT cchString)
1466 {
1467     LPWSTR dst;
1468     BOOL res = FALSE;
1469     DWORD len = cchString;
1470 
1471     TRACE("(%s, %d)\n", debugstr_w(pszString), cchString);
1472 
1473     if ((cchString < MAXLONG) && (dst = HeapAlloc(GetProcessHeap(), 0, cchString * sizeof(WCHAR))))
1474     {
1475         len = ExpandEnvironmentStringsW(pszString, dst, cchString);
1476         /* len includes the terminating 0 */
1477         if (len && len <= cchString)
1478         {
1479             res = TRUE;
1480             memcpy(pszString, dst, len * sizeof(WCHAR));
1481         }
1482         else
1483             len = cchString;
1484 
1485         HeapFree(GetProcessHeap(), 0, dst);
1486     }
1487     return MAKELONG(len, res);
1488 }
1489 
1490 /************************************************************************
1491  *	DoEnvironmentSubst			[SHELL32.53]
1492  *
1493  * See DoEnvironmentSubstA.
1494  */
1495 DWORD WINAPI DoEnvironmentSubstAW(LPVOID x, UINT y)
1496 {
1497     if (SHELL_OsIsUnicode())
1498         return DoEnvironmentSubstW(x, y);
1499     return DoEnvironmentSubstA(x, y);
1500 }
1501 
1502 /*************************************************************************
1503  *      GUIDFromStringA   [SHELL32.703]
1504  */
1505 BOOL WINAPI GUIDFromStringA(LPCSTR str, LPGUID guid)
1506 {
1507     TRACE("GUIDFromStringA() stub\n");
1508     return FALSE;
1509 }
1510 
1511 /*************************************************************************
1512  *      GUIDFromStringW   [SHELL32.704]
1513  */
1514 BOOL WINAPI GUIDFromStringW(LPCWSTR str, LPGUID guid)
1515 {
1516     UNICODE_STRING guid_str;
1517 
1518     RtlInitUnicodeString(&guid_str, str);
1519     return !RtlGUIDFromString(&guid_str, guid);
1520 }
1521 
1522 /*************************************************************************
1523  *      PathIsTemporaryA    [SHELL32.713]
1524  */
1525 BOOL WINAPI PathIsTemporaryA(LPSTR Str)
1526 {
1527     FIXME("(%s)stub\n", debugstr_a(Str));
1528     return FALSE;
1529 }
1530 
1531 /*************************************************************************
1532  *      PathIsTemporaryW    [SHELL32.714]
1533  */
1534 BOOL WINAPI PathIsTemporaryW(LPWSTR Str)
1535 {
1536     FIXME("(%s)stub\n", debugstr_w(Str));
1537     return FALSE;
1538 }
1539 
1540 typedef struct _PSXA
1541 {
1542     UINT uiCount;
1543     UINT uiAllocated;
1544     IShellPropSheetExt *pspsx[1];
1545 } PSXA, *PPSXA;
1546 
1547 typedef struct _PSXA_CALL
1548 {
1549     LPFNADDPROPSHEETPAGE lpfnAddReplaceWith;
1550     LPARAM lParam;
1551     BOOL bCalled;
1552     BOOL bMultiple;
1553     UINT uiCount;
1554 } PSXA_CALL, *PPSXA_CALL;
1555 
1556 static BOOL CALLBACK PsxaCall(HPROPSHEETPAGE hpage, LPARAM lParam)
1557 {
1558     PPSXA_CALL Call = (PPSXA_CALL)lParam;
1559 
1560     if (Call != NULL)
1561     {
1562         if ((Call->bMultiple || !Call->bCalled) &&
1563             Call->lpfnAddReplaceWith(hpage, Call->lParam))
1564         {
1565             Call->bCalled = TRUE;
1566             Call->uiCount++;
1567             return TRUE;
1568         }
1569     }
1570 
1571     return FALSE;
1572 }
1573 
1574 /*************************************************************************
1575  *      SHAddFromPropSheetExtArray	[SHELL32.167]
1576  */
1577 UINT WINAPI SHAddFromPropSheetExtArray(HPSXA hpsxa, LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam)
1578 {
1579     PSXA_CALL Call;
1580     UINT i;
1581     PPSXA psxa = (PPSXA)hpsxa;
1582 
1583     TRACE("(%p,%p,%08lx)\n", hpsxa, lpfnAddPage, lParam);
1584 
1585     if (psxa)
1586     {
1587         ZeroMemory(&Call, sizeof(Call));
1588         Call.lpfnAddReplaceWith = lpfnAddPage;
1589         Call.lParam = lParam;
1590         Call.bMultiple = TRUE;
1591 
1592         /* Call the AddPage method of all registered IShellPropSheetExt interfaces */
1593         for (i = 0; i != psxa->uiCount; i++)
1594         {
1595             psxa->pspsx[i]->lpVtbl->AddPages(psxa->pspsx[i], PsxaCall, (LPARAM)&Call);
1596         }
1597 
1598         return Call.uiCount;
1599     }
1600 
1601     return 0;
1602 }
1603 
1604 /*************************************************************************
1605  *      SHCreatePropSheetExtArray	[SHELL32.168]
1606  */
1607 HPSXA WINAPI SHCreatePropSheetExtArray(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface)
1608 {
1609     return SHCreatePropSheetExtArrayEx(hKey, pszSubKey, max_iface, NULL);
1610 }
1611 
1612 /*************************************************************************
1613  *      SHCreatePropSheetExtArrayEx	[SHELL32.194]
1614  */
1615 HPSXA WINAPI SHCreatePropSheetExtArrayEx(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface, LPDATAOBJECT pDataObj)
1616 {
1617     static const WCHAR szPropSheetSubKey[] = {'s','h','e','l','l','e','x','\\','P','r','o','p','e','r','t','y','S','h','e','e','t','H','a','n','d','l','e','r','s',0};
1618     WCHAR szHandler[64];
1619     DWORD dwHandlerLen;
1620     WCHAR szClsidHandler[39];
1621     DWORD dwClsidSize;
1622     CLSID clsid;
1623     LONG lRet;
1624     DWORD dwIndex;
1625     IShellExtInit *psxi;
1626     IShellPropSheetExt *pspsx;
1627     HKEY hkBase, hkPropSheetHandlers;
1628     PPSXA psxa = NULL;
1629 
1630     TRACE("(%p,%s,%u)\n", hKey, debugstr_w(pszSubKey), max_iface);
1631 
1632     if (max_iface == 0)
1633         return NULL;
1634 
1635     /* Open the registry key */
1636     lRet = RegOpenKeyW(hKey, pszSubKey, &hkBase);
1637     if (lRet != ERROR_SUCCESS)
1638         return NULL;
1639 
1640     lRet = RegOpenKeyExW(hkBase, szPropSheetSubKey, 0, KEY_ENUMERATE_SUB_KEYS, &hkPropSheetHandlers);
1641     RegCloseKey(hkBase);
1642     if (lRet == ERROR_SUCCESS)
1643     {
1644         /* Create and initialize the Property Sheet Extensions Array */
1645         psxa = LocalAlloc(LMEM_FIXED, FIELD_OFFSET(PSXA, pspsx[max_iface]));
1646         if (psxa)
1647         {
1648             ZeroMemory(psxa, FIELD_OFFSET(PSXA, pspsx[max_iface]));
1649             psxa->uiAllocated = max_iface;
1650 
1651             /* Enumerate all subkeys and attempt to load the shell extensions */
1652             dwIndex = 0;
1653             do
1654             {
1655                 dwHandlerLen = sizeof(szHandler) / sizeof(szHandler[0]);
1656                 lRet = RegEnumKeyExW(hkPropSheetHandlers, dwIndex++, szHandler, &dwHandlerLen, NULL, NULL, NULL, NULL);
1657                 if (lRet != ERROR_SUCCESS)
1658                 {
1659                     if (lRet == ERROR_MORE_DATA)
1660                         continue;
1661 
1662                     if (lRet == ERROR_NO_MORE_ITEMS)
1663                         lRet = ERROR_SUCCESS;
1664                     break;
1665                 }
1666 
1667                 /* The CLSID is stored either in the key itself or in its default value. */
1668                 if (FAILED(lRet = SHCLSIDFromStringW(szHandler, &clsid)))
1669                 {
1670                     dwClsidSize = sizeof(szClsidHandler);
1671                     if (SHGetValueW(hkPropSheetHandlers, szHandler, NULL, NULL, szClsidHandler, &dwClsidSize) == ERROR_SUCCESS)
1672                     {
1673                         /* Force a NULL-termination and convert the string */
1674                         szClsidHandler[(sizeof(szClsidHandler) / sizeof(szClsidHandler[0])) - 1] = 0;
1675                         lRet = SHCLSIDFromStringW(szClsidHandler, &clsid);
1676                     }
1677                 }
1678 
1679                 if (SUCCEEDED(lRet))
1680                 {
1681                     /* Attempt to get an IShellPropSheetExt and an IShellExtInit instance.
1682                        Only if both interfaces are supported it's a real shell extension.
1683                        Then call IShellExtInit's Initialize method. */
1684                     if (SUCCEEDED(CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER/* | CLSCTX_NO_CODE_DOWNLOAD */, &IID_IShellPropSheetExt, (LPVOID *)&pspsx)))
1685                     {
1686                         if (SUCCEEDED(pspsx->lpVtbl->QueryInterface(pspsx, &IID_IShellExtInit, (PVOID *)&psxi)))
1687                         {
1688                             if (SUCCEEDED(psxi->lpVtbl->Initialize(psxi, NULL, pDataObj, hKey)))
1689                             {
1690                                 /* Add the IShellPropSheetExt instance to the array */
1691                                 psxa->pspsx[psxa->uiCount++] = pspsx;
1692                             }
1693                             else
1694                             {
1695                                 psxi->lpVtbl->Release(psxi);
1696                                 pspsx->lpVtbl->Release(pspsx);
1697                             }
1698                         }
1699                         else
1700                             pspsx->lpVtbl->Release(pspsx);
1701                     }
1702                 }
1703 
1704             } while (psxa->uiCount != psxa->uiAllocated);
1705         }
1706         else
1707             lRet = ERROR_NOT_ENOUGH_MEMORY;
1708 
1709         RegCloseKey(hkPropSheetHandlers);
1710     }
1711 
1712     if (lRet != ERROR_SUCCESS && psxa)
1713     {
1714         SHDestroyPropSheetExtArray((HPSXA)psxa);
1715         psxa = NULL;
1716     }
1717 
1718     return (HPSXA)psxa;
1719 }
1720 
1721 /*************************************************************************
1722  *      SHReplaceFromPropSheetExtArray	[SHELL32.170]
1723  */
1724 UINT WINAPI SHReplaceFromPropSheetExtArray(HPSXA hpsxa, UINT uPageID, LPFNADDPROPSHEETPAGE lpfnReplaceWith, LPARAM lParam)
1725 {
1726     PSXA_CALL Call;
1727     UINT i;
1728     PPSXA psxa = (PPSXA)hpsxa;
1729 
1730     TRACE("(%p,%u,%p,%08lx)\n", hpsxa, uPageID, lpfnReplaceWith, lParam);
1731 
1732     if (psxa)
1733     {
1734         ZeroMemory(&Call, sizeof(Call));
1735         Call.lpfnAddReplaceWith = lpfnReplaceWith;
1736         Call.lParam = lParam;
1737 
1738         /* Call the ReplacePage method of all registered IShellPropSheetExt interfaces.
1739            Each shell extension is only allowed to call the callback once during the callback. */
1740         for (i = 0; i != psxa->uiCount; i++)
1741         {
1742             Call.bCalled = FALSE;
1743             psxa->pspsx[i]->lpVtbl->ReplacePage(psxa->pspsx[i], uPageID, PsxaCall, (LPARAM)&Call);
1744         }
1745 
1746         return Call.uiCount;
1747     }
1748 
1749     return 0;
1750 }
1751 
1752 /*************************************************************************
1753  *      SHDestroyPropSheetExtArray	[SHELL32.169]
1754  */
1755 void WINAPI SHDestroyPropSheetExtArray(HPSXA hpsxa)
1756 {
1757     UINT i;
1758     PPSXA psxa = (PPSXA)hpsxa;
1759 
1760     TRACE("(%p)\n", hpsxa);
1761 
1762     if (psxa)
1763     {
1764         for (i = 0; i != psxa->uiCount; i++)
1765         {
1766             psxa->pspsx[i]->lpVtbl->Release(psxa->pspsx[i]);
1767         }
1768 
1769         LocalFree(psxa);
1770     }
1771 }
1772 
1773 /*************************************************************************
1774  *      CIDLData_CreateFromIDArray	[SHELL32.83]
1775  *
1776  *  Create IDataObject from PIDLs??
1777  */
1778 HRESULT WINAPI CIDLData_CreateFromIDArray(
1779 	PCIDLIST_ABSOLUTE pidlFolder,
1780     UINT cpidlFiles,
1781 	PCUIDLIST_RELATIVE_ARRAY lppidlFiles,
1782 	LPDATAOBJECT *ppdataObject)
1783 {
1784     UINT i;
1785     HWND hwnd = 0;   /*FIXME: who should be hwnd of owner? set to desktop */
1786     HRESULT hResult;
1787 
1788     TRACE("(%p, %d, %p, %p)\n", pidlFolder, cpidlFiles, lppidlFiles, ppdataObject);
1789     if (TRACE_ON(pidl))
1790     {
1791 	pdump (pidlFolder);
1792 	for (i=0; i<cpidlFiles; i++) pdump (lppidlFiles[i]);
1793     }
1794     hResult = IDataObject_Constructor(hwnd, pidlFolder, lppidlFiles, cpidlFiles, ppdataObject);
1795     return hResult;
1796 }
1797 
1798 /*************************************************************************
1799  * SHCreateStdEnumFmtEtc			[SHELL32.74]
1800  *
1801  * NOTES
1802  *
1803  */
1804 HRESULT WINAPI SHCreateStdEnumFmtEtc(
1805     UINT cFormats,
1806 	const FORMATETC *lpFormats,
1807 	LPENUMFORMATETC *ppenumFormatetc)
1808 {
1809 	IEnumFORMATETC *pef;
1810 	HRESULT hRes;
1811 	TRACE("cf=%d fe=%p pef=%p\n", cFormats, lpFormats, ppenumFormatetc);
1812 
1813     hRes = IEnumFORMATETC_Constructor(cFormats, lpFormats, &pef);
1814     if (FAILED(hRes))
1815         return hRes;
1816 
1817 	IEnumFORMATETC_AddRef(pef);
1818 	hRes = IEnumFORMATETC_QueryInterface(pef, &IID_IEnumFORMATETC, (LPVOID*)ppenumFormatetc);
1819 	IEnumFORMATETC_Release(pef);
1820 
1821 	return hRes;
1822 }
1823 
1824 /*************************************************************************
1825  *		SHFindFiles (SHELL32.90)
1826  */
1827 BOOL WINAPI SHFindFiles( LPCITEMIDLIST pidlFolder, LPCITEMIDLIST pidlSaveFile )
1828 {
1829     FIXME("%p %p\n", pidlFolder, pidlSaveFile );
1830     return FALSE;
1831 }
1832 
1833 /*************************************************************************
1834  *		SHUpdateImageW (SHELL32.192)
1835  *
1836  * Notifies the shell that an icon in the system image list has been changed.
1837  *
1838  * PARAMS
1839  *  pszHashItem [I] Path to file that contains the icon.
1840  *  iIndex      [I] Zero-based index of the icon in the file.
1841  *  uFlags      [I] Flags determining the icon attributes. See notes.
1842  *  iImageIndex [I] Index of the icon in the system image list.
1843  *
1844  * RETURNS
1845  *  Nothing
1846  *
1847  * NOTES
1848  *  uFlags can be one or more of the following flags:
1849  *  GIL_NOTFILENAME - pszHashItem is not a file name.
1850  *  GIL_SIMULATEDOC - Create a document icon using the specified icon.
1851  */
1852 void WINAPI SHUpdateImageW(LPCWSTR pszHashItem, int iIndex, UINT uFlags, int iImageIndex)
1853 {
1854     FIXME("%s, %d, 0x%x, %d - stub\n", debugstr_w(pszHashItem), iIndex, uFlags, iImageIndex);
1855 }
1856 
1857 /*************************************************************************
1858  *		SHUpdateImageA (SHELL32.191)
1859  *
1860  * See SHUpdateImageW.
1861  */
1862 VOID WINAPI SHUpdateImageA(LPCSTR pszHashItem, INT iIndex, UINT uFlags, INT iImageIndex)
1863 {
1864     FIXME("%s, %d, 0x%x, %d - stub\n", debugstr_a(pszHashItem), iIndex, uFlags, iImageIndex);
1865 }
1866 
1867 INT WINAPI SHHandleUpdateImage(LPCITEMIDLIST pidlExtra)
1868 {
1869     FIXME("%p - stub\n", pidlExtra);
1870 
1871     return -1;
1872 }
1873 
1874 BOOL WINAPI SHObjectProperties(HWND hwnd, DWORD dwType, LPCWSTR szObject, LPCWSTR szPage)
1875 {
1876     FIXME("%p, 0x%08x, %s, %s - stub\n", hwnd, dwType, debugstr_w(szObject), debugstr_w(szPage));
1877 
1878     return TRUE;
1879 }
1880 
1881 BOOL WINAPI SHGetNewLinkInfoA(LPCSTR pszLinkTo, LPCSTR pszDir, LPSTR pszName, BOOL *pfMustCopy,
1882                               UINT uFlags)
1883 {
1884     WCHAR wszLinkTo[MAX_PATH];
1885     WCHAR wszDir[MAX_PATH];
1886     WCHAR wszName[MAX_PATH];
1887     BOOL res;
1888 
1889     MultiByteToWideChar(CP_ACP, 0, pszLinkTo, -1, wszLinkTo, MAX_PATH);
1890     MultiByteToWideChar(CP_ACP, 0, pszDir, -1, wszDir, MAX_PATH);
1891 
1892     res = SHGetNewLinkInfoW(wszLinkTo, wszDir, wszName, pfMustCopy, uFlags);
1893 
1894     if (res)
1895         WideCharToMultiByte(CP_ACP, 0, wszName, -1, pszName, MAX_PATH, NULL, NULL);
1896 
1897     return res;
1898 }
1899 
1900 BOOL WINAPI SHGetNewLinkInfoW(LPCWSTR pszLinkTo, LPCWSTR pszDir, LPWSTR pszName, BOOL *pfMustCopy,
1901                               UINT uFlags)
1902 {
1903     const WCHAR *basename;
1904     WCHAR *dst_basename;
1905     int i=2;
1906     static const WCHAR lnkformat[] = {'%','s','.','l','n','k',0};
1907     static const WCHAR lnkformatnum[] = {'%','s',' ','(','%','d',')','.','l','n','k',0};
1908 
1909     TRACE("(%s, %s, %p, %p, 0x%08x)\n", debugstr_w(pszLinkTo), debugstr_w(pszDir),
1910           pszName, pfMustCopy, uFlags);
1911 
1912     *pfMustCopy = FALSE;
1913 
1914     if (uFlags & SHGNLI_PIDL)
1915     {
1916         FIXME("SHGNLI_PIDL flag unsupported\n");
1917         return FALSE;
1918     }
1919 
1920     if (uFlags)
1921         FIXME("ignoring flags: 0x%08x\n", uFlags);
1922 
1923     /* FIXME: should test if the file is a shortcut or DOS program */
1924     if (GetFileAttributesW(pszLinkTo) == INVALID_FILE_ATTRIBUTES)
1925         return FALSE;
1926 
1927     basename = strrchrW(pszLinkTo, '\\');
1928     if (basename)
1929         basename = basename+1;
1930     else
1931         basename = pszLinkTo;
1932 
1933     lstrcpynW(pszName, pszDir, MAX_PATH);
1934     if (!PathAddBackslashW(pszName))
1935         return FALSE;
1936 
1937     dst_basename = pszName + strlenW(pszName);
1938 
1939     snprintfW(dst_basename, pszName + MAX_PATH - dst_basename, lnkformat, basename);
1940 
1941     while (GetFileAttributesW(pszName) != INVALID_FILE_ATTRIBUTES)
1942     {
1943         snprintfW(dst_basename, pszName + MAX_PATH - dst_basename, lnkformatnum, basename, i);
1944         i++;
1945     }
1946 
1947     return TRUE;
1948 }
1949 
1950 HRESULT WINAPI SHStartNetConnectionDialog(HWND hwnd, LPCSTR pszRemoteName, DWORD dwType)
1951 {
1952     FIXME("%p, %s, 0x%08x - stub\n", hwnd, debugstr_a(pszRemoteName), dwType);
1953 
1954     return S_OK;
1955 }
1956 /*************************************************************************
1957  *              SHSetLocalizedName (SHELL32.@)
1958  */
1959 HRESULT WINAPI SHSetLocalizedName(LPCWSTR pszPath, LPCWSTR pszResModule, int idsRes)
1960 {
1961     FIXME("%p, %s, %d - stub\n", pszPath, debugstr_w(pszResModule), idsRes);
1962 
1963     return S_OK;
1964 }
1965 
1966 /*************************************************************************
1967  *              LinkWindow_RegisterClass (SHELL32.258)
1968  */
1969 BOOL WINAPI LinkWindow_RegisterClass(void)
1970 {
1971     FIXME("()\n");
1972     return TRUE;
1973 }
1974 
1975 /*************************************************************************
1976  *              LinkWindow_UnregisterClass (SHELL32.259)
1977  */
1978 BOOL WINAPI LinkWindow_UnregisterClass(DWORD dwUnused)
1979 {
1980     FIXME("()\n");
1981     return TRUE;
1982 }
1983 
1984 /*************************************************************************
1985  *              SHFlushSFCache (SHELL32.526)
1986  *
1987  * Notifies the shell that a user-specified special folder location has changed.
1988  *
1989  * NOTES
1990  *   In Wine, the shell folder registry values are not cached, so this function
1991  *   has no effect.
1992  */
1993 void WINAPI SHFlushSFCache(void)
1994 {
1995 }
1996 
1997 /*************************************************************************
1998  *              SHGetImageList (SHELL32.727)
1999  *
2000  * Returns a copy of a shell image list.
2001  *
2002  * NOTES
2003  *   Windows XP features 4 sizes of image list, and Vista 5. Wine currently
2004  *   only supports the traditional small and large image lists, so requests
2005  *   for the others will currently fail.
2006  */
2007 HRESULT WINAPI SHGetImageList(int iImageList, REFIID riid, void **ppv)
2008 {
2009     HIMAGELIST hLarge, hSmall;
2010     HIMAGELIST hNew;
2011     HRESULT ret = E_FAIL;
2012 
2013     /* Wine currently only maintains large and small image lists */
2014     if ((iImageList != SHIL_LARGE) && (iImageList != SHIL_SMALL) && (iImageList != SHIL_SYSSMALL))
2015     {
2016         FIXME("Unsupported image list %i requested\n", iImageList);
2017         return E_FAIL;
2018     }
2019 
2020     Shell_GetImageLists(&hLarge, &hSmall);
2021 #ifndef __REACTOS__
2022     hNew = ImageList_Duplicate(iImageList == SHIL_LARGE ? hLarge : hSmall);
2023 
2024     /* Get the interface for the new image list */
2025     if (hNew)
2026     {
2027         ret = HIMAGELIST_QueryInterface(hNew, riid, ppv);
2028         ImageList_Destroy(hNew);
2029     }
2030 #else
2031     /* Duplicating the imagelist causes the start menu items not to draw on
2032      * the first show. Was the Duplicate necessary for some reason? I believe
2033      * Windows returns the raw pointer here. */
2034     hNew = (iImageList == SHIL_LARGE ? hLarge : hSmall);
2035     ret = IImageList2_QueryInterface((IImageList2 *) hNew, riid, ppv);
2036 #endif
2037 
2038     return ret;
2039 }
2040 
2041 #ifndef __REACTOS__
2042 
2043 /*************************************************************************
2044  * SHCreateShellFolderView			[SHELL32.256]
2045  *
2046  * Create a new instance of the default Shell folder view object.
2047  *
2048  * RETURNS
2049  *  Success: S_OK
2050  *  Failure: error value
2051  *
2052  * NOTES
2053  *  see IShellFolder::CreateViewObject
2054  */
2055 HRESULT WINAPI SHCreateShellFolderView(const SFV_CREATE *pcsfv,
2056                         IShellView **ppsv)
2057 {
2058 	IShellView * psf;
2059 	HRESULT hRes;
2060 
2061 	*ppsv = NULL;
2062 	if (!pcsfv || pcsfv->cbSize != sizeof(*pcsfv))
2063 	  return E_INVALIDARG;
2064 
2065 	TRACE("sf=%p outer=%p callback=%p\n",
2066 	  pcsfv->pshf, pcsfv->psvOuter, pcsfv->psfvcb);
2067 
2068     hRes = IShellView_Constructor(pcsfv->pshf, &psf);
2069     if (FAILED(hRes))
2070         return hRes;
2071 
2072 	hRes = IShellView_QueryInterface(psf, &IID_IShellView, (LPVOID *)ppsv);
2073 	IShellView_Release(psf);
2074 
2075 	return hRes;
2076 }
2077 #endif
2078 
2079 
2080 /*************************************************************************
2081  * SHTestTokenMembership    [SHELL32.245]
2082  *
2083  * Checks whether a given token is a mamber of a local group with the
2084  * specified RID.
2085  *
2086  */
2087 EXTERN_C BOOL
2088 WINAPI
2089 SHTestTokenMembership(HANDLE TokenHandle, ULONG ulRID)
2090 {
2091     SID_IDENTIFIER_AUTHORITY ntAuth = {SECURITY_NT_AUTHORITY};
2092     DWORD nSubAuthority0, nSubAuthority1;
2093     DWORD nSubAuthorityCount;
2094     PSID SidToCheck;
2095     BOOL IsMember = FALSE;
2096 
2097     if ((ulRID == SECURITY_SERVICE_RID) || ulRID == SECURITY_LOCAL_SYSTEM_RID)
2098     {
2099         nSubAuthority0 = ulRID;
2100         nSubAuthority1 = 0;
2101         nSubAuthorityCount= 1;
2102     }
2103     else
2104     {
2105         nSubAuthority0 = SECURITY_BUILTIN_DOMAIN_RID;
2106         nSubAuthority1 = ulRID;
2107         nSubAuthorityCount= 2;
2108     }
2109 
2110     if (!AllocateAndInitializeSid(&ntAuth,
2111                                   nSubAuthorityCount,
2112                                   nSubAuthority0,
2113                                   nSubAuthority1,
2114                                   0, 0, 0, 0, 0, 0,
2115                                   &SidToCheck))
2116     {
2117         return FALSE;
2118     }
2119 
2120     if (!CheckTokenMembership(TokenHandle, SidToCheck, &IsMember))
2121     {
2122         IsMember = FALSE;
2123     }
2124 
2125     FreeSid(SidToCheck);
2126     return IsMember;
2127 }
2128 
2129 /*************************************************************************
2130  * IsUserAnAdmin    [SHELL32.680] NT 4.0
2131  *
2132  * Checks whether the current user is a member of the Administrators group.
2133  *
2134  * PARAMS
2135  *     None
2136  *
2137  * RETURNS
2138  *     Success: TRUE
2139  *     Failure: FALSE
2140  */
2141 BOOL WINAPI IsUserAnAdmin(VOID)
2142 {
2143     return SHTestTokenMembership(NULL, DOMAIN_ALIAS_RID_ADMINS);
2144 }