Remove clipboard merge leftover.
[reactos.git] / reactos / dll / win32 / shell32 / shfldr_fs.c
1 /*
2 * file system folder
3 *
4 * Copyright 1997 Marcus Meissner
5 * Copyright 1998, 1999, 2002 Juergen Schmied
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29
30 #define COBJMACROS
31 #define NONAMELESSUNION
32 #define NONAMELESSSTRUCT
33
34 #include "winerror.h"
35 #include "windef.h"
36 #include "winbase.h"
37 #include "winreg.h"
38 #include "wingdi.h"
39 #include "winuser.h"
40
41 #include "ole2.h"
42 #include "shlguid.h"
43
44 #include "enumidlist.h"
45 #include "pidl.h"
46 #include "undocshell.h"
47 #include "shell32_main.h"
48 #include "shresdef.h"
49 #include "shlwapi.h"
50 #include "shellfolder.h"
51 #include "wine/debug.h"
52 #include "debughlp.h"
53 #include "shfldr.h"
54
55 WINE_DEFAULT_DEBUG_CHANNEL (shell);
56
57 extern BOOL fileMoving;
58
59 /***********************************************************************
60 * IShellFolder implementation
61 */
62
63 typedef struct {
64 const IUnknownVtbl *lpVtbl;
65 LONG ref;
66 const IShellFolder2Vtbl *lpvtblShellFolder;
67 const IPersistFolder3Vtbl *lpvtblPersistFolder3;
68 const IDropTargetVtbl *lpvtblDropTarget;
69 const ISFHelperVtbl *lpvtblSFHelper;
70
71 IUnknown *pUnkOuter; /* used for aggregation */
72
73 CLSID *pclsid;
74
75 /* both paths are parsible from the desktop */
76 LPSTR sPathTarget; /* complete path to target used for enumeration and ChangeNotify */
77
78 LPITEMIDLIST pidlRoot; /* absolute pidl */
79
80 UINT cfShellIDList; /* clipboardformat for IDropTarget */
81 BOOL fAcceptFmt; /* flag for pending Drop */
82 } IGenericSFImpl;
83
84 static const IUnknownVtbl unkvt;
85 static const IShellFolder2Vtbl sfvt;
86 static const IPersistFolder3Vtbl vt_FSFldr_PersistFolder3; /* IPersistFolder3 for a FS_Folder */
87 static const IDropTargetVtbl dtvt;
88 static const ISFHelperVtbl shvt;
89
90 static inline IGenericSFImpl *impl_from_IShellFolder2( IShellFolder2 *iface )
91 {
92 return (IGenericSFImpl *)((char*)iface - FIELD_OFFSET(IGenericSFImpl, lpvtblShellFolder));
93 }
94
95 static inline IGenericSFImpl *impl_from_IPersistFolder3( IPersistFolder3 *iface )
96 {
97 return (IGenericSFImpl *)((char*)iface - FIELD_OFFSET(IGenericSFImpl, lpvtblPersistFolder3));
98 }
99
100 static inline IGenericSFImpl *impl_from_IDropTarget( IDropTarget *iface )
101 {
102 return (IGenericSFImpl *)((char*)iface - FIELD_OFFSET(IGenericSFImpl, lpvtblDropTarget));
103 }
104
105 static inline IGenericSFImpl *impl_from_ISFHelper( ISFHelper *iface )
106 {
107 return (IGenericSFImpl *)((char*)iface - FIELD_OFFSET(IGenericSFImpl, lpvtblSFHelper));
108 }
109
110
111 /*
112 converts This to an interface pointer
113 */
114 #define _IUnknown_(This) (IUnknown*)&(This->lpVtbl)
115 #define _IShellFolder_(This) (IShellFolder*)&(This->lpvtblShellFolder)
116 #define _IShellFolder2_(This) (IShellFolder2*)&(This->lpvtblShellFolder)
117 #define _IPersist_(This) (IPersist*)&(This->lpvtblPersistFolder3)
118 #define _IPersistFolder_(This) (IPersistFolder*)&(This->lpvtblPersistFolder3)
119 #define _IPersistFolder2_(This) (IPersistFolder2*)&(This->lpvtblPersistFolder3)
120 #define _IPersistFolder3_(This) (IPersistFolder3*)&(This->lpvtblPersistFolder3)
121 #define _IDropTarget_(This) (IDropTarget*)&(This->lpvtblDropTarget)
122 #define _ISFHelper_(This) (ISFHelper*)&(This->lpvtblSFHelper)
123
124 /**************************************************************************
125 * registers clipboardformat once
126 */
127 static void SF_RegisterClipFmt (IGenericSFImpl * This)
128 {
129 TRACE ("(%p)\n", This);
130
131 if (!This->cfShellIDList) {
132 This->cfShellIDList = RegisterClipboardFormatA (CFSTR_SHELLIDLIST);
133 }
134 }
135
136 /**************************************************************************
137 * we need a separate IUnknown to handle aggregation
138 * (inner IUnknown)
139 */
140 static HRESULT WINAPI IUnknown_fnQueryInterface (IUnknown * iface, REFIID riid, LPVOID * ppvObj)
141 {
142 IGenericSFImpl *This = (IGenericSFImpl *)iface;
143
144 TRACE ("(%p)->(%s,%p)\n", This, shdebugstr_guid (riid), ppvObj);
145
146 *ppvObj = NULL;
147
148 if (IsEqualIID (riid, &IID_IUnknown))
149 *ppvObj = _IUnknown_ (This);
150 else if (IsEqualIID (riid, &IID_IShellFolder))
151 *ppvObj = _IShellFolder_ (This);
152 else if (IsEqualIID (riid, &IID_IShellFolder2))
153 *ppvObj = _IShellFolder_ (This);
154 else if (IsEqualIID (riid, &IID_IPersist))
155 *ppvObj = _IPersist_ (This);
156 else if (IsEqualIID (riid, &IID_IPersistFolder))
157 *ppvObj = _IPersistFolder_ (This);
158 else if (IsEqualIID (riid, &IID_IPersistFolder2))
159 *ppvObj = _IPersistFolder2_ (This);
160 else if (IsEqualIID (riid, &IID_IPersistFolder3))
161 *ppvObj = _IPersistFolder3_ (This);
162 else if (IsEqualIID (riid, &IID_ISFHelper))
163 *ppvObj = _ISFHelper_ (This);
164 else if (IsEqualIID (riid, &IID_IDropTarget)) {
165 *ppvObj = _IDropTarget_ (This);
166 SF_RegisterClipFmt (This);
167 }
168
169 if (*ppvObj) {
170 IUnknown_AddRef ((IUnknown *) (*ppvObj));
171 TRACE ("-- Interface = %p\n", *ppvObj);
172 return S_OK;
173 }
174 TRACE ("-- Interface: E_NOINTERFACE\n");
175 return E_NOINTERFACE;
176 }
177
178 static ULONG WINAPI IUnknown_fnAddRef (IUnknown * iface)
179 {
180 IGenericSFImpl *This = (IGenericSFImpl *)iface;
181 ULONG refCount = InterlockedIncrement(&This->ref);
182
183 TRACE ("(%p)->(count=%lu)\n", This, refCount - 1);
184
185 return refCount;
186 }
187
188 static ULONG WINAPI IUnknown_fnRelease (IUnknown * iface)
189 {
190 IGenericSFImpl *This = (IGenericSFImpl *)iface;
191 ULONG refCount = InterlockedDecrement(&This->ref);
192
193 TRACE ("(%p)->(count=%lu)\n", This, refCount + 1);
194
195 if (!refCount) {
196 TRACE ("-- destroying IShellFolder(%p)\n", This);
197
198 if (This->pidlRoot)
199 SHFree (This->pidlRoot);
200 if (This->sPathTarget)
201 SHFree (This->sPathTarget);
202 LocalFree ((HLOCAL) This);
203 }
204 return refCount;
205 }
206
207 static const IUnknownVtbl unkvt =
208 {
209 IUnknown_fnQueryInterface,
210 IUnknown_fnAddRef,
211 IUnknown_fnRelease,
212 };
213
214 static shvheader GenericSFHeader[] = {
215 {IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
216 {IDS_SHV_COLUMN2, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
217 {IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
218 {IDS_SHV_COLUMN4, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 12},
219 {IDS_SHV_COLUMN5, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 5}
220 };
221
222 #define GENERICSHELLVIEWCOLUMNS 5
223
224 /**************************************************************************
225 * IFSFolder_Constructor
226 *
227 * NOTES
228 * creating undocumented ShellFS_Folder as part of an aggregation
229 * {F3364BA0-65B9-11CE-A9BA-00AA004AE837}
230 *
231 */
232 HRESULT WINAPI
233 IFSFolder_Constructor (IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv)
234 {
235 IGenericSFImpl *sf;
236
237 TRACE ("unkOut=%p %s\n", pUnkOuter, shdebugstr_guid (riid));
238
239 if (pUnkOuter && !IsEqualIID (riid, &IID_IUnknown))
240 return CLASS_E_NOAGGREGATION;
241 sf = (IGenericSFImpl *) LocalAlloc (LMEM_ZEROINIT, sizeof (IGenericSFImpl));
242 if (!sf)
243 return E_OUTOFMEMORY;
244
245 sf->ref = 0;
246 sf->lpVtbl = &unkvt;
247 sf->lpvtblShellFolder = &sfvt;
248 sf->lpvtblPersistFolder3 = &vt_FSFldr_PersistFolder3;
249 sf->lpvtblDropTarget = &dtvt;
250 sf->lpvtblSFHelper = &shvt;
251 sf->pclsid = (CLSID *) & CLSID_ShellFSFolder;
252 sf->pUnkOuter = pUnkOuter ? pUnkOuter : _IUnknown_ (sf);
253
254 if (!SUCCEEDED (IUnknown_QueryInterface (_IUnknown_ (sf), riid, ppv))) {
255 IUnknown_Release (_IUnknown_ (sf));
256 return E_NOINTERFACE;
257 }
258
259 TRACE ("--%p\n", *ppv);
260 return S_OK;
261 }
262
263 /**************************************************************************
264 * IShellFolder_fnQueryInterface
265 *
266 * PARAMETERS
267 * REFIID riid [in ] Requested InterfaceID
268 * LPVOID* ppvObject [out] Interface* to hold the result
269 */
270 static HRESULT WINAPI
271 IShellFolder_fnQueryInterface (IShellFolder2 * iface, REFIID riid,
272 LPVOID * ppvObj)
273 {
274 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
275
276 TRACE ("(%p)->(%s,%p)\n", This, shdebugstr_guid (riid), ppvObj);
277
278 return IUnknown_QueryInterface (This->pUnkOuter, riid, ppvObj);
279 }
280
281 /**************************************************************************
282 * IShellFolder_AddRef
283 */
284
285 static ULONG WINAPI IShellFolder_fnAddRef (IShellFolder2 * iface)
286 {
287 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
288
289 TRACE ("(%p)->(count=%lu)\n", This, This->ref);
290
291 return IUnknown_AddRef (This->pUnkOuter);
292 }
293
294 /**************************************************************************
295 * IShellFolder_fnRelease
296 */
297 static ULONG WINAPI IShellFolder_fnRelease (IShellFolder2 * iface)
298 {
299 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
300
301 TRACE ("(%p)->(count=%lu)\n", This, This->ref);
302
303 return IUnknown_Release (This->pUnkOuter);
304 }
305
306 /**************************************************************************
307 * SHELL32_CreatePidlFromBindCtx [internal]
308 *
309 * If the caller bound File System Bind Data, assume it is the
310 * find data for the path.
311 * This allows binding of paths that don't exist.
312 */
313 LPITEMIDLIST SHELL32_CreatePidlFromBindCtx(IBindCtx *pbc, LPCWSTR path)
314 {
315 static const WCHAR szfsbc[] = {
316 'F','i','l','e',' ','S','y','s','t','e','m',' ',
317 'B','i','n','d',' ','D','a','t','a',0 };
318 IFileSystemBindData *fsbd = NULL;
319 LPITEMIDLIST pidl = NULL;
320 IUnknown *param = NULL;
321 WIN32_FIND_DATAW wfd;
322 HRESULT r;
323
324 TRACE("%p %s\n", pbc, debugstr_w(path));
325
326 if (!pbc)
327 return NULL;
328
329 /* see if the caller bound File System Bind Data */
330 r = IBindCtx_GetObjectParam( pbc, (LPOLESTR) szfsbc, &param );
331 if (FAILED(r))
332 return NULL;
333
334 r = IUnknown_QueryInterface( param, &IID_IFileSystemBindData,
335 (LPVOID*) &fsbd );
336 if (SUCCEEDED(r))
337 {
338 r = IFileSystemBindData_GetFindData( fsbd, &wfd );
339 if (SUCCEEDED(r))
340 {
341 lstrcpynW( &wfd.cFileName[0], path, MAX_PATH );
342 pidl = _ILCreateFromFindDataW( &wfd );
343 }
344 IFileSystemBindData_Release( fsbd );
345 }
346
347 return pidl;
348 }
349
350 /**************************************************************************
351 * IShellFolder_ParseDisplayName {SHELL32}
352 *
353 * Parse a display name.
354 *
355 * PARAMS
356 * hwndOwner [in] Parent window for any message's
357 * pbc [in] optional FileSystemBindData context
358 * lpszDisplayName [in] Unicode displayname.
359 * pchEaten [out] (unicode) characters processed
360 * ppidl [out] complex pidl to item
361 * pdwAttributes [out] items attributes
362 *
363 * NOTES
364 * Every folder tries to parse only its own (the leftmost) pidl and creates a
365 * subfolder to evaluate the remaining parts.
366 * Now we can parse into namespaces implemented by shell extensions
367 *
368 * Behaviour on win98: lpszDisplayName=NULL -> crash
369 * lpszDisplayName="" -> returns mycoputer-pidl
370 *
371 * FIXME
372 * pdwAttributes is not set
373 * pchEaten is not set like in windows
374 */
375 static HRESULT WINAPI
376 IShellFolder_fnParseDisplayName (IShellFolder2 * iface,
377 HWND hwndOwner,
378 LPBC pbc,
379 LPOLESTR lpszDisplayName,
380 DWORD * pchEaten, LPITEMIDLIST * ppidl,
381 DWORD * pdwAttributes)
382 {
383 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
384
385 HRESULT hr = E_INVALIDARG;
386 LPCWSTR szNext = NULL;
387 WCHAR szElement[MAX_PATH];
388 WCHAR szPath[MAX_PATH];
389 LPITEMIDLIST pidlTemp = NULL;
390 DWORD len;
391
392 TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
393 This, hwndOwner, pbc, lpszDisplayName, debugstr_w (lpszDisplayName),
394 pchEaten, ppidl, pdwAttributes);
395
396 if (!lpszDisplayName || !ppidl)
397 return E_INVALIDARG;
398
399 if (pchEaten)
400 *pchEaten = 0; /* strange but like the original */
401
402 pidlTemp = SHELL32_CreatePidlFromBindCtx(pbc, lpszDisplayName);
403 if (!pidlTemp && *lpszDisplayName)
404 {
405 /* get the next element */
406 szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
407
408 /* build the full pathname to the element */
409 /* lstrcpyW(szPath, This->sPathTarget); */
410 MultiByteToWideChar(CP_ACP, 0, This->sPathTarget, -1, szPath, MAX_PATH);
411 PathAddBackslashW(szPath);
412 len = lstrlenW(szPath);
413 lstrcpynW(szPath + len, szElement, MAX_PATH - len);
414
415 /* get the pidl */
416 hr = _ILCreateFromPathW(szPath, &pidlTemp);
417
418 if (SUCCEEDED(hr)) {
419 if (szNext && *szNext) {
420 /* try to analyse the next element */
421 hr = SHELL32_ParseNextElement (iface, hwndOwner, pbc,
422 &pidlTemp, (LPOLESTR) szNext, pchEaten, pdwAttributes);
423 } else {
424 /* it's the last element */
425 if (pdwAttributes && *pdwAttributes) {
426 hr = SHELL32_GetItemAttributes (_IShellFolder_ (This),
427 pidlTemp, pdwAttributes);
428 }
429 }
430 }
431 }
432
433 if (SUCCEEDED(hr))
434 *ppidl = pidlTemp;
435 else
436 *ppidl = NULL;
437
438 TRACE ("(%p)->(-- pidl=%p ret=0x%08lx)\n", This, ppidl ? *ppidl : 0, hr);
439
440 return hr;
441 }
442
443 /**************************************************************************
444 * IShellFolder_fnEnumObjects
445 * PARAMETERS
446 * HWND hwndOwner, //[in ] Parent Window
447 * DWORD grfFlags, //[in ] SHCONTF enumeration mask
448 * LPENUMIDLIST* ppenumIDList //[out] IEnumIDList interface
449 */
450 static HRESULT WINAPI
451 IShellFolder_fnEnumObjects (IShellFolder2 * iface, HWND hwndOwner,
452 DWORD dwFlags, LPENUMIDLIST * ppEnumIDList)
453 {
454 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
455
456 TRACE ("(%p)->(HWND=%p flags=0x%08lx pplist=%p)\n", This, hwndOwner,
457 dwFlags, ppEnumIDList);
458
459 *ppEnumIDList = IEnumIDList_Constructor();
460 if (*ppEnumIDList)
461 {
462 WCHAR path[MAX_PATH];
463 MultiByteToWideChar(CP_ACP, 0, This->sPathTarget, -1, path, MAX_PATH);
464 CreateFolderEnumList(*ppEnumIDList, path, dwFlags);
465 }
466
467 TRACE ("-- (%p)->(new ID List: %p)\n", This, *ppEnumIDList);
468
469 return *ppEnumIDList ? S_OK : E_OUTOFMEMORY;
470 }
471
472 /**************************************************************************
473 * IShellFolder_fnBindToObject
474 * PARAMETERS
475 * LPCITEMIDLIST pidl, //[in ] relative pidl to open
476 * LPBC pbc, //[in ] optional FileSystemBindData context
477 * REFIID riid, //[in ] Initial Interface
478 * LPVOID* ppvObject //[out] Interface*
479 */
480 static HRESULT WINAPI
481 IShellFolder_fnBindToObject (IShellFolder2 * iface, LPCITEMIDLIST pidl,
482 LPBC pbc, REFIID riid, LPVOID * ppvOut)
483 {
484 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
485 WCHAR szPath[MAX_PATH];
486
487 TRACE ("(%p)->(pidl=%p,%p,%s,%p)\n", This, pidl, pbc,
488 shdebugstr_guid (riid), ppvOut);
489
490 MultiByteToWideChar(CP_ACP, 0, This->sPathTarget, -1, szPath, MAX_PATH);
491 return SHELL32_BindToChild (This->pidlRoot, szPath, pidl, riid,
492 ppvOut);
493 }
494
495 /**************************************************************************
496 * IShellFolder_fnBindToStorage
497 * PARAMETERS
498 * LPCITEMIDLIST pidl, //[in ] complex pidl to store
499 * LPBC pbc, //[in ] reserved
500 * REFIID riid, //[in ] Initial storage interface
501 * LPVOID* ppvObject //[out] Interface* returned
502 */
503 static HRESULT WINAPI
504 IShellFolder_fnBindToStorage (IShellFolder2 * iface, LPCITEMIDLIST pidl,
505 LPBC pbcReserved, REFIID riid, LPVOID * ppvOut)
506 {
507 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
508
509 FIXME ("(%p)->(pidl=%p,%p,%s,%p) stub\n", This, pidl, pbcReserved,
510 shdebugstr_guid (riid), ppvOut);
511
512 *ppvOut = NULL;
513 return E_NOTIMPL;
514 }
515
516 /**************************************************************************
517 * IShellFolder_fnCompareIDs
518 */
519
520 static HRESULT WINAPI
521 IShellFolder_fnCompareIDs (IShellFolder2 * iface, LPARAM lParam,
522 LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
523 {
524 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
525
526 int nReturn;
527
528 TRACE ("(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n", This, lParam, pidl1, pidl2);
529 nReturn = SHELL32_CompareIDs (_IShellFolder_ (This), lParam, pidl1, pidl2);
530 TRACE ("-- %i\n", nReturn);
531 return nReturn;
532 }
533
534 /**************************************************************************
535 * IShellFolder_fnCreateViewObject
536 */
537 static HRESULT WINAPI
538 IShellFolder_fnCreateViewObject (IShellFolder2 * iface, HWND hwndOwner,
539 REFIID riid, LPVOID * ppvOut)
540 {
541 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
542
543 LPSHELLVIEW pShellView;
544 HRESULT hr = E_INVALIDARG;
545
546 TRACE ("(%p)->(hwnd=%p,%s,%p)\n", This, hwndOwner, shdebugstr_guid (riid),
547 ppvOut);
548
549 if (ppvOut) {
550 *ppvOut = NULL;
551
552 if (IsEqualIID (riid, &IID_IDropTarget)) {
553 hr = IShellFolder_QueryInterface (iface, &IID_IDropTarget, ppvOut);
554 } else if (IsEqualIID (riid, &IID_IContextMenu)) {
555 FIXME ("IContextMenu not implemented\n");
556 hr = E_NOTIMPL;
557 } else if (IsEqualIID (riid, &IID_IShellView)) {
558 pShellView = IShellView_Constructor ((IShellFolder *) iface);
559 if (pShellView) {
560 hr = IShellView_QueryInterface (pShellView, riid, ppvOut);
561 IShellView_Release (pShellView);
562 }
563 }
564 }
565 TRACE ("-- (%p)->(interface=%p)\n", This, ppvOut);
566 return hr;
567 }
568
569 /**************************************************************************
570 * IShellFolder_fnGetAttributesOf
571 *
572 * PARAMETERS
573 * UINT cidl, //[in ] num elements in pidl array
574 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
575 * ULONG* rgfInOut) //[out] result array
576 *
577 */
578 static HRESULT WINAPI
579 IShellFolder_fnGetAttributesOf (IShellFolder2 * iface, UINT cidl,
580 LPCITEMIDLIST * apidl, DWORD * rgfInOut)
581 {
582 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
583
584 HRESULT hr = S_OK;
585
586 TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08lx))\n", This, cidl, apidl,
587 rgfInOut, rgfInOut ? *rgfInOut : 0);
588
589 if (!rgfInOut)
590 return E_INVALIDARG;
591 if (cidl && !apidl)
592 return E_INVALIDARG;
593
594 if (*rgfInOut == 0)
595 *rgfInOut = ~0;
596
597 if(cidl == 0){
598 IShellFolder *psfParent = NULL;
599 LPCITEMIDLIST rpidl = NULL;
600
601 hr = SHBindToParent(This->pidlRoot, &IID_IShellFolder, (LPVOID*)&psfParent, (LPCITEMIDLIST*)&rpidl);
602 if(SUCCEEDED(hr)) {
603 SHELL32_GetItemAttributes (psfParent, rpidl, rgfInOut);
604 IShellFolder_Release(psfParent);
605 }
606 }
607 else {
608 while (cidl > 0 && *apidl) {
609 pdump (*apidl);
610 SHELL32_GetItemAttributes (_IShellFolder_ (This), *apidl, rgfInOut);
611 apidl++;
612 cidl--;
613 }
614 }
615 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
616 *rgfInOut &= ~SFGAO_VALIDATE;
617
618 TRACE ("-- result=0x%08lx\n", *rgfInOut);
619
620 return hr;
621 }
622
623 /**************************************************************************
624 * IShellFolder_fnGetUIObjectOf
625 *
626 * PARAMETERS
627 * HWND hwndOwner, //[in ] Parent window for any output
628 * UINT cidl, //[in ] array size
629 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
630 * REFIID riid, //[in ] Requested Interface
631 * UINT* prgfInOut, //[ ] reserved
632 * LPVOID* ppvObject) //[out] Resulting Interface
633 *
634 * NOTES
635 * This function gets asked to return "view objects" for one or more (multiple
636 * select) items:
637 * The viewobject typically is an COM object with one of the following
638 * interfaces:
639 * IExtractIcon,IDataObject,IContextMenu
640 * In order to support icon positions in the default Listview your DataObject
641 * must implement the SetData method (in addition to GetData :) - the shell
642 * passes a barely documented "Icon positions" structure to SetData when the
643 * drag starts, and GetData's it if the drop is in another explorer window that
644 * needs the positions.
645 */
646 static HRESULT WINAPI
647 IShellFolder_fnGetUIObjectOf (IShellFolder2 * iface,
648 HWND hwndOwner,
649 UINT cidl, LPCITEMIDLIST * apidl, REFIID riid,
650 UINT * prgfInOut, LPVOID * ppvOut)
651 {
652 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
653
654 LPITEMIDLIST pidl;
655 IUnknown *pObj = NULL;
656 HRESULT hr = E_INVALIDARG;
657
658 TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
659 This, hwndOwner, cidl, apidl, shdebugstr_guid (riid), prgfInOut, ppvOut);
660
661 if (ppvOut) {
662 *ppvOut = NULL;
663
664 if (IsEqualIID (riid, &IID_IContextMenu) && (cidl >= 1)) {
665 pObj = (LPUNKNOWN) ISvItemCm_Constructor ((IShellFolder *) iface,
666 This->pidlRoot, apidl, cidl);
667 hr = S_OK;
668 } else if (IsEqualIID (riid, &IID_IDataObject) && (cidl >= 1)) {
669 pObj = (LPUNKNOWN) IDataObject_Constructor (hwndOwner,
670 This->pidlRoot, apidl, cidl);
671 hr = S_OK;
672 } else if (IsEqualIID (riid, &IID_IExtractIconA) && (cidl == 1)) {
673 pidl = ILCombine (This->pidlRoot, apidl[0]);
674 pObj = (LPUNKNOWN) IExtractIconA_Constructor (pidl);
675 SHFree (pidl);
676 hr = S_OK;
677 } else if (IsEqualIID (riid, &IID_IExtractIconW) && (cidl == 1)) {
678 pidl = ILCombine (This->pidlRoot, apidl[0]);
679 pObj = (LPUNKNOWN) IExtractIconW_Constructor (pidl);
680 SHFree (pidl);
681 hr = S_OK;
682 } else if (IsEqualIID (riid, &IID_IDropTarget) && (cidl >= 1)) {
683 hr = IShellFolder_QueryInterface (iface, &IID_IDropTarget,
684 (LPVOID *) & pObj);
685 } else if ((IsEqualIID(riid,&IID_IShellLinkW) ||
686 IsEqualIID(riid,&IID_IShellLinkA)) && (cidl == 1)) {
687 pidl = ILCombine (This->pidlRoot, apidl[0]);
688 hr = IShellLink_ConstructFromFile(NULL, riid, pidl, (LPVOID*)&pObj);
689 SHFree (pidl);
690 } else {
691 hr = E_NOINTERFACE;
692 }
693
694 if (SUCCEEDED(hr) && !pObj)
695 hr = E_OUTOFMEMORY;
696
697 *ppvOut = pObj;
698 }
699 TRACE ("(%p)->hr=0x%08lx\n", This, hr);
700 return hr;
701 }
702
703 static const WCHAR AdvancedW[] = { 'S','O','F','T','W','A','R','E',
704 '\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
705 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','E','x','p','l',
706 'o','r','e','r','\\','A','d','v','a','n','c','e','d',0 };
707 static const WCHAR HideFileExtW[] = { 'H','i','d','e','F','i','l','e','E','x',
708 't',0 };
709 static const WCHAR NeverShowExtW[] = { 'N','e','v','e','r','S','h','o','w','E',
710 'x','t',0 };
711
712 /******************************************************************************
713 * SHELL_FS_HideExtension [Internal]
714 *
715 * Query the registry if the filename extension of a given path should be
716 * hidden.
717 *
718 * PARAMS
719 * szPath [I] Relative or absolute path of a file
720 *
721 * RETURNS
722 * TRUE, if the filename's extension should be hidden
723 * FALSE, otherwise.
724 */
725 BOOL SHELL_FS_HideExtension(LPWSTR szPath)
726 {
727 HKEY hKey;
728 DWORD dwData;
729 DWORD dwDataSize = sizeof (DWORD);
730 BOOL doHide = FALSE; /* The default value is FALSE (win98 at least) */
731
732 if (!RegCreateKeyExW(HKEY_CURRENT_USER, AdvancedW, 0, 0, 0, KEY_ALL_ACCESS, 0, &hKey, 0)) {
733 if (!RegQueryValueExW(hKey, HideFileExtW, 0, 0, (LPBYTE) &dwData, &dwDataSize))
734 doHide = dwData;
735 RegCloseKey (hKey);
736 }
737
738 if (!doHide) {
739 LPWSTR ext = PathFindExtensionW(szPath);
740
741 if (*ext != '\0') {
742 WCHAR classname[MAX_PATH];
743 LONG classlen = sizeof(classname);
744
745 if (!RegQueryValueW(HKEY_CLASSES_ROOT, ext, classname, &classlen))
746 if (!RegOpenKeyW(HKEY_CLASSES_ROOT, classname, &hKey)) {
747 if (!RegQueryValueExW(hKey, NeverShowExtW, 0, NULL, NULL, NULL))
748 doHide = TRUE;
749 RegCloseKey(hKey);
750 }
751 }
752 }
753 return doHide;
754 }
755
756 void SHELL_FS_ProcessDisplayFilename(LPSTR szPath, DWORD dwFlags)
757 {
758 WCHAR pathW[MAX_PATH];
759
760 /*FIXME: MSDN also mentions SHGDN_FOREDITING which is not yet handled. */
761 if (!(dwFlags & SHGDN_FORPARSING) &&
762 ((dwFlags & SHGDN_INFOLDER) || (dwFlags == SHGDN_NORMAL))) {
763 MultiByteToWideChar(CP_ACP, 0, szPath, -1, pathW, MAX_PATH);
764 if (SHELL_FS_HideExtension(pathW) && szPath[0] != '.')
765 PathRemoveExtensionA (szPath);
766 }
767 }
768
769 /**************************************************************************
770 * IShellFolder_fnGetDisplayNameOf
771 * Retrieves the display name for the specified file object or subfolder
772 *
773 * PARAMETERS
774 * LPCITEMIDLIST pidl, //[in ] complex pidl to item
775 * DWORD dwFlags, //[in ] SHGNO formatting flags
776 * LPSTRRET lpName) //[out] Returned display name
777 *
778 * FIXME
779 * if the name is in the pidl the ret value should be a STRRET_OFFSET
780 */
781
782 static HRESULT WINAPI
783 IShellFolder_fnGetDisplayNameOf (IShellFolder2 * iface, LPCITEMIDLIST pidl,
784 DWORD dwFlags, LPSTRRET strRet)
785 {
786 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
787
788 HRESULT hr = S_OK;
789 int len = 0;
790
791 TRACE ("(%p)->(pidl=%p,0x%08lx,%p)\n", This, pidl, dwFlags, strRet);
792 pdump (pidl);
793
794 if (!pidl || !strRet)
795 return E_INVALIDARG;
796
797 strRet->uType = STRRET_CSTR;
798 if (_ILIsDesktop(pidl)) { /* empty pidl */
799 if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) &&
800 (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER))
801 {
802 if (This->sPathTarget)
803 lstrcpynA(strRet->u.cStr, This->sPathTarget, MAX_PATH);
804 } else {
805 /* pidl has to contain exactly one non null SHITEMID */
806 hr = E_INVALIDARG;
807 }
808 } else if (_ILIsPidlSimple(pidl)) {
809 if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) &&
810 (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER) &&
811 This->sPathTarget)
812 {
813 lstrcpynA(strRet->u.cStr, This->sPathTarget, MAX_PATH);
814 PathAddBackslashA(strRet->u.cStr);
815 len = lstrlenA(strRet->u.cStr);
816 }
817 _ILSimpleGetText(pidl, strRet->u.cStr + len, MAX_PATH - len);
818 if (!_ILIsFolder(pidl)) SHELL_FS_ProcessDisplayFilename(strRet->u.cStr, dwFlags);
819 } else {
820 hr = SHELL32_GetDisplayNameOfChild(iface, pidl, dwFlags, strRet->u.cStr, MAX_PATH);
821 }
822
823 TRACE ("-- (%p)->(%s)\n", This, strRet->u.cStr);
824 return hr;
825 }
826
827 /**************************************************************************
828 * IShellFolder_fnSetNameOf
829 * Changes the name of a file object or subfolder, possibly changing its item
830 * identifier in the process.
831 *
832 * PARAMETERS
833 * HWND hwndOwner, //[in ] Owner window for output
834 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
835 * LPCOLESTR lpszName, //[in ] the items new display name
836 * DWORD dwFlags, //[in ] SHGNO formatting flags
837 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
838 */
839 static HRESULT WINAPI IShellFolder_fnSetNameOf (IShellFolder2 * iface,
840 HWND hwndOwner,
841 LPCITEMIDLIST pidl,
842 LPCOLESTR lpName,
843 DWORD dwFlags,
844 LPITEMIDLIST * pPidlOut)
845 {
846 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
847 WCHAR szSrc[MAX_PATH], szDest[MAX_PATH];
848 LPWSTR ptr;
849 BOOL bIsFolder = _ILIsFolder (ILFindLastID (pidl));
850
851 TRACE ("(%p)->(%p,pidl=%p,%s,%lu,%p)\n", This, hwndOwner, pidl,
852 debugstr_w (lpName), dwFlags, pPidlOut);
853
854 /* build source path */
855 MultiByteToWideChar(CP_ACP, 0, This->sPathTarget, -1, szSrc, MAX_PATH);
856 ptr = PathAddBackslashW (szSrc);
857 if (ptr)
858 _ILSimpleGetTextW (pidl, ptr, MAX_PATH - (ptr - szSrc));
859
860 /* build destination path */
861 if (dwFlags == SHGDN_NORMAL || dwFlags & SHGDN_INFOLDER) {
862 MultiByteToWideChar(CP_ACP, 0, This->sPathTarget, -1, szDest, MAX_PATH);
863 ptr = PathAddBackslashW (szDest);
864 if (ptr)
865 lstrcpynW(ptr, lpName, MAX_PATH - (ptr - szDest));
866 } else
867 lstrcpynW(szDest, lpName, MAX_PATH);
868
869 if(!(dwFlags & SHGDN_FORPARSING) && SHELL_FS_HideExtension(szSrc)) {
870 WCHAR *ext = PathFindExtensionW(szSrc);
871 if(*ext != '\0') {
872 INT len = strlenW(szDest);
873 lstrcpynW(szDest + len, ext, MAX_PATH - len);
874 }
875 }
876
877 TRACE ("src=%s dest=%s\n", debugstr_w(szSrc), debugstr_w(szDest));
878
879 if (MoveFileW (szSrc, szDest)) {
880 HRESULT hr = S_OK;
881
882 if (pPidlOut)
883 hr = _ILCreateFromPathW(szDest, pPidlOut);
884
885 SHChangeNotify (bIsFolder ? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM,
886 SHCNF_PATHW, szSrc, szDest);
887
888 return hr;
889 }
890
891 return E_FAIL;
892 }
893
894 static HRESULT WINAPI IShellFolder_fnGetDefaultSearchGUID (IShellFolder2 *iface,
895 GUID * pguid)
896 {
897 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
898 FIXME ("(%p)\n", This);
899 return E_NOTIMPL;
900 }
901 static HRESULT WINAPI IShellFolder_fnEnumSearches (IShellFolder2 * iface,
902 IEnumExtraSearch ** ppenum)
903 {
904 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
905 FIXME ("(%p)\n", This);
906 return E_NOTIMPL;
907 }
908
909 static HRESULT WINAPI
910 IShellFolder_fnGetDefaultColumn (IShellFolder2 * iface, DWORD dwRes,
911 ULONG * pSort, ULONG * pDisplay)
912 {
913 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
914
915 TRACE ("(%p)\n", This);
916
917 if (pSort)
918 *pSort = 0;
919 if (pDisplay)
920 *pDisplay = 0;
921
922 return S_OK;
923 }
924
925 static HRESULT WINAPI
926 IShellFolder_fnGetDefaultColumnState (IShellFolder2 * iface, UINT iColumn,
927 DWORD * pcsFlags)
928 {
929 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
930
931 TRACE ("(%p)\n", This);
932
933 if (!pcsFlags || iColumn >= GENERICSHELLVIEWCOLUMNS)
934 return E_INVALIDARG;
935
936 *pcsFlags = GenericSFHeader[iColumn].pcsFlags;
937
938 return S_OK;
939 }
940
941 static HRESULT WINAPI
942 IShellFolder_fnGetDetailsEx (IShellFolder2 * iface, LPCITEMIDLIST pidl,
943 const SHCOLUMNID * pscid, VARIANT * pv)
944 {
945 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
946 FIXME ("(%p)\n", This);
947
948 return E_NOTIMPL;
949 }
950
951 static HRESULT WINAPI
952 IShellFolder_fnGetDetailsOf (IShellFolder2 * iface, LPCITEMIDLIST pidl,
953 UINT iColumn, SHELLDETAILS * psd)
954 {
955 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
956 HRESULT hr = E_FAIL;
957
958 TRACE ("(%p)->(%p %i %p)\n", This, pidl, iColumn, psd);
959
960 if (!psd || iColumn >= GENERICSHELLVIEWCOLUMNS)
961 return E_INVALIDARG;
962
963 if (!pidl) {
964 /* the header titles */
965 psd->fmt = GenericSFHeader[iColumn].fmt;
966 psd->cxChar = GenericSFHeader[iColumn].cxChar;
967 psd->str.uType = STRRET_CSTR;
968 LoadStringA (shell32_hInstance, GenericSFHeader[iColumn].colnameid,
969 psd->str.u.cStr, MAX_PATH);
970 return S_OK;
971 } else {
972 /* the data from the pidl */
973 switch (iColumn) {
974 case 0: /* name */
975 hr = IShellFolder_GetDisplayNameOf (iface, pidl,
976 SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
977 break;
978 case 1: /* size */
979 _ILGetFileSize (pidl, psd->str.u.cStr, MAX_PATH);
980 break;
981 case 2: /* type */
982 _ILGetFileType (pidl, psd->str.u.cStr, MAX_PATH);
983 break;
984 case 3: /* date */
985 _ILGetFileDate (pidl, psd->str.u.cStr, MAX_PATH);
986 break;
987 case 4: /* attributes */
988 _ILGetFileAttributes (pidl, psd->str.u.cStr, MAX_PATH);
989 break;
990 }
991 hr = S_OK;
992 psd->str.uType = STRRET_CSTR;
993 }
994
995 return hr;
996 }
997
998 static HRESULT WINAPI
999 IShellFolder_fnMapColumnToSCID (IShellFolder2 * iface, UINT column,
1000 SHCOLUMNID * pscid)
1001 {
1002 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
1003 FIXME ("(%p)\n", This);
1004 return E_NOTIMPL;
1005 }
1006
1007 static const IShellFolder2Vtbl sfvt =
1008 {
1009 IShellFolder_fnQueryInterface,
1010 IShellFolder_fnAddRef,
1011 IShellFolder_fnRelease,
1012 IShellFolder_fnParseDisplayName,
1013 IShellFolder_fnEnumObjects,
1014 IShellFolder_fnBindToObject,
1015 IShellFolder_fnBindToStorage,
1016 IShellFolder_fnCompareIDs,
1017 IShellFolder_fnCreateViewObject,
1018 IShellFolder_fnGetAttributesOf,
1019 IShellFolder_fnGetUIObjectOf,
1020 IShellFolder_fnGetDisplayNameOf,
1021 IShellFolder_fnSetNameOf,
1022 /* ShellFolder2 */
1023 IShellFolder_fnGetDefaultSearchGUID,
1024 IShellFolder_fnEnumSearches,
1025 IShellFolder_fnGetDefaultColumn,
1026 IShellFolder_fnGetDefaultColumnState,
1027 IShellFolder_fnGetDetailsEx,
1028 IShellFolder_fnGetDetailsOf,
1029 IShellFolder_fnMapColumnToSCID
1030 };
1031
1032 /****************************************************************************
1033 * ISFHelper for IShellFolder implementation
1034 */
1035
1036 static HRESULT WINAPI
1037 ISFHelper_fnQueryInterface (ISFHelper * iface, REFIID riid, LPVOID * ppvObj)
1038 {
1039 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1040
1041 TRACE ("(%p)->(count=%lu)\n", This, This->ref);
1042
1043 return IUnknown_QueryInterface (This->pUnkOuter, riid, ppvObj);
1044 }
1045
1046 static ULONG WINAPI ISFHelper_fnAddRef (ISFHelper * iface)
1047 {
1048 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1049
1050 TRACE ("(%p)->(count=%lu)\n", This, This->ref);
1051
1052 return IUnknown_AddRef (This->pUnkOuter);
1053 }
1054
1055 static ULONG WINAPI ISFHelper_fnRelease (ISFHelper * iface)
1056 {
1057 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1058
1059 TRACE ("(%p)\n", This);
1060
1061 return IUnknown_Release (This->pUnkOuter);
1062 }
1063
1064 /****************************************************************************
1065 * ISFHelper_fnAddFolder
1066 *
1067 * creates a unique folder name
1068 */
1069
1070 static HRESULT WINAPI
1071 ISFHelper_fnGetUniqueName (ISFHelper * iface, LPSTR lpName, UINT uLen)
1072 {
1073 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1074 IEnumIDList *penum;
1075 HRESULT hr;
1076 char szText[MAX_PATH];
1077 const char *szNewFolder = "New Folder";
1078
1079 TRACE ("(%p)(%s %u)\n", This, lpName, uLen);
1080
1081 if (uLen < strlen (szNewFolder) + 4)
1082 return E_POINTER;
1083
1084 strcpy (lpName, szNewFolder);
1085
1086 hr = IShellFolder_fnEnumObjects (_IShellFolder2_ (This), 0,
1087 SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &penum);
1088 if (penum) {
1089 LPITEMIDLIST pidl;
1090 DWORD dwFetched;
1091 int i = 1;
1092
1093 next:
1094 IEnumIDList_Reset (penum);
1095 while (S_OK == IEnumIDList_Next (penum, 1, &pidl, &dwFetched) &&
1096 dwFetched) {
1097 _ILSimpleGetText (pidl, szText, MAX_PATH);
1098 if (0 == strcasecmp (szText, lpName)) {
1099 sprintf (lpName, "%s %d", szNewFolder, i++);
1100 if (i > 99) {
1101 hr = E_FAIL;
1102 break;
1103 }
1104 goto next;
1105 }
1106 }
1107
1108 IEnumIDList_Release (penum);
1109 }
1110 return hr;
1111 }
1112
1113 /****************************************************************************
1114 * ISFHelper_fnAddFolder
1115 *
1116 * adds a new folder.
1117 */
1118
1119 static HRESULT WINAPI
1120 ISFHelper_fnAddFolder (ISFHelper * iface, HWND hwnd, LPCSTR lpName,
1121 LPITEMIDLIST * ppidlOut)
1122 {
1123 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1124 char lpstrNewDir[MAX_PATH];
1125 DWORD bRes;
1126 HRESULT hres = E_FAIL;
1127
1128 TRACE ("(%p)(%s %p)\n", This, lpName, ppidlOut);
1129
1130 strcpy (lpstrNewDir, This->sPathTarget);
1131 PathAppendA(lpstrNewDir, lpName);
1132
1133 bRes = CreateDirectoryA (lpstrNewDir, NULL);
1134 if (bRes) {
1135 SHChangeNotify (SHCNE_MKDIR, SHCNF_PATHA, lpstrNewDir, NULL);
1136
1137 hres = S_OK;
1138
1139 if (ppidlOut)
1140 hres = _ILCreateFromPathA(lpstrNewDir, ppidlOut);
1141 } else {
1142 char lpstrText[128 + MAX_PATH];
1143 char lpstrTempText[128];
1144 char lpstrCaption[256];
1145
1146 /* Cannot Create folder because of permissions */
1147 LoadStringA (shell32_hInstance, IDS_CREATEFOLDER_DENIED, lpstrTempText,
1148 sizeof (lpstrTempText));
1149 LoadStringA (shell32_hInstance, IDS_CREATEFOLDER_CAPTION, lpstrCaption,
1150 sizeof (lpstrCaption));
1151 sprintf (lpstrText, lpstrTempText, lpstrNewDir);
1152 MessageBoxA (hwnd, lpstrText, lpstrCaption, MB_OK | MB_ICONEXCLAMATION);
1153 }
1154
1155 return hres;
1156 }
1157
1158 /****************************************************************************
1159 * ISFHelper_fnDeleteItems
1160 *
1161 * deletes items in folder
1162 */
1163 static HRESULT WINAPI
1164 ISFHelper_fnDeleteItems (ISFHelper * iface, UINT cidl, LPCITEMIDLIST * apidl)
1165 {
1166 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1167 UINT i;
1168 char szPath[MAX_PATH];
1169 BOOL bConfirm = TRUE;
1170
1171 TRACE ("(%p)(%u %p)\n", This, cidl, apidl);
1172
1173 /* deleting multiple items so give a slightly different warning */
1174 if (cidl != 1) {
1175 char tmp[8];
1176
1177 snprintf (tmp, sizeof (tmp), "%d", cidl);
1178 if (!SHELL_ConfirmDialog(ASK_DELETE_MULTIPLE_ITEM, tmp))
1179 return E_FAIL;
1180 bConfirm = FALSE;
1181 }
1182
1183 for (i = 0; i < cidl; i++) {
1184 strcpy (szPath, This->sPathTarget);
1185 PathAddBackslashA (szPath);
1186 _ILSimpleGetText (apidl[i], szPath + strlen (szPath), MAX_PATH);
1187
1188 if (_ILIsFolder (apidl[i])) {
1189 LPITEMIDLIST pidl;
1190
1191 TRACE ("delete %s\n", szPath);
1192 if (!SHELL_DeleteDirectoryA (szPath, bConfirm)) {
1193 TRACE ("delete %s failed, bConfirm=%d\n", szPath, bConfirm);
1194 return E_FAIL;
1195 }
1196 pidl = ILCombine (This->pidlRoot, apidl[i]);
1197 SHChangeNotify (SHCNE_RMDIR, SHCNF_IDLIST, pidl, NULL);
1198 SHFree (pidl);
1199 } else if (_ILIsValue (apidl[i])) {
1200 LPITEMIDLIST pidl;
1201
1202 TRACE ("delete %s\n", szPath);
1203 if (!SHELL_DeleteFileA (szPath, bConfirm)) {
1204 TRACE ("delete %s failed, bConfirm=%d\n", szPath, bConfirm);
1205 return E_FAIL;
1206 }
1207 pidl = ILCombine (This->pidlRoot, apidl[i]);
1208 SHChangeNotify (SHCNE_DELETE, SHCNF_IDLIST, pidl, NULL);
1209 SHFree (pidl);
1210 }
1211
1212 }
1213 return S_OK;
1214 }
1215
1216 /****************************************************************************
1217 * ISFHelper_fnCopyItems
1218 *
1219 * copies items to this folder
1220 */
1221 static HRESULT WINAPI
1222 ISFHelper_fnCopyItems (ISFHelper * iface, IShellFolder * pSFFrom, UINT cidl,
1223 LPCITEMIDLIST * apidl)
1224 {
1225 UINT i;
1226 IPersistFolder2 *ppf2 = NULL;
1227 char szSrcPath[MAX_PATH],
1228 szDstPath[MAX_PATH];
1229
1230 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1231
1232 TRACE ("(%p)->(%p,%u,%p)\n", This, pSFFrom, cidl, apidl);
1233
1234 IShellFolder_QueryInterface (pSFFrom, &IID_IPersistFolder2,
1235 (LPVOID *) & ppf2);
1236 if (ppf2)
1237 {
1238 LPITEMIDLIST pidl;
1239
1240 if (SUCCEEDED (IPersistFolder2_GetCurFolder (ppf2, &pidl)))
1241 {
1242 for (i = 0; i < cidl; i++)
1243 {
1244 SHGetPathFromIDListA (pidl, szSrcPath);
1245 PathAddBackslashA (szSrcPath);
1246 _ILSimpleGetText (apidl[i], szSrcPath + strlen (szSrcPath),
1247 MAX_PATH);
1248
1249 strcpy (szDstPath, This->sPathTarget);
1250 PathAddBackslashA (szDstPath);
1251 _ILSimpleGetText (apidl[i], szDstPath + strlen (szDstPath),
1252 MAX_PATH);
1253 DPRINT1 ("copy %s to %s\n", szSrcPath, szDstPath);
1254
1255 if (fileMoving)
1256 {
1257 fileMoving = FALSE;
1258 SHNotifyMoveFileA(szSrcPath, szDstPath);
1259 }
1260 else
1261 {
1262 SHNotifyCopyFileA(szSrcPath, szDstPath, TRUE);
1263 }
1264
1265 /* FIXME: to work with folders we need SHFileOperation!
1266 SHFILEOPSTRUCTA op;
1267
1268 if (fileMoving)
1269 {
1270 op.wFunc = FO_MOVE;
1271 fileMoving = FALSE;
1272 }
1273 else
1274 {
1275 op.wFunc = FO_COPY;
1276 }
1277
1278 op.pTo = szDstPath;
1279 op.pFrom = szSrcPath;
1280 op.fFlags = FOF_SIMPLEPROGRESS;
1281 op.hwnd = NULL;
1282 op.hNameMappings = NULL;
1283 op.lpszProgressTitle = NULL;
1284
1285 UINT bRes = SHFileOperationA(&op);
1286 DbgPrint("CopyItems SHFileOperationA 0x%08x\n", bRes);
1287 */
1288
1289 }
1290 SHFree (pidl);
1291 }
1292 IPersistFolder2_Release (ppf2);
1293 }
1294 return S_OK;
1295 }
1296
1297 static const ISFHelperVtbl shvt =
1298 {
1299 ISFHelper_fnQueryInterface,
1300 ISFHelper_fnAddRef,
1301 ISFHelper_fnRelease,
1302 ISFHelper_fnGetUniqueName,
1303 ISFHelper_fnAddFolder,
1304 ISFHelper_fnDeleteItems,
1305 ISFHelper_fnCopyItems
1306 };
1307
1308 /************************************************************************
1309 * IFSFldr_PersistFolder3_QueryInterface
1310 *
1311 */
1312 static HRESULT WINAPI
1313 IFSFldr_PersistFolder3_QueryInterface (IPersistFolder3 * iface, REFIID iid,
1314 LPVOID * ppvObj)
1315 {
1316 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1317
1318 TRACE ("(%p)\n", This);
1319
1320 return IUnknown_QueryInterface (This->pUnkOuter, iid, ppvObj);
1321 }
1322
1323 /************************************************************************
1324 * IFSFldr_PersistFolder3_AddRef
1325 *
1326 */
1327 static ULONG WINAPI
1328 IFSFldr_PersistFolder3_AddRef (IPersistFolder3 * iface)
1329 {
1330 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1331
1332 TRACE ("(%p)->(count=%lu)\n", This, This->ref);
1333
1334 return IUnknown_AddRef (This->pUnkOuter);
1335 }
1336
1337 /************************************************************************
1338 * IFSFldr_PersistFolder3_Release
1339 *
1340 */
1341 static ULONG WINAPI
1342 IFSFldr_PersistFolder3_Release (IPersistFolder3 * iface)
1343 {
1344 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1345
1346 TRACE ("(%p)->(count=%lu)\n", This, This->ref);
1347
1348 return IUnknown_Release (This->pUnkOuter);
1349 }
1350
1351 /************************************************************************
1352 * IFSFldr_PersistFolder3_GetClassID
1353 */
1354 static HRESULT WINAPI
1355 IFSFldr_PersistFolder3_GetClassID (IPersistFolder3 * iface, CLSID * lpClassId)
1356 {
1357 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1358
1359 TRACE ("(%p)\n", This);
1360
1361 if (!lpClassId)
1362 return E_POINTER;
1363 *lpClassId = *This->pclsid;
1364
1365 return S_OK;
1366 }
1367
1368 /************************************************************************
1369 * IFSFldr_PersistFolder3_Initialize
1370 *
1371 * NOTES
1372 * sPathTarget is not set. Don't know how to handle in a non rooted environment.
1373 */
1374 static HRESULT WINAPI
1375 IFSFldr_PersistFolder3_Initialize (IPersistFolder3 * iface, LPCITEMIDLIST pidl)
1376 {
1377 char sTemp[MAX_PATH];
1378
1379 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1380
1381 TRACE ("(%p)->(%p)\n", This, pidl);
1382
1383 if (This->pidlRoot)
1384 SHFree (This->pidlRoot); /* free the old pidl */
1385 This->pidlRoot = ILClone (pidl); /* set my pidl */
1386
1387 if (This->sPathTarget)
1388 SHFree (This->sPathTarget);
1389
1390 /* set my path */
1391 if (SHGetPathFromIDListA (pidl, sTemp)) {
1392 This->sPathTarget = SHAlloc (strlen (sTemp) + 1);
1393 strcpy (This->sPathTarget, sTemp);
1394 }
1395
1396 TRACE ("--(%p)->(%s)\n", This, This->sPathTarget);
1397 return S_OK;
1398 }
1399
1400 /**************************************************************************
1401 * IFSFldr_PersistFolder3_GetCurFolder
1402 */
1403 static HRESULT WINAPI
1404 IFSFldr_PersistFolder3_fnGetCurFolder (IPersistFolder3 * iface,
1405 LPITEMIDLIST * pidl)
1406 {
1407 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1408
1409 TRACE ("(%p)->(%p)\n", This, pidl);
1410
1411 if (!pidl) return E_POINTER;
1412 *pidl = ILClone (This->pidlRoot);
1413 return S_OK;
1414 }
1415
1416 /**************************************************************************
1417 * IFSFldr_PersistFolder3_InitializeEx
1418 *
1419 * FIXME: error handling
1420 */
1421 static HRESULT WINAPI
1422 IFSFldr_PersistFolder3_InitializeEx (IPersistFolder3 * iface,
1423 IBindCtx * pbc, LPCITEMIDLIST pidlRoot,
1424 const PERSIST_FOLDER_TARGET_INFO * ppfti)
1425 {
1426 char sTemp[MAX_PATH];
1427
1428 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1429
1430 TRACE ("(%p)->(%p,%p,%p)\n", This, pbc, pidlRoot, ppfti);
1431 if (ppfti)
1432 TRACE ("--%p %s %s 0x%08lx 0x%08x\n",
1433 ppfti->pidlTargetFolder, debugstr_w (ppfti->szTargetParsingName),
1434 debugstr_w (ppfti->szNetworkProvider), ppfti->dwAttributes,
1435 ppfti->csidl);
1436
1437 pdump (pidlRoot);
1438 if (ppfti && ppfti->pidlTargetFolder)
1439 pdump (ppfti->pidlTargetFolder);
1440
1441 if (This->pidlRoot)
1442 __SHFreeAndNil (&This->pidlRoot); /* free the old */
1443 if (This->sPathTarget)
1444 __SHFreeAndNil (&This->sPathTarget);
1445
1446 /*
1447 * Root path and pidl
1448 */
1449 This->pidlRoot = ILClone (pidlRoot);
1450
1451 /*
1452 * the target folder is spezified in csidl OR pidlTargetFolder OR
1453 * szTargetParsingName
1454 */
1455 if (ppfti) {
1456 if (ppfti->csidl != -1) {
1457 if (SHGetSpecialFolderPathA (0, sTemp, ppfti->csidl,
1458 ppfti->csidl & CSIDL_FLAG_CREATE)) {
1459 __SHCloneStrA (&This->sPathTarget, sTemp);
1460 }
1461 } else if (ppfti->szTargetParsingName[0]) {
1462 __SHCloneStrWtoA (&This->sPathTarget, ppfti->szTargetParsingName);
1463 } else if (ppfti->pidlTargetFolder) {
1464 if (SHGetPathFromIDListA (ppfti->pidlTargetFolder, sTemp)) {
1465 __SHCloneStrA (&This->sPathTarget, sTemp);
1466 }
1467 }
1468 }
1469
1470 TRACE ("--(%p)->(target=%s)\n", This, debugstr_a (This->sPathTarget));
1471 pdump (This->pidlRoot);
1472 return (This->sPathTarget) ? S_OK : E_FAIL;
1473 }
1474
1475 static HRESULT WINAPI
1476 IFSFldr_PersistFolder3_GetFolderTargetInfo (IPersistFolder3 * iface,
1477 PERSIST_FOLDER_TARGET_INFO * ppfti)
1478 {
1479 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1480 FIXME ("(%p)->(%p)\n", This, ppfti);
1481 ZeroMemory (ppfti, sizeof (ppfti));
1482 return E_NOTIMPL;
1483 }
1484
1485 static const IPersistFolder3Vtbl vt_FSFldr_PersistFolder3 =
1486 {
1487 IFSFldr_PersistFolder3_QueryInterface,
1488 IFSFldr_PersistFolder3_AddRef,
1489 IFSFldr_PersistFolder3_Release,
1490 IFSFldr_PersistFolder3_GetClassID,
1491 IFSFldr_PersistFolder3_Initialize,
1492 IFSFldr_PersistFolder3_fnGetCurFolder,
1493 IFSFldr_PersistFolder3_InitializeEx,
1494 IFSFldr_PersistFolder3_GetFolderTargetInfo
1495 };
1496
1497 /****************************************************************************
1498 * ISFDropTarget implementation
1499 */
1500 static BOOL
1501 ISFDropTarget_QueryDrop (IDropTarget * iface, DWORD dwKeyState,
1502 LPDWORD pdwEffect)
1503 {
1504 DWORD dwEffect = *pdwEffect;
1505
1506 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1507
1508 *pdwEffect = DROPEFFECT_NONE;
1509
1510 if (This->fAcceptFmt) { /* Does our interpretation of the keystate ... */
1511 *pdwEffect = KeyStateToDropEffect (dwKeyState);
1512
1513 /* ... matches the desired effect ? */
1514 if (dwEffect & *pdwEffect) {
1515 return TRUE;
1516 }
1517 }
1518 return FALSE;
1519 }
1520
1521 static HRESULT WINAPI
1522 ISFDropTarget_QueryInterface (IDropTarget * iface, REFIID riid, LPVOID * ppvObj)
1523 {
1524 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1525
1526 TRACE ("(%p)\n", This);
1527
1528 return IUnknown_QueryInterface (This->pUnkOuter, riid, ppvObj);
1529 }
1530
1531 static ULONG WINAPI ISFDropTarget_AddRef (IDropTarget * iface)
1532 {
1533 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1534
1535 TRACE ("(%p)\n", This);
1536
1537 return IUnknown_AddRef (This->pUnkOuter);
1538 }
1539
1540 static ULONG WINAPI ISFDropTarget_Release (IDropTarget * iface)
1541 {
1542 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1543
1544 TRACE ("(%p)\n", This);
1545
1546 return IUnknown_Release (This->pUnkOuter);
1547 }
1548
1549 static HRESULT WINAPI
1550 ISFDropTarget_DragEnter (IDropTarget * iface, IDataObject * pDataObject,
1551 DWORD dwKeyState, POINTL pt, DWORD * pdwEffect)
1552 {
1553 FORMATETC fmt;
1554
1555 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1556
1557 TRACE ("(%p)->(DataObject=%p)\n", This, pDataObject);
1558
1559 InitFormatEtc (fmt, This->cfShellIDList, TYMED_HGLOBAL);
1560
1561 This->fAcceptFmt = (S_OK == IDataObject_QueryGetData (pDataObject, &fmt)) ?
1562 TRUE : FALSE;
1563
1564 ISFDropTarget_QueryDrop (iface, dwKeyState, pdwEffect);
1565
1566 return S_OK;
1567 }
1568
1569 static HRESULT WINAPI
1570 ISFDropTarget_DragOver (IDropTarget * iface, DWORD dwKeyState, POINTL pt,
1571 DWORD * pdwEffect)
1572 {
1573 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1574
1575 TRACE ("(%p)\n", This);
1576
1577 if (!pdwEffect)
1578 return E_INVALIDARG;
1579
1580 ISFDropTarget_QueryDrop (iface, dwKeyState, pdwEffect);
1581
1582 return S_OK;
1583 }
1584
1585 static HRESULT WINAPI ISFDropTarget_DragLeave (IDropTarget * iface)
1586 {
1587 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1588
1589 TRACE ("(%p)\n", This);
1590
1591 This->fAcceptFmt = FALSE;
1592
1593 return S_OK;
1594 }
1595
1596 static HRESULT WINAPI
1597 ISFDropTarget_Drop (IDropTarget * iface, IDataObject * pDataObject,
1598 DWORD dwKeyState, POINTL pt, DWORD * pdwEffect)
1599 {
1600 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1601
1602 FIXME ("(%p) object dropped\n", This);
1603
1604 return E_NOTIMPL;
1605 }
1606
1607 static const IDropTargetVtbl dtvt = {
1608 ISFDropTarget_QueryInterface,
1609 ISFDropTarget_AddRef,
1610 ISFDropTarget_Release,
1611 ISFDropTarget_DragEnter,
1612 ISFDropTarget_DragOver,
1613 ISFDropTarget_DragLeave,
1614 ISFDropTarget_Drop
1615 };