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