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