ok() does not support '%S'. Store the Ansi version, convert to Unicode
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22 #include "config.h"
23
24 #include <string.h>
25 #include <stdio.h>
26 #include "winerror.h"
27 #include "winreg.h"
28 #include "wine/debug.h"
29 #include "winnls.h"
30 #include "heap.h"
31
32 #include "shellapi.h"
33 #include "shlguid.h"
34 #include "shlobj.h"
35 #include "shell32_main.h"
36 #include "undocshell.h"
37 #include "pidl.h"
38 #include "shlwapi.h"
39 #include "commdlg.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(shell);
42 WINE_DECLARE_DEBUG_CHANNEL(pidl);
43
44 /* FIXME: !!! move CREATEMRULIST and flags to header file !!! */
45 /*        !!! it is in both here and comctl32undoc.c      !!! */
46 typedef struct tagCREATEMRULIST
47 {
48     DWORD  cbSize;        /* size of struct */
49     DWORD  nMaxItems;     /* max no. of items in list */
50     DWORD  dwFlags;       /* see below */
51     HKEY   hKey;          /* root reg. key under which list is saved */
52     LPCSTR lpszSubKey;    /* reg. subkey */
53     PROC   lpfnCompare;   /* item compare proc */
54 } CREATEMRULISTA, *LPCREATEMRULISTA;
55
56 /* dwFlags */
57 #define MRUF_STRING_LIST  0 /* list will contain strings */
58 #define MRUF_BINARY_LIST  1 /* list will contain binary data */
59 #define MRUF_DELAYED_SAVE 2 /* only save list order to reg. is FreeMRUList */
60
61 extern HANDLE WINAPI CreateMRUListA(LPCREATEMRULISTA lpcml);
62 extern DWORD  WINAPI FreeMRUList(HANDLE hMRUList);
63 extern INT    WINAPI AddMRUData(HANDLE hList, LPCVOID lpData, DWORD cbData);
64 extern INT    WINAPI FindMRUData(HANDLE hList, LPCVOID lpData, DWORD cbData, LPINT lpRegNum);
65 extern INT    WINAPI EnumMRUListA(HANDLE hList, INT nItemPos, LPVOID lpBuffer, DWORD nBufferSize);
66
67 /*************************************************************************
68  * ParseFieldA                                  [internal]
69  *
70  * copies a field from a ',' delimited string
71  *
72  * first field is nField = 1
73  */
74 DWORD WINAPI ParseFieldA(
75         LPCSTR src,
76         DWORD nField,
77         LPSTR dst,
78         DWORD len)
79 {
80         WARN("(%s,0x%08lx,%p,%ld) semi-stub.\n",debugstr_a(src),nField,dst,len);
81
82         if (!src || !src[0] || !dst || !len)
83           return 0;
84
85         /* skip n fields delimited by ',' */
86         while (nField > 1)
87         {
88           if (*src=='\0') return FALSE;
89           if (*(src++)==',') nField--;
90         }
91
92         /* copy part till the next ',' to dst */
93         while ( *src!='\0' && *src!=',' && (len--)>0 ) *(dst++)=*(src++);
94
95         /* finalize the string */
96         *dst=0x0;
97
98         return TRUE;
99 }
100
101 /*************************************************************************
102  * ParseFieldW                  [internal]
103  *
104  * copies a field from a ',' delimited string
105  *
106  * first field is nField = 1
107  */
108 DWORD WINAPI ParseFieldW(LPCWSTR src, DWORD nField, LPWSTR dst, DWORD len)
109 {
110         WARN("(%s,0x%08lx,%p,%ld) semi-stub.\n", debugstr_w(src), nField, dst, len);
111
112         if (!src || !src[0] || !dst || !len)
113           return 0;
114
115         /* skip n fields delimited by ',' */
116         while (nField > 1)
117         {
118           if (*src == 0x0) return FALSE;
119           if (*src++ == ',') nField--;
120         }
121
122         /* copy part till the next ',' to dst */
123         while ( *src != 0x0 && *src != ',' && (len--)>0 ) *(dst++) = *(src++);
124
125         /* finalize the string */
126         *dst = 0x0;
127
128         return TRUE;
129 }
130
131 /*************************************************************************
132  * ParseField                   [SHELL32.58]
133  */
134 DWORD WINAPI ParseFieldAW(LPCVOID src, DWORD nField, LPVOID dst, DWORD len)
135 {
136         if (SHELL_OsIsUnicode())
137           return ParseFieldW(src, nField, dst, len);
138         return ParseFieldA(src, nField, dst, len);
139 }
140
141 /*************************************************************************
142  * GetFileNameFromBrowse                        [SHELL32.63]
143  *
144  */
145 BOOL WINAPI GetFileNameFromBrowse(
146         HWND hwndOwner,
147         LPSTR lpstrFile,
148         DWORD nMaxFile,
149         LPCSTR lpstrInitialDir,
150         LPCSTR lpstrDefExt,
151         LPCSTR lpstrFilter,
152         LPCSTR lpstrTitle)
153 {
154     HMODULE hmodule;
155     FARPROC pGetOpenFileNameA;
156     OPENFILENAMEA ofn;
157     BOOL ret;
158
159     TRACE("%p, %s, %ld, %s, %s, %s, %s)\n",
160           hwndOwner, lpstrFile, nMaxFile, lpstrInitialDir, lpstrDefExt,
161           lpstrFilter, lpstrTitle);
162
163     hmodule = LoadLibraryA("comdlg32.dll");
164     if(!hmodule) return FALSE;
165     pGetOpenFileNameA = GetProcAddress(hmodule, "GetOpenFileNameA");
166     if(!pGetOpenFileNameA)
167     {
168         FreeLibrary(hmodule);
169         return FALSE;
170     }
171
172     memset(&ofn, 0, sizeof(ofn));
173
174     ofn.lStructSize = sizeof(ofn);
175     ofn.hwndOwner = hwndOwner;
176     ofn.lpstrFilter = lpstrFilter;
177     ofn.lpstrFile = lpstrFile;
178     ofn.nMaxFile = nMaxFile;
179     ofn.lpstrInitialDir = lpstrInitialDir;
180     ofn.lpstrTitle = lpstrTitle;
181     ofn.lpstrDefExt = lpstrDefExt;
182     ofn.Flags = OFN_EXPLORER | OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;
183     ret = pGetOpenFileNameA(&ofn);
184
185     FreeLibrary(hmodule);
186     return ret;
187 }
188
189 /*************************************************************************
190  * SHGetSetSettings                             [SHELL32.68]
191  */
192 VOID WINAPI SHGetSetSettings(LPSHELLSTATE lpss, DWORD dwMask, BOOL bSet)
193 {
194   if(bSet)
195   {
196     FIXME("%p 0x%08lx TRUE\n", lpss, dwMask);
197   }
198   else
199   {
200     SHGetSettings((LPSHELLFLAGSTATE)lpss,dwMask);
201   }
202 }
203
204 /*************************************************************************
205  * SHGetSettings                                [SHELL32.@]
206  *
207  * NOTES
208  *  the registry path are for win98 (tested)
209  *  and possibly are the same in nt40
210  *
211  */
212 VOID WINAPI SHGetSettings(LPSHELLFLAGSTATE lpsfs, DWORD dwMask)
213 {
214         HKEY    hKey;
215         DWORD   dwData;
216         DWORD   dwDataSize = sizeof (DWORD);
217
218         TRACE("(%p 0x%08lx)\n",lpsfs,dwMask);
219
220         if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced",
221                                  0, 0, 0, KEY_ALL_ACCESS, 0, &hKey, 0))
222           return;
223
224         if ( (SSF_SHOWEXTENSIONS & dwMask) && !RegQueryValueExA(hKey, "HideFileExt", 0, 0, (LPBYTE)&dwData, &dwDataSize))
225           lpsfs->fShowExtensions  = ((dwData == 0) ?  0 : 1);
226
227         if ( (SSF_SHOWINFOTIP & dwMask) && !RegQueryValueExA(hKey, "ShowInfoTip", 0, 0, (LPBYTE)&dwData, &dwDataSize))
228           lpsfs->fShowInfoTip  = ((dwData == 0) ?  0 : 1);
229
230         if ( (SSF_DONTPRETTYPATH & dwMask) && !RegQueryValueExA(hKey, "DontPrettyPath", 0, 0, (LPBYTE)&dwData, &dwDataSize))
231           lpsfs->fDontPrettyPath  = ((dwData == 0) ?  0 : 1);
232
233         if ( (SSF_HIDEICONS & dwMask) && !RegQueryValueExA(hKey, "HideIcons", 0, 0, (LPBYTE)&dwData, &dwDataSize))
234           lpsfs->fHideIcons  = ((dwData == 0) ?  0 : 1);
235
236         if ( (SSF_MAPNETDRVBUTTON & dwMask) && !RegQueryValueExA(hKey, "MapNetDrvBtn", 0, 0, (LPBYTE)&dwData, &dwDataSize))
237           lpsfs->fMapNetDrvBtn  = ((dwData == 0) ?  0 : 1);
238
239         if ( (SSF_SHOWATTRIBCOL & dwMask) && !RegQueryValueExA(hKey, "ShowAttribCol", 0, 0, (LPBYTE)&dwData, &dwDataSize))
240           lpsfs->fShowAttribCol  = ((dwData == 0) ?  0 : 1);
241
242         if (((SSF_SHOWALLOBJECTS | SSF_SHOWSYSFILES) & dwMask) && !RegQueryValueExA(hKey, "Hidden", 0, 0, (LPBYTE)&dwData, &dwDataSize))
243         { if (dwData == 0)
244           { if (SSF_SHOWALLOBJECTS & dwMask)    lpsfs->fShowAllObjects  = 0;
245             if (SSF_SHOWSYSFILES & dwMask)      lpsfs->fShowSysFiles  = 0;
246           }
247           else if (dwData == 1)
248           { if (SSF_SHOWALLOBJECTS & dwMask)    lpsfs->fShowAllObjects  = 1;
249             if (SSF_SHOWSYSFILES & dwMask)      lpsfs->fShowSysFiles  = 0;
250           }
251           else if (dwData == 2)
252           { if (SSF_SHOWALLOBJECTS & dwMask)    lpsfs->fShowAllObjects  = 0;
253             if (SSF_SHOWSYSFILES & dwMask)      lpsfs->fShowSysFiles  = 1;
254           }
255         }
256         RegCloseKey (hKey);
257
258         TRACE("-- 0x%04x\n", *(WORD*)lpsfs);
259 }
260
261 /*************************************************************************
262  * SHShellFolderView_Message                    [SHELL32.73]
263  *
264  * PARAMETERS
265  *  hwndCabinet defines the explorer cabinet window that contains the
266  *              shellview you need to communicate with
267  *  uMsg        identifying the SFVM enum to perform
268  *  lParam
269  *
270  * NOTES
271  *  Message SFVM_REARRANGE = 1
272  *    This message gets sent when a column gets clicked to instruct the
273  *    shell view to re-sort the item list. lParam identifies the column
274  *    that was clicked.
275  */
276 int WINAPI SHShellFolderView_Message(
277         HWND hwndCabinet,
278         DWORD dwMessage,
279         DWORD dwParam)
280 {
281         FIXME("%p %08lx %08lx stub\n",hwndCabinet, dwMessage, dwParam);
282         return 0;
283 }
284
285 /*************************************************************************
286  * RegisterShellHook                            [SHELL32.181]
287  *
288  * PARAMS
289  *      hwnd [I]  window handle
290  *      y    [I]  flag ????
291  *
292  * NOTES
293  *     exported by ordinal
294  */
295 BOOL WINAPI RegisterShellHook(
296         HWND hWnd,
297         DWORD dwType)
298 {
299         FIXME("(%p,0x%08lx):stub.\n",hWnd, dwType);
300         return TRUE;
301 }
302 /*************************************************************************
303  * ShellMessageBoxW                             [SHELL32.182]
304  *
305  * Format and output errormessage.
306  *
307  * idText       resource ID of title or LPSTR
308  * idTitle      resource ID of title or LPSTR
309  *
310  * NOTES
311  *     exported by ordinal
312  */
313 int WINAPIV ShellMessageBoxW(
314         HINSTANCE hInstance,
315         HWND hWnd,
316         LPCWSTR lpText,
317         LPCWSTR lpCaption,
318         UINT uType,
319         ...)
320 {
321         WCHAR   szText[100],szTitle[100];
322         LPCWSTR pszText = szText, pszTitle = szTitle, pszTemp;
323         va_list args;
324         int     ret;
325
326         va_start(args, uType);
327         /* wvsprintfA(buf,fmt, args); */
328
329         TRACE("(%08lx,%08lx,%p,%p,%08x)\n",
330         (DWORD)hInstance,(DWORD)hWnd,lpText,lpCaption,uType);
331
332         if (!HIWORD(lpCaption))
333           LoadStringW(hInstance, (DWORD)lpCaption, szTitle, sizeof(szTitle)/sizeof(szTitle[0]));
334         else
335           pszTitle = lpCaption;
336
337         if (!HIWORD(lpText))
338           LoadStringW(hInstance, (DWORD)lpText, szText, sizeof(szText)/sizeof(szText[0]));
339         else
340           pszText = lpText;
341
342         FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
343                        pszText, 0, 0, (LPWSTR)&pszTemp, 0, &args);
344
345         va_end(args);
346
347         ret = MessageBoxW(hWnd,pszTemp,pszTitle,uType);
348         LocalFree((HLOCAL)pszTemp);
349         return ret;
350 }
351
352 /*************************************************************************
353  * ShellMessageBoxA                             [SHELL32.183]
354  */
355 int WINAPIV ShellMessageBoxA(
356         HINSTANCE hInstance,
357         HWND hWnd,
358         LPCSTR lpText,
359         LPCSTR lpCaption,
360         UINT uType,
361         ...)
362 {
363         char    szText[100],szTitle[100];
364         LPCSTR  pszText = szText, pszTitle = szTitle, pszTemp;
365         va_list args;
366         int     ret;
367
368         va_start(args, uType);
369         /* wvsprintfA(buf,fmt, args); */
370
371         TRACE("(%08lx,%08lx,%p,%p,%08x)\n",
372         (DWORD)hInstance,(DWORD)hWnd,lpText,lpCaption,uType);
373
374         if (!HIWORD(lpCaption))
375           LoadStringA(hInstance, (DWORD)lpCaption, szTitle, sizeof(szTitle));
376         else
377           pszTitle = lpCaption;
378
379         if (!HIWORD(lpText))
380           LoadStringA(hInstance, (DWORD)lpText, szText, sizeof(szText));
381         else
382           pszText = lpText;
383
384         FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
385                        pszText, 0, 0, (LPSTR)&pszTemp, 0, &args);
386
387         va_end(args);
388
389         ret = MessageBoxA(hWnd,pszTemp,pszTitle,uType);
390         LocalFree((HLOCAL)pszTemp);
391         return ret;
392 }
393
394 /*************************************************************************
395  * SHRegisterDragDrop                           [SHELL32.86]
396  *
397  * NOTES
398  *     exported by ordinal
399  */
400 HRESULT WINAPI SHRegisterDragDrop(
401         HWND hWnd,
402         LPDROPTARGET pDropTarget)
403 {
404         FIXME("(%p,%p):stub.\n", hWnd, pDropTarget);
405         if (GetShellOle()) return pRegisterDragDrop(hWnd, pDropTarget);
406         return 0;
407 }
408
409 /*************************************************************************
410  * SHRevokeDragDrop                             [SHELL32.87]
411  *
412  * NOTES
413  *     exported by ordinal
414  */
415 HRESULT WINAPI SHRevokeDragDrop(HWND hWnd)
416 {
417     FIXME("(%p):stub.\n",hWnd);
418     if (GetShellOle()) return pRevokeDragDrop(hWnd);
419     return 0;
420 }
421
422 /*************************************************************************
423  * SHDoDragDrop                                 [SHELL32.88]
424  *
425  * NOTES
426  *     exported by ordinal
427  */
428 HRESULT WINAPI SHDoDragDrop(
429         HWND hWnd,
430         LPDATAOBJECT lpDataObject,
431         LPDROPSOURCE lpDropSource,
432         DWORD dwOKEffect,
433         LPDWORD pdwEffect)
434 {
435     FIXME("(%p %p %p 0x%08lx %p):stub.\n",
436     hWnd, lpDataObject, lpDropSource, dwOKEffect, pdwEffect);
437         if (GetShellOle()) return pDoDragDrop(lpDataObject, lpDropSource, dwOKEffect, pdwEffect);
438         return 0;
439 }
440
441 /*************************************************************************
442  * ArrangeWindows                               [SHELL32.184]
443  *
444  */
445 WORD WINAPI ArrangeWindows(
446         HWND hwndParent,
447         DWORD dwReserved,
448         LPCRECT lpRect,
449         WORD cKids,
450         CONST HWND * lpKids)
451 {
452     FIXME("(%p 0x%08lx %p 0x%04x %p):stub.\n",
453            hwndParent, dwReserved, lpRect, cKids, lpKids);
454     return 0;
455 }
456
457 /*************************************************************************
458  * SignalFileOpen                               [SHELL32.103]
459  *
460  * NOTES
461  *     exported by ordinal
462  */
463 DWORD WINAPI
464 SignalFileOpen (DWORD dwParam1)
465 {
466     FIXME("(0x%08lx):stub.\n", dwParam1);
467
468     return 0;
469 }
470
471 /*************************************************************************
472  * SHADD_get_policy - helper function for SHAddToRecentDocs
473  *
474  * PARAMETERS
475  *   policy    [IN]  policy name (null termed string) to find
476  *   type      [OUT] ptr to DWORD to receive type
477  *   buffer    [OUT] ptr to area to hold data retrieved
478  *   len       [IN/OUT] ptr to DWORD holding size of buffer and getting
479  *                      length filled
480  *
481  * RETURNS
482  *   result of the SHQueryValueEx call
483  */
484 static INT SHADD_get_policy(LPSTR policy, LPDWORD type, LPVOID buffer, LPDWORD len)
485 {
486     HKEY Policy_basekey;
487     INT ret;
488
489     /* Get the key for the policies location in the registry
490      */
491     if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,
492                       "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer",
493                       0, KEY_READ, &Policy_basekey)) {
494
495         if (RegOpenKeyExA(HKEY_CURRENT_USER,
496                           "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer",
497                           0, KEY_READ, &Policy_basekey)) {
498             TRACE("No Explorer Policies location exists. Policy wanted=%s\n",
499                   policy);
500             *len = 0;
501             return ERROR_FILE_NOT_FOUND;
502         }
503     }
504
505     /* Retrieve the data if it exists
506      */
507     ret = SHQueryValueExA(Policy_basekey, policy, 0, type, buffer, len);
508     RegCloseKey(Policy_basekey);
509     return ret;
510 }
511
512
513 /*************************************************************************
514  * SHADD_compare_mru - helper function for SHAddToRecentDocs
515  *
516  * PARAMETERS
517  *   data1     [IN] data being looked for
518  *   data2     [IN] data in MRU
519  *   cbdata    [IN] length from FindMRUData call (not used)
520  *
521  * RETURNS
522  *   position within MRU list that data was added.
523  */
524 static INT CALLBACK SHADD_compare_mru(LPCVOID data1, LPCVOID data2, DWORD cbData)
525 {
526     return lstrcmpiA(data1, data2);
527 }
528
529 /*************************************************************************
530  * SHADD_create_add_mru_data - helper function for SHAddToRecentDocs
531  *
532  * PARAMETERS
533  *   mruhandle    [IN] handle for created MRU list
534  *   doc_name     [IN] null termed pure doc name
535  *   new_lnk_name [IN] null termed path and file name for .lnk file
536  *   buffer       [IN/OUT] 2048 byte area to consturct MRU data
537  *   len          [OUT] ptr to int to receive space used in buffer
538  *
539  * RETURNS
540  *   position within MRU list that data was added.
541  */
542 static INT SHADD_create_add_mru_data(HANDLE mruhandle, LPSTR doc_name, LPSTR new_lnk_name,
543                                      LPSTR buffer, INT *len)
544 {
545     LPSTR ptr;
546     INT wlen;
547
548     /*FIXME: Document:
549      *  RecentDocs MRU data structure seems to be:
550      *    +0h   document file name w/ terminating 0h
551      *    +nh   short int w/ size of remaining
552      *    +n+2h 02h 30h, or 01h 30h, or 00h 30h  -  unknown
553      *    +n+4h 10 bytes zeros  -   unknown
554      *    +n+eh shortcut file name w/ terminating 0h
555      *    +n+e+nh 3 zero bytes  -  unknown
556      */
557
558     /* Create the MRU data structure for "RecentDocs"
559          */
560     ptr = buffer;
561     lstrcpyA(ptr, doc_name);
562     ptr += (lstrlenA(buffer) + 1);
563     wlen= lstrlenA(new_lnk_name) + 1 + 12;
564     *((short int*)ptr) = wlen;
565     ptr += 2;   /* step past the length */
566     *(ptr++) = 0x30;  /* unknown reason */
567     *(ptr++) = 0;     /* unknown, but can be 0x00, 0x01, 0x02 */
568     memset(ptr, 0, 10);
569     ptr += 10;
570     lstrcpyA(ptr, new_lnk_name);
571     ptr += (lstrlenA(new_lnk_name) + 1);
572     memset(ptr, 0, 3);
573     ptr += 3;
574     *len = ptr - buffer;
575
576     /* Add the new entry into the MRU list
577      */
578     return AddMRUData(mruhandle, (LPCVOID)buffer, *len);
579 }
580
581 /*************************************************************************
582  * SHAddToRecentDocs                            [SHELL32.@]
583  *
584  * PARAMETERS
585  *   uFlags  [IN] SHARD_PATH or SHARD_PIDL
586  *   pv      [IN] string or pidl, NULL clears the list
587  *
588  * NOTES
589  *     exported by name
590  *
591  * FIXME: ?? MSDN shows this as a VOID
592  */
593 DWORD WINAPI SHAddToRecentDocs (UINT uFlags,LPCVOID pv)
594 {
595 /* If list is a string list lpfnCompare has the following prototype
596  * int CALLBACK MRUCompareString(LPCSTR s1, LPCSTR s2)
597  * for binary lists the prototype is
598  * int CALLBACK MRUCompareBinary(LPCVOID data1, LPCVOID data2, DWORD cbData)
599  * where cbData is the no. of bytes to compare.
600  * Need to check what return value means identical - 0?
601  */
602
603
604     UINT olderrormode;
605     HKEY HCUbasekey;
606     CHAR doc_name[MAX_PATH];
607     CHAR link_dir[MAX_PATH];
608     CHAR new_lnk_filepath[MAX_PATH];
609     CHAR new_lnk_name[MAX_PATH];
610     IMalloc *ppM;
611     LPITEMIDLIST pidl;
612     HWND hwnd = 0;       /* FIXME:  get real window handle */
613     INT ret;
614     DWORD data[64], datalen, type;
615
616     /*FIXME: Document:
617      *  RecentDocs MRU data structure seems to be:
618      *    +0h   document file name w/ terminating 0h
619      *    +nh   short int w/ size of remaining
620      *    +n+2h 02h 30h, or 01h 30h, or 00h 30h  -  unknown
621      *    +n+4h 10 bytes zeros  -   unknown
622      *    +n+eh shortcut file name w/ terminating 0h
623      *    +n+e+nh 3 zero bytes  -  unknown
624      */
625
626     /* See if we need to do anything.
627      */
628     datalen = 64;
629     ret=SHADD_get_policy( "NoRecentDocsHistory", &type, &data, &datalen);
630     if ((ret > 0) && (ret != ERROR_FILE_NOT_FOUND)) {
631         ERR("Error %d getting policy \"NoRecentDocsHistory\"\n", ret);
632         return 0;
633     }
634     if (ret == ERROR_SUCCESS) {
635         if (!( (type == REG_DWORD) ||
636                ((type == REG_BINARY) && (datalen == 4)) )) {
637             ERR("Error policy data for \"NoRecentDocsHistory\" not formated correctly, type=%ld, len=%ld\n",
638                 type, datalen);
639             return 0;
640         }
641
642         TRACE("policy value for NoRecentDocsHistory = %08lx\n", data[0]);
643         /* now test the actual policy value */
644         if ( data[0] != 0)
645             return 0;
646     }
647
648     /* Open key to where the necessary info is
649      */
650     /* FIXME: This should be done during DLL PROCESS_ATTACH (or THREAD_ATTACH)
651      *        and the close should be done during the _DETACH. The resulting
652      *        key is stored in the DLL global data.
653      */
654     if (RegCreateKeyExA(HKEY_CURRENT_USER,
655                         "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
656                         0, 0, 0, KEY_READ, 0, &HCUbasekey, 0)) {
657         ERR("Failed to create 'Software\\Microsoft\\Windows\\CurrentVersion\\Explorer'\n");
658         return 0;
659     }
660
661     /* Get path to user's "Recent" directory
662      */
663     if(SUCCEEDED(SHGetMalloc(&ppM))) {
664         if (SUCCEEDED(SHGetSpecialFolderLocation(hwnd, CSIDL_RECENT,
665                                                  &pidl))) {
666             SHGetPathFromIDListA(pidl, link_dir);
667             IMalloc_Free(ppM, pidl);
668         }
669         else {
670             /* serious issues */
671             link_dir[0] = 0;
672             ERR("serious issues 1\n");
673         }
674         IMalloc_Release(ppM);
675     }
676     else {
677         /* serious issues */
678         link_dir[0] = 0;
679         ERR("serious issues 2\n");
680     }
681     TRACE("Users Recent dir %s\n", link_dir);
682
683     /* If no input, then go clear the lists */
684     if (!pv) {
685         /* clear user's Recent dir
686          */
687
688         /* FIXME: delete all files in "link_dir"
689          *
690          * while( more files ) {
691          *    lstrcpyA(old_lnk_name, link_dir);
692          *    PathAppendA(old_lnk_name, filenam);
693          *    DeleteFileA(old_lnk_name);
694          * }
695          */
696         FIXME("should delete all files in %s\\ \n", link_dir);
697
698         /* clear MRU list
699          */
700         /* MS Bug ?? v4.72.3612.1700 of shell32 does the delete against
701          *  HKEY_LOCAL_MACHINE version of ...CurrentVersion\Explorer
702          *  and naturally it fails w/ rc=2. It should do it against
703          *  HKEY_CURRENT_USER which is where it is stored, and where
704          *  the MRU routines expect it!!!!
705          */
706         RegDeleteKeyA(HCUbasekey, "RecentDocs");
707         RegCloseKey(HCUbasekey);
708         return 0;
709     }
710
711     /* Have data to add, the jobs to be done:
712      *   1. Add document to MRU list in registry "HKCU\Software\
713      *      Microsoft\Windows\CurrentVersion\Explorer\RecentDocs".
714      *   2. Add shortcut to document in the user's Recent directory
715      *      (CSIDL_RECENT).
716      *   3. Add shortcut to Start menu's Documents submenu.
717      */
718
719     /* Get the pure document name from the input
720      */
721     if (uFlags & SHARD_PIDL) {
722         SHGetPathFromIDListA((LPCITEMIDLIST) pv, doc_name);
723     }
724     else {
725         lstrcpyA(doc_name, (LPSTR) pv);
726     }
727     TRACE("full document name %s\n", doc_name);
728     PathStripPathA(doc_name);
729     TRACE("stripped document name %s\n", doc_name);
730
731
732     /* ***  JOB 1: Update registry for ...\Explorer\RecentDocs list  *** */
733
734     {  /* on input needs:
735         *      doc_name    -  pure file-spec, no path
736         *      link_dir    -  path to the user's Recent directory
737         *      HCUbasekey  -  key of ...Windows\CurrentVersion\Explorer" node
738         * creates:
739         *      new_lnk_name-  pure file-spec, no path for new .lnk file
740         *      new_lnk_filepath
741         *                  -  path and file name of new .lnk file
742         */
743         CREATEMRULISTA mymru;
744         HANDLE mruhandle;
745         INT len, pos, bufused, err;
746         INT i;
747         DWORD attr;
748         CHAR buffer[2048];
749         CHAR *ptr;
750         CHAR old_lnk_name[MAX_PATH];
751         short int slen;
752
753         mymru.cbSize = sizeof(CREATEMRULISTA);
754         mymru.nMaxItems = 15;
755         mymru.dwFlags = MRUF_BINARY_LIST | MRUF_DELAYED_SAVE;
756         mymru.hKey = HCUbasekey;
757         mymru.lpszSubKey = "RecentDocs";
758         mymru.lpfnCompare = &SHADD_compare_mru;
759         mruhandle = CreateMRUListA(&mymru);
760         if (!mruhandle) {
761             /* MRU failed */
762             ERR("MRU processing failed, handle zero\n");
763             RegCloseKey(HCUbasekey);
764             return 0;
765         }
766         len = lstrlenA(doc_name);
767         pos = FindMRUData(mruhandle, doc_name, len, 0);
768
769         /* Now get the MRU entry that will be replaced
770          * and delete the .lnk file for it
771          */
772         if ((bufused = EnumMRUListA(mruhandle, (pos == -1) ? 14 : pos,
773                                     buffer, 2048)) != -1) {
774             ptr = buffer;
775             ptr += (lstrlenA(buffer) + 1);
776             slen = *((short int*)ptr);
777             ptr += 2;  /* skip the length area */
778             if (bufused >= slen + (ptr-buffer)) {
779                 /* buffer size looks good */
780                 ptr += 12; /* get to string */
781                 len = bufused - (ptr-buffer);  /* get length of buf remaining */
782                 if ((lstrlenA(ptr) > 0) && (lstrlenA(ptr) <= len-1)) {
783                     /* appears to be good string */
784                     lstrcpyA(old_lnk_name, link_dir);
785                     PathAppendA(old_lnk_name, ptr);
786                     if (!DeleteFileA(old_lnk_name)) {
787                         if ((attr = GetFileAttributesA(old_lnk_name)) == -1) {
788                             if ((err = GetLastError()) != ERROR_FILE_NOT_FOUND) {
789                                 ERR("Delete for %s failed, err=%d, attr=%08lx\n",
790                                     old_lnk_name, err, attr);
791                             }
792                             else {
793                                 TRACE("old .lnk file %s did not exist\n",
794                                       old_lnk_name);
795                             }
796                         }
797                         else {
798                             ERR("Delete for %s failed, attr=%08lx\n",
799                                 old_lnk_name, attr);
800                         }
801                     }
802                     else {
803                         TRACE("deleted old .lnk file %s\n", old_lnk_name);
804                     }
805                 }
806             }
807         }
808
809         /* Create usable .lnk file name for the "Recent" directory
810          */
811         wsprintfA(new_lnk_name, "%s.lnk", doc_name);
812         lstrcpyA(new_lnk_filepath, link_dir);
813         PathAppendA(new_lnk_filepath, new_lnk_name);
814         i = 1;
815         olderrormode = SetErrorMode(SEM_FAILCRITICALERRORS);
816         while (GetFileAttributesA(new_lnk_filepath) != -1) {
817             i++;
818             wsprintfA(new_lnk_name, "%s (%u).lnk", doc_name, i);
819             lstrcpyA(new_lnk_filepath, link_dir);
820             PathAppendA(new_lnk_filepath, new_lnk_name);
821         }
822         SetErrorMode(olderrormode);
823         TRACE("new shortcut will be %s\n", new_lnk_filepath);
824
825         /* Now add the new MRU entry and data
826          */
827         pos = SHADD_create_add_mru_data(mruhandle, doc_name, new_lnk_name,
828                                         buffer, &len);
829         FreeMRUList(mruhandle);
830         TRACE("Updated MRU list, new doc is position %d\n", pos);
831     }
832
833     /* ***  JOB 2: Create shortcut in user's "Recent" directory  *** */
834
835     {  /* on input needs:
836         *      doc_name    -  pure file-spec, no path
837         *      new_lnk_filepath
838         *                  -  path and file name of new .lnk file
839         *      uFlags[in]  -  flags on call to SHAddToRecentDocs
840         *      pv[in]      -  document path/pidl on call to SHAddToRecentDocs
841         */
842         IShellLinkA *psl = NULL;
843         IPersistFile *pPf = NULL;
844         HRESULT hres;
845         CHAR desc[MAX_PATH];
846         WCHAR widelink[MAX_PATH];
847
848         CoInitialize(0);
849
850         hres = CoCreateInstance( &CLSID_ShellLink,
851                                  NULL,
852                                  CLSCTX_INPROC_SERVER,
853                                  &IID_IShellLinkA,
854                                  (LPVOID )&psl);
855         if(SUCCEEDED(hres)) {
856
857             hres = IShellLinkA_QueryInterface(psl, &IID_IPersistFile,
858                                              (LPVOID *)&pPf);
859             if(FAILED(hres)) {
860                 /* bombed */
861                 ERR("failed QueryInterface for IPersistFile %08lx\n", hres);
862                 goto fail;
863             }
864
865             /* Set the document path or pidl */
866             if (uFlags & SHARD_PIDL) {
867                 hres = IShellLinkA_SetIDList(psl, (LPCITEMIDLIST) pv);
868             } else {
869                 hres = IShellLinkA_SetPath(psl, (LPCSTR) pv);
870             }
871             if(FAILED(hres)) {
872                 /* bombed */
873                 ERR("failed Set{IDList|Path} %08lx\n", hres);
874                 goto fail;
875             }
876
877             lstrcpyA(desc, "Shortcut to ");
878             lstrcatA(desc, doc_name);
879             hres = IShellLinkA_SetDescription(psl, desc);
880             if(FAILED(hres)) {
881                 /* bombed */
882                 ERR("failed SetDescription %08lx\n", hres);
883                 goto fail;
884             }
885
886             MultiByteToWideChar(CP_ACP, 0, new_lnk_filepath, -1,
887                                 widelink, MAX_PATH);
888             /* create the short cut */
889             hres = IPersistFile_Save(pPf, widelink, TRUE);
890             if(FAILED(hres)) {
891                 /* bombed */
892                 ERR("failed IPersistFile::Save %08lx\n", hres);
893                 IPersistFile_Release(pPf);
894                 IShellLinkA_Release(psl);
895                 goto fail;
896             }
897             hres = IPersistFile_SaveCompleted(pPf, widelink);
898             IPersistFile_Release(pPf);
899             IShellLinkA_Release(psl);
900             TRACE("shortcut %s has been created, result=%08lx\n",
901                   new_lnk_filepath, hres);
902         }
903         else {
904             ERR("CoCreateInstance failed, hres=%08lx\n", hres);
905         }
906     }
907
908  fail:
909     CoUninitialize();
910
911     /* all done */
912     RegCloseKey(HCUbasekey);
913     return 0;
914 }
915
916 /*************************************************************************
917  * SHCreateShellFolderViewEx                    [SHELL32.174]
918  *
919  * NOTES
920  *  see IShellFolder::CreateViewObject
921  */
922 HRESULT WINAPI SHCreateShellFolderViewEx(
923         LPCSHELLFOLDERVIEWINFO psvcbi, /* [in] shelltemplate struct */
924         LPSHELLVIEW* ppv)              /* [out] IShellView pointer */
925 {
926         IShellView * psf;
927         HRESULT hRes;
928
929         TRACE("sf=%p pidl=%p cb=%p mode=0x%08x parm=0x%08lx\n",
930           psvcbi->pshf, psvcbi->pidlFolder, psvcbi->lpfnCallback,
931           psvcbi->uViewMode, psvcbi->dwUser);
932
933         psf = IShellView_Constructor(psvcbi->pshf);
934
935         if (!psf)
936           return E_OUTOFMEMORY;
937
938         IShellView_AddRef(psf);
939         hRes = IShellView_QueryInterface(psf, &IID_IShellView, (LPVOID *)ppv);
940         IShellView_Release(psf);
941
942         return hRes;
943 }
944 /*************************************************************************
945  *  SHWinHelp                                   [SHELL32.127]
946  *
947  */
948 HRESULT WINAPI SHWinHelp (DWORD v, DWORD w, DWORD x, DWORD z)
949 {       FIXME("0x%08lx 0x%08lx 0x%08lx 0x%08lx stub\n",v,w,x,z);
950         return 0;
951 }
952 /*************************************************************************
953  *  SHRunControlPanel [SHELL32.161]
954  *
955  */
956 HRESULT WINAPI SHRunControlPanel (DWORD x, DWORD z)
957 {       FIXME("0x%08lx 0x%08lx stub\n",x,z);
958         return 0;
959 }
960
961 static LPUNKNOWN SHELL32_IExplorerInterface=0;
962 /*************************************************************************
963  * SHSetInstanceExplorer                        [SHELL32.176]
964  *
965  * NOTES
966  *  Sets the interface
967  */
968 HRESULT WINAPI SHSetInstanceExplorer (LPUNKNOWN lpUnknown)
969 {       TRACE("%p\n", lpUnknown);
970         SHELL32_IExplorerInterface = lpUnknown;
971         return (HRESULT) lpUnknown;
972 }
973 /*************************************************************************
974  * SHGetInstanceExplorer                        [SHELL32.@]
975  *
976  * NOTES
977  *  gets the interface pointer of the explorer and a reference
978  */
979 HRESULT WINAPI SHGetInstanceExplorer (LPUNKNOWN * lpUnknown)
980 {       TRACE("%p\n", lpUnknown);
981
982         *lpUnknown = SHELL32_IExplorerInterface;
983
984         if (!SHELL32_IExplorerInterface)
985           return E_FAIL;
986
987         IUnknown_AddRef(SHELL32_IExplorerInterface);
988         return NOERROR;
989 }
990 /*************************************************************************
991  * SHFreeUnusedLibraries                        [SHELL32.123]
992  *
993  * NOTES
994  *  exported by name
995  */
996 void WINAPI SHFreeUnusedLibraries (void)
997 {
998         FIXME("stub\n");
999 }
1000 /*************************************************************************
1001  * DAD_AutoScroll                               [SHELL32.129]
1002  *
1003  */
1004 DWORD WINAPI DAD_AutoScroll(HWND hwnd, LPSCROLLSAMPLES samples, LPPOINT pt)
1005 {
1006     FIXME("hwnd = %p %p %p\n",hwnd,samples,pt);
1007     return 0;
1008 }
1009 /*************************************************************************
1010  * DAD_DragEnter                                [SHELL32.130]
1011  *
1012  */
1013 BOOL WINAPI DAD_DragEnter(HWND hwnd)
1014 {
1015     FIXME("hwnd = %p\n",hwnd);
1016     return FALSE;
1017 }
1018 /*************************************************************************
1019  * DAD_DragEnterEx                              [SHELL32.131]
1020  *
1021  */
1022 BOOL WINAPI DAD_DragEnterEx(HWND hwnd, POINT p)
1023 {
1024     FIXME("hwnd = %p (%ld,%ld)\n",hwnd,p.x,p.y);
1025     return FALSE;
1026 }
1027 /*************************************************************************
1028  * DAD_DragMove                         [SHELL32.134]
1029  *
1030  */
1031 BOOL WINAPI DAD_DragMove(POINT p)
1032 {
1033     FIXME("(%ld,%ld)\n",p.x,p.y);
1034     return FALSE;
1035 }
1036 /*************************************************************************
1037  * DAD_DragLeave                                [SHELL32.132]
1038  *
1039  */
1040 BOOL WINAPI DAD_DragLeave(VOID)
1041 {
1042     FIXME("\n");
1043     return FALSE;
1044 }
1045 /*************************************************************************
1046  * DAD_SetDragImage                             [SHELL32.136]
1047  *
1048  * NOTES
1049  *  exported by name
1050  */
1051 BOOL WINAPI DAD_SetDragImage(
1052         HIMAGELIST himlTrack,
1053         LPPOINT lppt)
1054 {
1055         FIXME("%p %p stub\n",himlTrack, lppt);
1056   return 0;
1057 }
1058 /*************************************************************************
1059  * DAD_ShowDragImage                            [SHELL32.137]
1060  *
1061  * NOTES
1062  *  exported by name
1063  */
1064 BOOL WINAPI DAD_ShowDragImage(BOOL bShow)
1065 {
1066         FIXME("0x%08x stub\n",bShow);
1067         return 0;
1068 }
1069 /*************************************************************************
1070  * ReadCabinetState                             [SHELL32.651] NT 4.0
1071  *
1072  */
1073 HRESULT WINAPI ReadCabinetState(DWORD u, DWORD v)
1074 {       FIXME("0x%04lx 0x%04lx stub\n",u,v);
1075         return 0;
1076 }
1077 /*************************************************************************
1078  * WriteCabinetState                            [SHELL32.652] NT 4.0
1079  *
1080  */
1081 HRESULT WINAPI WriteCabinetState(DWORD u)
1082 {       FIXME("0x%04lx stub\n",u);
1083         return 0;
1084 }
1085 /*************************************************************************
1086  * FileIconInit                                 [SHELL32.660]
1087  *
1088  */
1089 BOOL WINAPI FileIconInit(BOOL bFullInit)
1090 {       FIXME("(%s)\n", bFullInit ? "true" : "false");
1091         return 0;
1092 }
1093 /*************************************************************************
1094  * IsUserAdmin                                  [SHELL32.680] NT 4.0
1095  *
1096  */
1097 HRESULT WINAPI IsUserAdmin(void)
1098 {       FIXME("stub\n");
1099         return TRUE;
1100 }
1101
1102 /*************************************************************************
1103  * SHAllocShared                                [SHELL32.520]
1104  *
1105  * NOTES
1106  *  parameter1 is return value from HeapAlloc
1107  *  parameter2 is equal to the size allocated with HeapAlloc
1108  *  parameter3 is return value from GetCurrentProcessId
1109  *
1110  *  the return value is posted as lParam with 0x402 (WM_USER+2) to somewhere
1111  *  WM_USER+2 could be the undocumented CWM_SETPATH
1112  *  the allocated memory contains a pidl
1113  */
1114 HGLOBAL WINAPI SHAllocShared(LPVOID psrc, DWORD size, DWORD procID)
1115 {       HGLOBAL hmem;
1116         LPVOID pmem;
1117
1118         TRACE("ptr=%p size=0x%04lx procID=0x%04lx\n",psrc,size,procID);
1119         hmem = GlobalAlloc(GMEM_FIXED, size);
1120         if (!hmem)
1121           return 0;
1122
1123         pmem =  GlobalLock (hmem);
1124
1125         if (! pmem)
1126           return 0;
1127
1128         memcpy (pmem, psrc, size);
1129         GlobalUnlock(hmem);
1130         return hmem;
1131 }
1132 /*************************************************************************
1133  * SHLockShared                                 [SHELL32.521]
1134  *
1135  * NOTES
1136  *  parameter1 is return value from SHAllocShared
1137  *  parameter2 is return value from GetCurrentProcessId
1138  *  the receiver of (WM_USER+2) tries to lock the HANDLE (?)
1139  *  the return value seems to be a memory address
1140  */
1141 LPVOID WINAPI SHLockShared(HANDLE hmem, DWORD procID)
1142 {       TRACE("handle=%p procID=0x%04lx\n",hmem,procID);
1143         return GlobalLock(hmem);
1144 }
1145 /*************************************************************************
1146  * SHUnlockShared                               [SHELL32.522]
1147  *
1148  * NOTES
1149  *  parameter1 is return value from SHLockShared
1150  */
1151 BOOL WINAPI SHUnlockShared(LPVOID pv)
1152 {
1153         TRACE("%p\n",pv);
1154         return GlobalUnlock((HANDLE)pv);
1155 }
1156 /*************************************************************************
1157  * SHFreeShared                                 [SHELL32.523]
1158  *
1159  * NOTES
1160  *  parameter1 is return value from SHAllocShared
1161  *  parameter2 is return value from GetCurrentProcessId
1162  */
1163 BOOL WINAPI SHFreeShared(
1164         HANDLE hMem,
1165         DWORD pid)
1166 {
1167         TRACE("handle=%p 0x%04lx\n",hMem,pid);
1168         return (BOOL)GlobalFree(hMem);
1169 }
1170
1171 /*************************************************************************
1172  * SetAppStartingCursor                         [SHELL32.99]
1173  */
1174 HRESULT WINAPI SetAppStartingCursor(HWND u, DWORD v)
1175 {       FIXME("hwnd=%p 0x%04lx stub\n",u,v );
1176         return 0;
1177 }
1178 /*************************************************************************
1179  * SHLoadOLE                                    [SHELL32.151]
1180  *
1181  */
1182 HRESULT WINAPI SHLoadOLE(DWORD u)
1183 {       FIXME("0x%04lx stub\n",u);
1184         return S_OK;
1185 }
1186 /*************************************************************************
1187  * DriveType                                    [SHELL32.64]
1188  *
1189  */
1190 HRESULT WINAPI DriveType(DWORD u)
1191 {       FIXME("0x%04lx stub\n",u);
1192         return 0;
1193 }
1194 /*************************************************************************
1195  * SHAbortInvokeCommand                         [SHELL32.198]
1196  *
1197  */
1198 HRESULT WINAPI SHAbortInvokeCommand(void)
1199 {       FIXME("stub\n");
1200         return 1;
1201 }
1202 /*************************************************************************
1203  * SHOutOfMemoryMessageBox                      [SHELL32.126]
1204  *
1205  */
1206 int WINAPI SHOutOfMemoryMessageBox(
1207         HWND hwndOwner,
1208         LPCSTR lpCaption,
1209         UINT uType)
1210 {
1211         FIXME("%p %s 0x%08x stub\n",hwndOwner, lpCaption, uType);
1212         return 0;
1213 }
1214 /*************************************************************************
1215  * SHFlushClipboard                             [SHELL32.121]
1216  *
1217  */
1218 HRESULT WINAPI SHFlushClipboard(void)
1219 {       FIXME("stub\n");
1220         return 1;
1221 }
1222
1223 /*************************************************************************
1224  * SHWaitForFileToOpen                          [SHELL32.97]
1225  *
1226  */
1227 BOOL WINAPI SHWaitForFileToOpen(
1228         LPCITEMIDLIST pidl,
1229         DWORD dwFlags,
1230         DWORD dwTimeout)
1231 {
1232         FIXME("%p 0x%08lx 0x%08lx stub\n", pidl, dwFlags, dwTimeout);
1233         return 0;
1234 }
1235
1236 /************************************************************************
1237  *      @                               [SHELL32.654]
1238  *
1239  * NOTES: first parameter seems to be a pointer (same as passed to WriteCabinetState)
1240  * second one could be a size (0x0c). The size is the same as the structure saved to
1241  * HCU\Software\Microsoft\Windows\CurrentVersion\Explorer\CabinetState
1242  * I'm (js) guessing: this one is just ReadCabinetState ;-)
1243  */
1244 HRESULT WINAPI shell32_654 (DWORD x, DWORD y)
1245 {       FIXME("0x%08lx 0x%08lx stub\n",x,y);
1246         return 0;
1247 }
1248
1249 /************************************************************************
1250  *      RLBuildListOfPaths                      [SHELL32.146]
1251  *
1252  * NOTES
1253  *   builds a DPA
1254  */
1255 DWORD WINAPI RLBuildListOfPaths (void)
1256 {       FIXME("stub\n");
1257         return 0;
1258 }
1259 /************************************************************************
1260  *      SHValidateUNC                           [SHELL32.173]
1261  *
1262  */
1263 HRESULT WINAPI SHValidateUNC (DWORD x, DWORD y, DWORD z)
1264 {
1265         FIXME("0x%08lx 0x%08lx 0x%08lx stub\n",x,y,z);
1266         return 0;
1267 }
1268
1269 /************************************************************************
1270  *      DoEnvironmentSubstA                     [SHELL32.@]
1271  *
1272  */
1273 HRESULT WINAPI DoEnvironmentSubstA(LPSTR x, LPSTR y)
1274 {
1275         FIXME("(%s, %s) stub\n", debugstr_a(x), debugstr_a(y));
1276         return 0;
1277 }
1278
1279 /************************************************************************
1280  *      DoEnvironmentSubstW                     [SHELL32.@]
1281  *
1282  */
1283 HRESULT WINAPI DoEnvironmentSubstW(LPWSTR x, LPWSTR y)
1284 {
1285         FIXME("(%s, %s): stub\n", debugstr_w(x), debugstr_w(y));
1286         return 0;
1287 }
1288
1289 /************************************************************************
1290  *      DoEnvironmentSubst                      [SHELL32.53]
1291  *
1292  */
1293 HRESULT WINAPI DoEnvironmentSubstAW(LPVOID x, LPVOID y)
1294 {
1295         if (SHELL_OsIsUnicode())
1296           return DoEnvironmentSubstW(x, y);
1297         return DoEnvironmentSubstA(x, y);
1298 }
1299
1300 /*************************************************************************
1301  *      @                             [SHELL32.243]
1302  *
1303  * Win98+ by-ordinal routine.  In Win98 this routine returns zero and
1304  * does nothing else.  Possibly this does something in NT or SHELL32 5.0?
1305  *
1306  */
1307
1308 BOOL WINAPI shell32_243(DWORD a, DWORD b)
1309 {
1310   return FALSE;
1311 }
1312
1313 /*************************************************************************
1314  *      @       [SHELL32.714]
1315  */
1316 DWORD WINAPI SHELL32_714(LPVOID x)
1317 {
1318         FIXME("(%s)stub\n", debugstr_w(x));
1319         return 0;
1320 }
1321
1322 /*************************************************************************
1323  *      SHAddFromPropSheetExtArray      [SHELL32.167]
1324  */
1325 DWORD WINAPI SHAddFromPropSheetExtArray(DWORD a, DWORD b, DWORD c)
1326 {
1327         FIXME("(%08lx,%08lx,%08lx)stub\n", a, b, c);
1328         return 0;
1329 }
1330
1331 /*************************************************************************
1332  *      SHCreatePropSheetExtArray       [SHELL32.168]
1333  */
1334 DWORD WINAPI SHCreatePropSheetExtArray(DWORD a, LPCSTR b, DWORD c)
1335 {
1336         FIXME("(%08lx,%s,%08lx)stub\n", a, debugstr_a(b), c);
1337         return 0;
1338 }
1339
1340 /*************************************************************************
1341  *      SHReplaceFromPropSheetExtArray  [SHELL32.170]
1342  */
1343 DWORD WINAPI SHReplaceFromPropSheetExtArray(DWORD a, DWORD b, DWORD c, DWORD d)
1344 {
1345         FIXME("(%08lx,%08lx,%08lx,%08lx)stub\n", a, b, c, d);
1346         return 0;
1347 }
1348
1349 /*************************************************************************
1350  *      SHDestroyPropSheetExtArray      [SHELL32.169]
1351  */
1352 DWORD WINAPI SHDestroyPropSheetExtArray(DWORD a)
1353 {
1354         FIXME("(%08lx)stub\n", a);
1355         return 0;
1356 }
1357
1358 /*************************************************************************
1359  *      CIDLData_CreateFromIDArray      [SHELL32.83]
1360  *
1361  *  Create IDataObject from PIDLs??
1362  */
1363 HRESULT WINAPI CIDLData_CreateFromIDArray(
1364         LPCITEMIDLIST pidlFolder,
1365         DWORD cpidlFiles,
1366         LPCITEMIDLIST *lppidlFiles,
1367         LPDATAOBJECT *ppdataObject)
1368 {
1369     UINT i;
1370     HWND hwnd = 0;   /*FIXME: who should be hwnd of owner? set to desktop */
1371
1372     TRACE("(%p, %ld, %p, %p)\n", pidlFolder, cpidlFiles, lppidlFiles, ppdataObject);
1373     if (TRACE_ON(pidl))
1374     {
1375         pdump (pidlFolder);
1376         for (i=0; i<cpidlFiles; i++) pdump (lppidlFiles[i]);
1377     }
1378     *ppdataObject = IDataObject_Constructor( hwnd, pidlFolder,
1379                                              lppidlFiles, cpidlFiles);
1380     if (*ppdataObject) return S_OK;
1381     return E_OUTOFMEMORY;
1382 }
1383
1384 /*************************************************************************
1385  * SHCreateStdEnumFmtEtc                        [SHELL32.74]
1386  *
1387  * NOTES
1388  *
1389  */
1390 HRESULT WINAPI SHCreateStdEnumFmtEtc(
1391         DWORD cFormats,
1392         const FORMATETC *lpFormats,
1393         LPENUMFORMATETC *ppenumFormatetc)
1394 {
1395         IEnumFORMATETC *pef;
1396         HRESULT hRes;
1397         TRACE("cf=%ld fe=%p pef=%p\n", cFormats, lpFormats, ppenumFormatetc);
1398
1399         pef = IEnumFORMATETC_Constructor(cFormats, lpFormats);
1400         if (!pef)
1401           return E_OUTOFMEMORY;
1402
1403         IEnumFORMATETC_AddRef(pef);
1404         hRes = IEnumFORMATETC_QueryInterface(pef, &IID_IEnumFORMATETC, (LPVOID*)ppenumFormatetc);
1405         IEnumFORMATETC_Release(pef);
1406
1407         return hRes;
1408 }