source: trunk/Erasext/ErasextMenu.cpp @ 32

Revision 32, 25.4 KB checked in by lowjoel, 7 years ago (diff)

-Commit my fix for files which have filenames which are too long for the standard Windows filename handling to work
-Commit my fix to ignore files which are actually junctions or symbolic links
-UNC files are now ignored during free space wipes
-Silenced a few unused formal parameter warnings

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