source: trunk/Erasext/ErasextMenu.cpp @ 36

Revision 36, 25.0 KB checked in by lowjoel, 7 years ago (diff)

Fixed the case of the duplicate menu items in the explorer context menu. This closes http://bbs.heidi.ie/viewtopic.php?t=2475.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1// ErasextMenu.cpp
2// $Id$
3//
4// Eraser. Secure data removal. For Windows.
5// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
6// Copyright © 2007 The Eraser Project.
7//
8// This program is free software; you can redistribute it and/or
9// modify it under the terms of the GNU General Public License
10// as published by the Free Software Foundation; either version 2
11// of the License, or (at your option) any later version.
12//
13// This program 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
16// GNU General Public License for more details.
17//
18// You should have received a copy of the GNU General Public License
19// along with this program; if not, write to the Free Software
20// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21// 02111-1307, USA.
22
23#include "stdafx.h"
24#include "resource.h"
25#include "..\EraserDll\eraserdll.h"
26#include "..\shared\FileHelper.h"
27#include "..\shared\key.h"
28
29#include "ConfirmDialog.h"
30#include "ConfirmReplaceDlg.h"
31#include "WipeProgDlg.h"
32
33#include <shlobj.h>
34
35#include "Erasext.h"
36#include "ErasextMenu.h"
37
38#define ResultFromShort(i)  MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, (i));
39
40#ifdef _DEBUG
41#define new DEBUG_NEW
42#undef THIS_FILE
43static char THIS_FILE[] = __FILE__;
44#endif
45
46const LPCTSTR szAccelerKey = "Acceler";
47
48/////////////////////////////////////////////////////////////////////////////
49// CErasextMenu
50enum
51{
52    CMD_ERASE = 0, CMD_MOVE = 1
53};
54IMPLEMENT_DYNCREATE(CErasextMenu, CCmdTarget)
55
56static void DisplayError(DWORD dwError)
57{
58    LPVOID lpMsgBuf;
59
60    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
61                  NULL,
62                  dwError,
63                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
64                  (LPTSTR) &lpMsgBuf,
65                  0,
66                  NULL);
67
68    AfxMessageBox((LPCTSTR)lpMsgBuf, MB_ICONERROR);
69
70    // free the buffer
71    LocalFree(lpMsgBuf);
72}
73
74CErasextMenu::CErasextMenu() :
75m_bUseFiles(TRUE),
76m_dwItems(0),
77m_dwDirectories(0),
78m_bDragMenu(FALSE)
79{
80    EnableAutomation();
81
82    // To keep the application running as long as an OLE automation
83    // object is active, the constructor calls AfxOleLockApp.
84
85    AfxOleLockApp();
86
87    // NT or not
88    OSVERSIONINFO ov;
89
90    ZeroMemory(&ov, sizeof(OSVERSIONINFO));
91    ov.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
92
93    GetVersionEx(&ov);
94    m_bNT = true;//(ov.dwPlatformId == VER_PLATFORM_WIN32_NT);
95}
96
97CErasextMenu::~CErasextMenu()
98{
99    // To terminate the application when all objects created with
100    // with OLE automation, the destructor calls AfxOleUnlockApp.
101
102    AfxOleUnlockApp();
103}
104
105
106void CErasextMenu::OnFinalRelease()
107{
108    // When the last reference for an automation object is released
109    // OnFinalRelease is called.  The base class will automatically
110    // deletes the object.  Add additional cleanup required for your
111    // object before calling the base class.
112
113    CCmdTarget::OnFinalRelease();
114}
115
116
117BEGIN_MESSAGE_MAP(CErasextMenu, CCmdTarget)
118    //{{AFX_MSG_MAP(CErasextMenu)
119        // NOTE - the ClassWizard will add and remove mapping macros here.
120    //}}AFX_MSG_MAP
121END_MESSAGE_MAP()
122
123BEGIN_DISPATCH_MAP(CErasextMenu, CCmdTarget)
124    //{{AFX_DISPATCH_MAP(CErasextMenu)
125        // NOTE - the ClassWizard will add and remove mapping macros here.
126    //}}AFX_DISPATCH_MAP
127END_DISPATCH_MAP()
128
129// Note: we add support for IID_IErasextMenu to support typesafe binding
130//  from VBA.  This IID must match the GUID that is attached to the
131//  dispinterface in the .ODL file.
132
133// {8BE13461-936F-11D1-A87D-444553540000}
134static const IID IID_IErasextMenu =
135{ 0x8be13461, 0x936f, 0x11d1, { 0xa8, 0x7d, 0x44, 0x45, 0x53, 0x54, 0x0, 0x0 } };
136
137IMPLEMENT_OLECREATE(CErasextMenu, "ErasextMenu", 0x8be13461, 0x936f, 0x11d1, 0xa8, 0x7d, 0x44, 0x45, 0x53, 0x54, 0x0, 0x0);
138
139BEGIN_INTERFACE_MAP(CErasextMenu, CCmdTarget)
140    INTERFACE_PART(CErasextMenu, IID_IErasextMenu, Dispatch)
141    INTERFACE_PART(CErasextMenu, IID_IContextMenu, MenuExt)
142    INTERFACE_PART(CErasextMenu, IID_IShellExtInit, ShellInit)
143END_INTERFACE_MAP()
144
145// IUnknown for IContextMenu
146STDMETHODIMP CErasextMenu::XMenuExt::QueryInterface(REFIID riid, void** ppv)
147{
148    METHOD_PROLOGUE(CErasextMenu, MenuExt);
149    TRACE("CErasextMenu::XMenuExt::QueryInterface\n");
150    return pThis->ExternalQueryInterface(&riid, ppv);
151}
152
153STDMETHODIMP_(ULONG) CErasextMenu::XMenuExt::AddRef(void)
154{
155    METHOD_PROLOGUE(CErasextMenu, MenuExt);
156    TRACE("CErasextMenu::XMenuExt::AddRef\n");
157    return pThis->ExternalAddRef();
158}
159
160STDMETHODIMP_(ULONG) CErasextMenu::XMenuExt::Release(void)
161{
162    METHOD_PROLOGUE(CErasextMenu, MenuExt);
163    TRACE("CErasextMenu::XMenuExt::Release\n");
164    return pThis->ExternalRelease();
165}
166
167CString setShortcut(CString str)
168{
169    CKey kReg;
170    CString strPath(""), strKey(""), strRes("");
171    strPath.Format("%s\\%s", ERASER_REGISTRY_BASE, szAccelerKey);
172    int iPos;
173    if (kReg.Open(HKEY_CURRENT_USER, strPath,FALSE))
174    {
175        if ((iPos=str.Find('&'))!=-1) {
176            str = str.Left(iPos) + str.Right(str.GetLength()-iPos-1);
177        }
178        if (kReg.GetValue(strKey,str))
179        {           
180            CString strTmp(str);
181            strKey.MakeUpper();
182            strTmp.MakeUpper();
183            iPos=strTmp.Find(strKey[0]);
184            strRes = str.Left(iPos)+"&"+str.Right(str.GetLength()-iPos);
185        }
186        kReg.Close();
187    }   
188    else{
189        strRes = str;
190    }
191    return strRes;
192}
193
194STDMETHODIMP CErasextMenu::XMenuExt::QueryContextMenu(HMENU hMenu, UINT nIndex, UINT idCmdFirst, UINT /*idCmdLast*/, UINT uFlags)
195{
196    METHOD_PROLOGUE(CErasextMenu, MenuExt);
197
198    // do not show menu for shortcuts or when the shell
199    // wants only the default item, or if the user has disabled
200    // the shell extension
201
202    CKey kReg;
203    BOOL bEnabled = TRUE;
204
205    if (kReg.Open(HKEY_CURRENT_USER, ERASER_REGISTRY_BASE))
206    {
207        kReg.GetValue(bEnabled, ERASEXT_REGISTRY_ENABLED, TRUE);
208        kReg.Close();
209    }
210
211    if (bEnabled && (uFlags & CMF_VERBSONLY) == 0 && (uFlags & CMF_DEFAULTONLY) == 0)
212    {
213        CString str;
214
215        try
216        {
217            UINT startIndex = nIndex;
218            if (!pThis->m_bDragMenu)
219            {
220                if (!InsertMenu(hMenu, nIndex++, MF_SEPARATOR | MF_BYPOSITION, idCmdFirst , ""))
221                    return ResultFromShort(0);
222
223                if (!pThis->m_bUseFiles)
224                    str.LoadString(IDS_MENU_TEXT_DRIVE);
225                else
226                    str.LoadString(IDS_MENU_TEXT_FILE);
227
228                str = setShortcut(str);
229                if (!InsertMenu(hMenu, nIndex++ , MF_STRING | MF_BYPOSITION, idCmdFirst + CMD_ERASE, str))
230                    return ResultFromShort(0);
231            }
232
233            if (pThis->m_bUseFiles)
234            {
235                str.LoadString(IDS_MENU_TEXT_DRAG);
236                str = setShortcut(str);
237                if (!InsertMenu(hMenu, nIndex++ , MF_STRING | MF_BYPOSITION, idCmdFirst + CMD_MOVE, str))
238                    return ResultFromShort(0);
239            }
240
241            if (!InsertMenu(hMenu, nIndex++, MF_SEPARATOR | MF_BYPOSITION, idCmdFirst , ""))
242                return ResultFromShort(0);
243
244            return MAKE_HRESULT(SEVERITY_SUCCESS, 0, nIndex - startIndex);
245        }
246        catch (CException *e)
247        {
248            ASSERT(FALSE);
249
250            e->ReportError(MB_ICONERROR);
251            e->Delete();
252        }
253        catch (...)
254        {
255            ASSERT(FALSE);
256        }
257    }
258
259    return ResultFromShort(0);
260}
261
262BOOL GetFolder(HWND hParent, TCHAR* path)
263{
264
265    BROWSEINFO bi;
266    memset(&bi, 0, sizeof (bi));
267    bi.hwndOwner = hParent;
268    bi.ulFlags = BIF_NEWDIALOGSTYLE | BIF_EDITBOX;
269    bi.lpszTitle = "Select target folder";
270
271
272    LPITEMIDLIST pidlFolder;
273    pidlFolder = SHBrowseForFolder(&bi);
274    if (!pidlFolder)
275        return FALSE;
276
277    //HRESULT hr = SHGetTargetFolderIDList(pidlFolder, &pidlTarget);
278
279
280
281    SHGetPathFromIDList(pidlFolder, path);   // Make sure it is a path
282    CoTaskMemFree(pidlFolder);
283
284    return TRUE;
285   
286}
287STDMETHODIMP CErasextMenu::XMenuExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
288{
289    METHOD_PROLOGUE(CErasextMenu, MenuExt);
290    TRACE("CErasextMenu::XMenuExt::InvokeCommand\n");
291
292    if (!HIWORD(lpici->lpVerb) &&
293        CMD_ERASE == LOWORD((DWORD)lpici->lpVerb) || CMD_MOVE == LOWORD((DWORD)lpici->lpVerb) )
294    {
295        ASSERT(IsWindow(lpici->hwnd));
296
297        CWnd parent;
298        parent.Attach(lpici->hwnd);
299
300        if (CMD_MOVE == LOWORD((DWORD)lpici->lpVerb))
301        {
302            pThis->m_bDragMenu = TRUE;
303        }
304
305        try
306        {
307            CConfirmDialog cd(&parent);
308
309            cd.m_bSingleFile    = FALSE;
310            cd.m_strData        = "?";
311            cd.m_bUseFiles      = pThis->m_bUseFiles;
312            cd.m_bMove          = pThis->m_bDragMenu;
313            cd.m_strTarget      = pThis->m_szDropTarget;
314
315            CString strTemp;
316
317            if (pThis->m_bUseFiles)
318            {
319                CStringList strlSourceFolders;
320
321                // get source folders if moving
322                if (pThis->m_bDragMenu)
323                {
324                    CString strSourceFolder;
325                    int iSize = pThis->m_saData.GetSize(), i;
326
327                    for (i = 0; i < iSize; i++)
328                    {
329                        strSourceFolder = pThis->m_saData[i];
330                        strSourceFolder = strSourceFolder.Left(strSourceFolder.ReverseFind('\\') + 1);
331
332                        if (strlSourceFolders.Find(strSourceFolder) == NULL)
333                            strlSourceFolders.AddTail(strSourceFolder);
334                    }
335
336                    iSize = pThis->m_saFolders.GetSize();
337
338                    for (i = 0; i < iSize; i++)
339                    {
340                        strSourceFolder = pThis->m_saFolders[i];
341                        if (strSourceFolder[strSourceFolder.GetLength() - 1] == '\\')
342                            strSourceFolder.Left(strSourceFolder.GetLength() - 1);
343
344                        strSourceFolder = strSourceFolder.Left(strSourceFolder.ReverseFind('\\') + 1);
345
346                        if (strlSourceFolders.Find(strSourceFolder) == NULL)
347                            strlSourceFolders.AddTail(strSourceFolder);
348                    }
349
350                    ASSERT(!strlSourceFolders.IsEmpty());
351                }
352
353                // parse files from the folders
354                if (pThis->m_dwDirectories > 0)
355                {
356                    CStringArray saSubfolders;
357                    int iSize = pThis->m_saFolders.GetSize(), i;
358
359                    // parseDirectory will recount all directories for us
360                    pThis->m_dwDirectories = 0;
361
362                    for (i = 0; i < iSize; i++)
363                    {
364                        parseDirectory((LPCTSTR)pThis->m_saFolders[i],
365                                       pThis->m_saData,
366                                       saSubfolders,
367                                       TRUE,
368                                       &pThis->m_dwItems,
369                                       &pThis->m_dwDirectories);
370                    }
371
372                    // add found subfolders to the list for removal
373                    if (saSubfolders.GetSize() > 0)
374                        pThis->m_saFolders.InsertAt(0, &saSubfolders);
375                }
376
377                // done parsing, continue if there is something to erase
378
379                if (pThis->m_dwItems > 0 || pThis->m_dwDirectories > 0)
380                {
381                    // select which confirmation message to show
382
383                    if (pThis->m_dwDirectories > 0)
384                    {
385                        // at least one folder and zero or more files
386                        if (!pThis->m_bDragMenu)
387                            strTemp.LoadString(IDS_CONFIRM_FILES_AND_FOLDERS);
388                        else
389                            strTemp.LoadString(IDS_CONFIRM_MOVE_FILES_AND_FOLDERS);
390
391                        cd.m_strData.Format(strTemp, pThis->m_dwItems, pThis->m_dwDirectories);
392                    }
393                    else if (pThis->m_dwItems == 1)
394                    {
395                        // only one file
396                        cd.m_strData = pThis->m_saData[0];
397                        cd.m_bSingleFile = TRUE;
398                    }
399                    else if (pThis->m_dwItems > 1)
400                    {
401                        // more than one file and no folders
402                        if (!pThis->m_bDragMenu)
403                            strTemp.LoadString(IDS_CONFIRM_FILES);
404                        else
405                            strTemp.LoadString(IDS_CONFIRM_MOVE_FILES);
406
407                        cd.m_strData.Format(strTemp, pThis->m_dwItems);
408                    }
409
410                    // ask for confirmation
411                    if (cd.m_bMove)
412                    {
413                        if ( !strlen(pThis->m_szDropTarget) 
414                            && !GetFolder(lpici->hwnd, pThis->m_szDropTarget))
415                        {
416                            parent.Detach();
417                            return NOERROR;
418                        }
419                        cd.m_strTarget = pThis->m_szDropTarget;
420
421                    }
422
423                    if (cd.DoModal() == IDOK)
424                    {
425                        if (pThis->m_bDragMenu)
426                        {
427                            // if there is data to copy
428                            CStringArray saFolders;
429                            if (pThis->m_saFolders.GetSize() > 0)
430                                saFolders.Copy(pThis->m_saFolders);
431                           
432                           
433                               
434                           
435                            if (!pThis->MoveFileList(&parent,                 // parent window
436                                                     pThis->m_saData,         // source files
437                                                     saFolders,               // source folders
438                                                     strlSourceFolders,       // source folders
439                                                     pThis->m_szDropTarget))  // destination folder
440                            {
441                                parent.Detach();
442                                return E_FAIL;
443                            }
444
445                            // the amount of items to erase
446                            pThis->m_dwItems = pThis->m_saData.GetSize();
447                        }
448
449                        if (pThis->m_dwItems > 0)
450                        {
451                            // if there are files to erase
452
453                            CEraserDlg dlgEraser(&parent);
454
455                            dlgEraser.m_bMove        = pThis->m_bDragMenu;
456                            dlgEraser.m_bShowResults = TRUE;
457                            dlgEraser.m_bUseFiles    = pThis->m_bUseFiles;
458                            dlgEraser.m_saData.Copy(pThis->m_saData);
459
460                            dlgEraser.DoModal();
461                        }
462
463                        if (pThis->m_dwDirectories > 0)
464                        {
465                            // if there are (empty) directories to remove
466
467                            int iSize = pThis->m_saFolders.GetSize(), i;
468                            for (i = 0; i < iSize; i++)
469                            {
470                                if (eraserOK(eraserRemoveFolder((LPVOID)(LPCTSTR)pThis->m_saFolders[i],
471                                        (E_UINT16)pThis->m_saFolders[i].GetLength(), ERASER_REMOVE_FOLDERONLY)))
472                                {
473                                    SHChangeNotify(SHCNE_RMDIR, SHCNF_PATH, (LPCTSTR)pThis->m_saFolders[i], NULL);
474                                }
475                            }
476                        }
477                    }
478                }
479            }
480            else if (!pThis->m_bDragMenu)
481            {
482                // drive(s)
483
484                if (pThis->m_dwItems > 1)
485                    cd.m_strData.LoadString(IDS_CONFIRM_MULTI_DRIVE);
486                else if (pThis->m_dwItems == 1)
487                {
488                    strTemp.LoadString(IDS_CONFIRM_DRIVE);
489                    cd.m_strData.Format((LPCTSTR)strTemp, pThis->m_saData[0]);
490                }
491
492                if (cd.DoModal() == IDOK)
493                {
494                    CEraserDlg dlgEraser(&parent);
495
496                    dlgEraser.m_saData.Copy(pThis->m_saData);
497                    dlgEraser.m_bShowResults = TRUE;
498                    dlgEraser.m_bUseFiles = pThis->m_bUseFiles;
499
500                    dlgEraser.DoModal();
501                }
502            }
503        }
504        catch (CException *e)
505        {
506            ASSERT(FALSE);
507
508            e->ReportError(MB_ICONERROR);
509            e->Delete();
510        }
511        catch (...)
512        {
513            ASSERT(FALSE);
514        }
515
516        parent.Detach();
517
518        return NOERROR;
519    }
520
521    return E_INVALIDARG;
522}
523
524void 
525CErasextMenu::getstr_handle_erase(UINT /*nType*/, CString& cmdstr)
526{
527    if (m_bUseFiles)
528    {
529        if (m_dwDirectories > 0)
530            cmdstr.LoadString(IDS_COMMAND_STRING_DIRECTORIES);
531        else
532            cmdstr.LoadString(IDS_COMMAND_STRING_FILE);
533    }
534    else
535    {
536        cmdstr.LoadString(IDS_COMMAND_STRING_DRIVE);
537    }
538
539}
540
541void 
542CErasextMenu::getstr_handle_move(UINT /*nType*/, CString& cmdstr)
543{
544   
545    cmdstr = "Move";
546}
547
548STDMETHODIMP CErasextMenu::XMenuExt::GetCommandString(UINT_PTR  idCmd, UINT nType, UINT* /*pnReserved*/, LPSTR lpszName, UINT nMax)
549{
550    METHOD_PROLOGUE(CErasextMenu, MenuExt);
551    TRACE("CErasextMenu::XMenuExt::GetCommandString\n");
552
553    CString cmdstr;
554    ZeroMemory(lpszName, nMax);
555    try
556    {
557        if (0 == idCmd )
558            pThis->getstr_handle_erase(nType, cmdstr);
559        else
560            if (1 == idCmd)
561                pThis->getstr_handle_move(nType, cmdstr);
562           
563           
564    }
565    catch (CException *e)
566    {
567        ASSERT(FALSE);
568
569        e->ReportError(MB_ICONERROR);
570        e->Delete();
571
572        return E_OUTOFMEMORY;
573    }
574    catch (...)
575    {
576        ASSERT(FALSE);
577        return E_FAIL;
578    }
579
580    if (!pThis->m_bNT)
581        lstrcpyn(lpszName, (LPCTSTR) cmdstr, nMax);
582    else
583    {
584        MultiByteToWideChar(CP_ACP, 0, (LPCSTR)cmdstr, -1, (LPWSTR)lpszName,
585            nMax / sizeof(WCHAR));
586    }
587    return NOERROR;
588}
589
590// IUnknown for IShellExtInit
591STDMETHODIMP CErasextMenu::XShellInit::QueryInterface(REFIID riid, void** ppv)
592{
593    METHOD_PROLOGUE(CErasextMenu, ShellInit);
594    TRACE("CErasextMenu::XShellInit::QueryInterface\n");
595    return pThis->ExternalQueryInterface(&riid, ppv);
596}
597
598STDMETHODIMP_(ULONG) CErasextMenu::XShellInit::AddRef(void)
599{
600    METHOD_PROLOGUE(CErasextMenu, ShellInit);
601    TRACE("CErasextMenu::XShellInit::AddRef\n");
602    return pThis->ExternalAddRef();
603}
604
605STDMETHODIMP_(ULONG) CErasextMenu::XShellInit::Release(void)
606{
607    METHOD_PROLOGUE(CErasextMenu, ShellInit);
608    TRACE("CErasextMenu::XShellInit::Release\n");
609    return pThis->ExternalRelease();
610}
611
612STDMETHODIMP CErasextMenu::XShellInit::Initialize(LPCITEMIDLIST pidlFolder, LPDATAOBJECT lpdobj, HKEY /*hkeyProgID*/)
613{
614    METHOD_PROLOGUE(CErasextMenu, ShellInit);
615    TRACE("CErasextMenu::XShellInit::Initialize\n");
616
617    HRESULT hres = E_FAIL;
618    STGMEDIUM medium;
619    FORMATETC fmte = {CF_HDROP,
620                      NULL,
621                      DVASPECT_CONTENT,
622                      -1,
623                      TYMED_HGLOBAL};
624
625    // duplicate the object pointer
626    if (lpdobj == NULL)
627    {
628        TRACE("CErasextMenu::XShellInit::Initialize() no data object\n");
629        return E_FAIL;
630    }
631
632    // Use the given IDataObject to get a list of filenames (CF_HDROP)
633    hres = lpdobj->GetData(&fmte, &medium);
634
635    if (FAILED(hres))
636    {
637        TRACE("CErasextMenu::XShellInit::Initialize() can't get data\n");
638        return E_FAIL;
639    }
640
641    // clear members
642    ZeroMemory(pThis->m_szDropTarget, MAX_PATH + 2);
643    pThis->m_saData.RemoveAll();
644    pThis->m_saFolders.RemoveAll();
645    pThis->m_dwItems = 0;
646    pThis->m_dwDirectories = 0;
647
648    if (pidlFolder != NULL &&
649        SHGetPathFromIDList(pidlFolder, pThis->m_szDropTarget))
650    {
651        TRACE1("Drop Target: %s\n", pThis->m_szDropTarget);
652        pThis->m_bDragMenu = TRUE;
653    }
654    else
655    {
656        pThis->m_bDragMenu = FALSE;
657        pThis->m_szDropTarget[0] = '\0';
658    }
659
660
661    BOOL bDrives = FALSE;
662    BOOL bFiles = FALSE;
663
664    UINT uAmount;
665    UINT uCount;
666    DWORD dwAttr;
667
668    TCHAR szFileName[MAX_PATH + 1];
669    ZeroMemory(szFileName, MAX_PATH + 1);
670
671    // Get the number of items selected.
672    uAmount = DragQueryFile(static_cast<HDROP>(medium.hGlobal),
673              static_cast<UINT>(-1), NULL, 0);
674
675    for (uCount = 0; uCount < uAmount; uCount++)
676    {
677        szFileName[0] = '\0';
678
679        DragQueryFile(static_cast<HDROP>(medium.hGlobal), uCount, szFileName, MAX_PATH);
680
681        if (!bFiles && lstrlen(szFileName) <= _MAX_DRIVE)
682        {
683            // drive
684            dwAttr = GetDriveType((LPCTSTR) szFileName);
685
686            if (dwAttr != DRIVE_UNKNOWN &&
687                dwAttr != DRIVE_NO_ROOT_DIR &&
688                dwAttr != DRIVE_CDROM &&
689                dwAttr != DRIVE_REMOTE)
690            {
691                pThis->m_saData.Add(szFileName);
692                bDrives = TRUE;
693
694                pThis->m_dwItems++;
695            }
696        }
697        else if (!bDrives)
698        {
699            dwAttr = GetFileAttributes(szFileName);
700
701            if (dwAttr != (DWORD)-1)
702            {
703                if (dwAttr & FILE_ATTRIBUTE_DIRECTORY)
704                {
705                    // folder - read files later
706                    pThis->m_saFolders.Add(szFileName);
707                    bFiles = TRUE;
708
709                    pThis->m_dwDirectories++;
710                }
711                else
712                {
713                    // file
714                    pThis->m_saData.Add(szFileName);
715                    bFiles = TRUE;
716
717                    pThis->m_dwItems++;
718                }
719            }
720        }
721    }
722
723    // Release the data.
724    ReleaseStgMedium(&medium);
725
726    if (bFiles)
727        pThis->m_bUseFiles = TRUE;
728    else if (bDrives)
729        pThis->m_bUseFiles = FALSE;
730    else
731        return E_FAIL;
732
733    return S_OK;
734}
735
736
737static inline void
738GetSourceFolderFromList(CString& strFolder, CString strFile, CStringList& strlList)
739{
740    POSITION pos = NULL;
741    int iPosition = -1;
742
743    if (strFile.IsEmpty())
744        return;
745
746    if (strFile[strFile.GetLength() - 1] == '\\')
747        strFile = strFile.Left(strFile.GetLength() - 1);
748
749    iPosition = strFile.ReverseFind('\\');
750
751    while (iPosition != -1)
752    {
753        strFile = strFile.Left(iPosition + 1);
754        pos = strlList.Find(strFile);
755
756        if (pos != NULL)
757        {
758            strFolder = strlList.GetAt(pos);
759            break;
760        }
761
762        strFile = strFile.Left(strFile.GetLength() - 1);
763        iPosition = strFile.ReverseFind('\\');
764    }
765}
766
767BOOL CErasextMenu::MoveFileList(CWnd *pParent, CStringArray& saList, CStringArray& saFolders,
768                                CStringList& strlSource, LPCTSTR szDestination)
769{
770    CStringArray saErase;
771    CString strFile;
772    CString strDestination(szDestination);
773    CString strTemp;
774    BOOL    bFailed = FALSE;
775    BOOL    bNoToAll = FALSE, bYesToAll = FALSE;
776    int     iSize, i;
777
778    if (strDestination.IsEmpty() || strlSource.IsEmpty())
779        return FALSE;
780
781    // folders
782    if (strDestination[strDestination.GetLength() - 1] != '\\')
783        strDestination += "\\";
784
785    // must reverse the order of folders on the list and
786    // convert pathnames to destination folder
787
788    iSize = saFolders.GetSize();
789    for (i = 0; i < iSize; i++)
790    {
791        GetSourceFolderFromList(strTemp, saFolders[i], strlSource);
792
793        // source and destination are same
794        if (strTemp.CompareNoCase(strDestination) == 0)
795        {
796            AfxMessageBox(IDS_ERROR_MOVE_SAMEFOLDER, MB_ICONERROR);
797            return FALSE;
798        }
799
800        strTemp = saFolders[i].Right(saFolders[i].GetLength() - strTemp.GetLength());
801        strTemp = strDestination + strTemp;
802        saErase.InsertAt(0, strTemp);
803    }
804
805    saFolders.RemoveAll();
806    if (saErase.GetSize() > 0)
807    {
808        saFolders.Copy(saErase);
809        saErase.RemoveAll();
810    }
811
812    // create destination folders
813
814    iSize = saFolders.GetSize();
815    for (i = 0; i < iSize; i++)
816    {
817        // don't care about the results; if the function fails,
818        // the folder either exists or then we'll catch the error
819        // when trying to copy files to this directory
820
821        CreateDirectory((LPCTSTR)saFolders[i], NULL);
822    }
823
824    // copy files
825
826    iSize = saList.GetSize();
827    for (i = 0; i < iSize; i++)
828    {
829        GetSourceFolderFromList(strTemp, saList[i], strlSource);
830        strTemp = saList[i].Right(saList[i].GetLength() - strTemp.GetLength());
831        strTemp = strDestination + strTemp;
832
833        if (!CopyFile((LPCTSTR)saList[i], (LPCTSTR)strTemp, TRUE))
834        {
835            if (GetLastError() == ERROR_FILE_EXISTS)
836            {
837                if (bNoToAll)
838                {
839                    // never overwrite the destination
840                    continue;
841                }
842                else
843                {
844                    CConfirmReplaceDlg crd(pParent);
845
846                    crd.SetExisting((LPCTSTR)strTemp);
847                    crd.SetSource((LPCTSTR)saList[i]);
848
849                    if (bYesToAll || crd.DoModal() == IDOK)
850                    {
851                        bFailed = (CopyFile((LPCTSTR)saList[i], (LPCTSTR)strTemp, FALSE) == FALSE);
852
853                        if (!bYesToAll)
854                            bYesToAll = crd.ApplyToAll();
855                    }
856                    else
857                    {
858                        if (!bYesToAll && !bNoToAll)
859                            bNoToAll = crd.ApplyToAll();
860
861                        // do not erase the source
862                        continue;
863                    }
864                }
865            }
866            else
867            {
868                bFailed = TRUE;
869            }
870        }
871
872        if (bFailed)
873        {
874            DisplayError(GetLastError());
875            return FALSE;
876        }
877
878        // if file was copied, set the source to be
879        // erased
880
881        saErase.Add(saList[i]);
882    }
883
884    // set the file list
885    saList.RemoveAll();
886    if (saErase.GetSize() > 0)
887        saList.Copy(saErase);
888
889    return TRUE;
890}
Note: See TracBrowser for help on using the repository browser.