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