source: trunk/EraserDoc.cpp @ 3

Revision 3, 36.8 KB checked in by lowjoel, 7 years ago (diff)

Added the source files from root (SVN migration commit 1)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1// EraserDoc.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 "Eraser.h"
24#include "Item.h"
25#include "EraserDll\EraserDll.h"
26#include "shared\key.h"
27#include "shared\utils.h"
28#include "shared\FileDialogEx.h"
29#include "PreferencesSheet.h"
30#include "TimeOutMessageBox.h"
31#include "EraserDoc.h"
32#include "MainFrm.h"
33#include "version.h"
34//#include <afxpriv.h>
35
36#include <direct.h>
37
38#ifdef _DEBUG
39#define new DEBUG_NEW
40#undef THIS_FILE
41static char THIS_FILE[] = __FILE__;
42#endif
43
44/////////////////////////////////////////////////////////////////////////////
45// CEraserDoc
46
47
48
49CString findRecycledBinGUID()
50{
51    const LPCTSTR RBIN_NSPACE = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Desktop\\NameSpace";
52    CKey kReg;
53    BOOL bRes;
54    HKEY hReg;
55    TCHAR szSubKey[MAX_KEY_LENGTH];
56    DWORD dwSubKeyLen = MAX_KEY_LENGTH;
57    DWORD dwIndex=0;
58    CString strValue=_T(""),strDef=_T(""),strFind=_T("");
59   
60    bRes = kReg.Open(HKEY_LOCAL_MACHINE,RBIN_NSPACE,FALSE);
61    hReg = kReg.GetHandle();
62    while (ERROR_SUCCESS == RegEnumKeyEx(hReg,dwIndex,szSubKey,&dwSubKeyLen,NULL,NULL,NULL,NULL))
63    {       
64        CKey kTmpReg;
65        CString strTmp=_T("");
66        strTmp.Format("%s\\%s", RBIN_NSPACE, szSubKey);
67        if (kTmpReg.Open(HKEY_LOCAL_MACHINE,strTmp,FALSE)) {
68            kTmpReg.GetValue(strValue,strDef,"");
69            if (strValue == "Recycle Bin") {
70                strFind = szSubKey; 
71            }
72            dwIndex++;
73            dwSubKeyLen = MAX_KEY_LENGTH;           
74        }
75        kTmpReg.Close();
76    }
77    kReg.Close();
78    return strFind;
79}
80
81
82IMPLEMENT_DYNCREATE(CEraserDoc, CDocument)
83
84BEGIN_MESSAGE_MAP(CEraserDoc, CDocument)
85    //{{AFX_MSG_MAP(CEraserDoc)
86    ON_UPDATE_COMMAND_UI(ID_FILE_EXPORT, OnUpdateFileExport)
87    ON_COMMAND(ID_FILE_EXPORT, OnFileExport)
88    ON_COMMAND(ID_FILE_IMPORT, OnFileImport)
89    ON_COMMAND(ID_TRAY_ENABLE, OnTrayEnable)
90    ON_UPDATE_COMMAND_UI(ID_TRAY_SHOW_WINDOW, OnUpdateTrayShowWindow)
91    ON_UPDATE_COMMAND_UI(ID_TRAY_ENABLE, OnUpdateTrayEnable)
92    ON_COMMAND(ID_TRAY_SHOW_WINDOW, OnTrayShowWindow)
93    ON_COMMAND(ID_EDIT_PREFERENCES_GENERAL, OnEditPreferencesGeneral)
94    ON_COMMAND(ID_EDIT_PREFERENCES_ERASER, OnEditPreferencesEraser)
95    ON_COMMAND(ID_FILE_VIEW_LOG, OnFileViewLog)
96    //}}AFX_MSG_MAP
97END_MESSAGE_MAP()
98
99/////////////////////////////////////////////////////////////////////////////
100// CEraserDoc construction/destruction
101
102CEraserDoc::CEraserDoc() :
103m_bResolveLock(TRUE),
104m_bResolveAskUser(TRUE),
105m_bSchedulerEnabled(TRUE),
106m_wProcessCount(0),
107m_bResultsForFiles(TRUE),
108m_bResultsForUnusedSpace(TRUE),
109m_bResultsOnlyWhenFailed(FALSE),
110m_bLog(TRUE),
111m_bLogOnlyErrors(FALSE),
112m_bStartup(TRUE),
113m_bQueueTasks(TRUE),
114m_bNoVisualErrors(FALSE),
115m_dwMaxLogSize(10),
116m_bClearSwap(FALSE),
117m_bShellextResults(FALSE),
118m_bErasextEnabled(TRUE),
119m_bEnableSlowPoll(FALSE),
120m_dwStartView((DWORD)-1),
121m_bIconAnimation(FALSE),
122m_bSmallIconView(FALSE),
123m_dwOutbarWidth(0),
124m_bNoTrayIcon(FALSE),
125m_bHideOnMinimize(FALSE),
126m_bViewInfoBar(FALSE),
127m_smallImageList (NULL)
128{
129    TRACE("CEraserDoc::CEraserDoc\n");
130
131    m_bAutoDelete = FALSE;
132    ZeroMemory(&m_rWindowRect, sizeof(RECT));
133
134    // find executable location for logging
135    try
136    {
137
138       /* Removed GT 28/07/2007 for Vista
139        GetModuleFileName(AfxGetInstanceHandle(),
140                          m_strExePath.GetBuffer(MAX_PATH), MAX_PATH);
141        m_strExePath.ReleaseBuffer();
142        m_strExePath = m_strExePath.Left(m_strExePath.ReverseFind('\\') + 1);
143
144       */   
145       
146        LPTSTR p = m_strExePath.GetBuffer(MAX_PATH);
147        HRESULT hr = ::SHGetFolderPath(NULL,CSIDL_COMMON_DOCUMENTS | CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, p);
148        m_strExePath.ReleaseBuffer();
149        m_strExePath = m_strExePath.Left(m_strExePath.ReverseFind('\\') + 1)+szDefaultDir;
150
151        // read preferences
152        if (!ReadPreferences())
153        {
154            AfxTimeOutMessageBox(IDS_ERROR_PREFERENCES_READ, MB_ICONERROR);
155
156            if (m_bLog)
157                LogAction(IDS_ERROR_PREFERENCES_READ);
158        }
159
160        // create task bar tray icon
161        m_stIcon.Create(NULL, WM_TRAY_NOTIFY, "Starting...",
162                        AfxGetApp()->LoadIcon(IDI_ICON_TRAY),
163                        IDR_MENU_TRAY, !m_bNoTrayIcon);
164
165        // create timers
166        CalcNextAssignment();
167        UpdateToolTip();
168
169        if (m_bLog && !m_bLogOnlyErrors)
170        {
171            CString strStart;
172            AfxFormatString1(strStart, IDS_ACTION_START, VERSION_NUMBER_STRING);
173            LogAction(strStart);
174        }
175
176        VERIFY(m_ilHeader.Create(IDB_HEADER, 10, 1, RGB(255, 255, 255)));
177
178        //image list setup
179        HIMAGELIST hSystemSmallImageList;
180        SHFILEINFO ssfi;
181
182        //get a handle to the system small icon list
183        hSystemSmallImageList =
184            reinterpret_cast<HIMAGELIST>(SHGetFileInfo((LPCTSTR)_T("C:\\"),
185                                      0, &ssfi, sizeof(SHFILEINFO),
186                                      SHGFI_SYSICONINDEX | SHGFI_SMALLICON));
187
188   
189        //m_smallImageList.Attach(hSystemSmallImageList);
190        m_smallImageList = CImageList::FromHandle(hSystemSmallImageList);
191    }
192    catch (CException *e)
193    {
194        ASSERT(FALSE);
195        REPORT_ERROR(e);
196        e->Delete();
197    }
198}
199
200CEraserDoc::~CEraserDoc()
201{
202    TRACE("CEraserDoc::~CEraserDoc\n");
203
204    try
205    {
206        m_smallImageList->Detach();
207        m_stIcon.RemoveIcon();
208
209        if (!SavePreferences() && m_bLog)
210            LogAction(IDS_ERROR_PREFERENCES_SAVE);
211
212        if (m_bLog && !m_bLogOnlyErrors)
213            LogAction(IDS_ACTION_QUIT);
214
215    //  delete m_smallImageList;
216    }
217    catch (...)
218    {
219        ASSERT(FALSE);
220    }
221}
222
223BOOL CEraserDoc::OnNewDocument()
224{
225    TRACE("CEraserDoc::OnNewDocument\n");
226
227    try
228    {
229        if (!CDocument::OnNewDocument())
230            return FALSE;
231
232        CString strDefault = m_strExePath + szDefaultFile;
233        Import((LPCTSTR)strDefault, FALSE);
234
235        return TRUE;
236    }
237    catch (CException *e)
238    {
239        ASSERT(FALSE);
240        REPORT_ERROR(e);
241        e->Delete();
242    }
243
244    return FALSE;
245}
246
247
248
249/////////////////////////////////////////////////////////////////////////////
250// CEraserDoc serialization
251
252void CEraserDoc::Serialize(CArchive& ar)
253{
254    TRACE("CEraserDoc::Serialize\n");
255
256    CItem           *piItem     = 0;
257    CScheduleItem   *psiItem    = 0;
258
259    if (ar.IsStoring())
260    {
261        int iSize;
262        WORD wID = 0;
263
264        // remove invalid items
265        CleanList(m_paTasks, sizeof(CItem));
266        CleanList(m_paScheduledTasks, sizeof(CScheduleItem));
267
268        ar << static_cast<DWORD>(m_paTasks.GetSize() + m_paScheduledTasks.GetSize());
269
270        iSize = m_paTasks.GetSize();
271
272        while (iSize--)
273        {
274            piItem = static_cast<CItem*>(m_paTasks[iSize]);
275
276            ar << static_cast<WORD>(ITEMVERSION);
277            ar << static_cast<WORD>(ITEM_ID);
278            piItem->Serialize(ar);
279        }
280
281        iSize = m_paScheduledTasks.GetSize();
282
283        while (iSize--)
284        {
285            psiItem = static_cast<CScheduleItem*>(m_paScheduledTasks[iSize]);
286
287            ar << static_cast<WORD>(ITEMVERSION);
288            ar << static_cast<WORD>(SCHEDULE_ID);
289            psiItem->Serialize(ar);
290        }
291    }
292    else
293    {
294        DWORD dwCount = 0;
295        WORD  wID     = 0;
296        WORD  wItemID = 0;
297
298        ar >> dwCount;
299
300        for (DWORD dwItem = 0; dwItem < dwCount; dwItem++)
301        {
302            ar >> wID;
303
304            piItem = 0;
305            psiItem = 0;
306
307            if (wID >= ITEMVERSION_30 && wID <= ITEMVERSION)
308            {
309                ar >> wItemID;
310
311                try
312                {
313                    if (wItemID == ITEM_ID)
314                    {
315                        piItem = new CItem();
316
317                        switch (wID)
318                        {
319                        case ITEMVERSION:
320                            piItem->Serialize(ar);
321                            break;
322                        case ITEMVERSION_41:
323                            psiItem->Serialize(ar);
324                            break;
325#ifdef SCHEDULER_IMPORT_COMPATIBLE
326                        case ITEMVERSION_40:
327                            piItem->Serialize40(ar);
328                            break;
329                        case ITEMVERSION_30:
330                            piItem->Serialize30(ar);
331                            break;
332#endif
333                        default:
334                            AfxThrowArchiveException(CArchiveException::badIndex);
335                        }
336
337                        AddTask(piItem);
338                    }
339                    else if (wItemID == SCHEDULE_ID)
340                    {
341                        psiItem = new CScheduleItem();
342
343                        switch (wID)
344                        {
345                        case ITEMVERSION:
346                            psiItem->Serialize(ar);
347                            break;
348                        case ITEMVERSION_41:
349                            psiItem->Serialize41(ar);
350                            break;
351#ifdef SCHEDULER_IMPORT_COMPATIBLE
352                        case ITEMVERSION_40:
353                            psiItem->Serialize40(ar);
354                            break;
355                        case ITEMVERSION_30:
356                            psiItem->Serialize30(ar);
357                            break;
358#endif
359                        default:
360                            AfxThrowArchiveException(CArchiveException::badIndex);
361                        }
362
363                        AddScheduledTask(psiItem);
364                    }
365                }
366                catch (...)
367                {
368                    if (piItem)
369                    {
370                        delete piItem;
371                        piItem = 0;
372                    }
373
374                    if (psiItem)
375                    {
376                        delete psiItem;
377                        psiItem = 0;
378                    }
379
380                    ASSERT(FALSE);
381                    throw;
382                }
383            }
384#ifdef SCHEDULER_IMPORT_COMPATIBLE
385            else if (wID == ITEMVERSION_21)
386            {
387                psiItem = new CScheduleItem();
388
389                try
390                {
391                    psiItem->Serialize21(ar);
392                    AddScheduledTask(psiItem);
393                }
394                catch (...)
395                {
396                    delete psiItem;
397                    psiItem = 0;
398
399                    ASSERT(FALSE);
400                    throw;
401                }
402            }
403#endif
404            else
405            {
406                // unsupported format
407                AfxThrowArchiveException(CArchiveException::badIndex);
408            }
409        }
410    }
411}
412
413/////////////////////////////////////////////////////////////////////////////
414// CEraserDoc diagnostics
415
416#ifdef _DEBUG
417void CEraserDoc::AssertValid() const
418{
419    CDocument::AssertValid();
420}
421
422void CEraserDoc::Dump(CDumpContext& dc) const
423{
424    CDocument::Dump(dc);
425}
426#endif //_DEBUG
427
428/////////////////////////////////////////////////////////////////////////////
429// CEraserDoc commands
430
431BOOL CEraserDoc::OnOpenDocument(LPCTSTR lpszPathName)
432{
433    TRACE("CEraserDoc::OnOpenDocument\n");
434
435    try
436    {
437        if (!CDocument::OnNewDocument())
438            return FALSE;
439
440        Import(lpszPathName);
441
442        return TRUE;
443    }
444    catch (CException *e)
445    {
446        ASSERT(FALSE);
447        REPORT_ERROR(e);
448        e->Delete();
449    }
450
451    return FALSE;
452}
453
454void CEraserDoc::DeleteContents()
455{
456    TRACE("CEraserDoc::DeleteContents\n");
457
458    FreeTasks();
459    CDocument::DeleteContents();
460}
461
462void CEraserDoc::FreeTasks()
463{
464    TRACE("CEraserDoc::FreeTasks\n");
465
466    try
467    {
468        CItem         *piItem  = 0;
469        CScheduleItem *psiItem = 0;
470        int           iSize    = 0;
471
472        // tasks of type CItem
473        iSize = m_paTasks.GetSize();
474
475        while (iSize--)
476        {
477            piItem = static_cast<CItem*>(m_paTasks[iSize]);
478            if (AfxIsValidAddress(piItem, sizeof(CItem)))
479                delete piItem;
480
481            piItem = 0;
482        }
483
484        m_paTasks.RemoveAll();
485
486        // scheduled tasks of type CScheduleItem
487        iSize = m_paScheduledTasks.GetSize();
488
489        while (iSize--)
490        {
491            psiItem = static_cast<CScheduleItem*>(m_paScheduledTasks[iSize]);
492
493            if (AfxIsValidAddress(psiItem, sizeof(CScheduleItem)))
494                delete psiItem;
495
496            psiItem = 0;
497        }
498
499        m_paScheduledTasks.RemoveAll();
500    }
501    catch (CException *e)
502    {
503        ASSERT(FALSE);
504        REPORT_ERROR(e);
505        e->Delete();
506    }
507}
508
509BOOL CEraserDoc::AddTask(CItem *piItem)
510{
511    TRACE("CEraserDoc::AddTask\n");
512
513    if (AfxIsValidAddress(piItem, sizeof(CItem)))
514    {
515        try
516        {
517            CString strNew;
518            piItem->GetData(strNew);
519
520            CItem   *piCurrent  = 0;
521            int     iSize       = m_paTasks.GetSize();
522
523            // duplicates are not accepted for on-demand eraser
524
525            while (iSize--)
526            {
527                piCurrent = static_cast<CItem*>(m_paTasks[iSize]);
528                if (AfxIsValidAddress(piCurrent, sizeof(CItem)))
529                {
530                    if (!strNew.CompareNoCase((LPCTSTR)(piCurrent->GetData())))
531                        return FALSE;
532                }
533            }
534
535            m_paTasks.Add(static_cast<void*>(piItem));
536            return TRUE;
537        }
538        catch (CException *e)
539        {
540            ASSERT(FALSE);
541            REPORT_ERROR(e);
542            e->Delete();
543        }
544    }
545
546    return FALSE;
547}
548
549BOOL CEraserDoc::AddScheduledTask(CScheduleItem *psiItem)
550{
551    TRACE("CEraserDoc::AddScheduledTask\n");
552
553    if (AfxIsValidAddress(psiItem, sizeof(CScheduleItem)))
554    {
555        try
556        {
557            m_paScheduledTasks.Add(static_cast<void*>(psiItem));
558            return TRUE;
559        }
560        catch (CException *e)
561        {
562            ASSERT(FALSE);
563            REPORT_ERROR(e);
564            e->Delete();
565        }
566    }
567
568    return FALSE;
569}
570
571
572void CEraserDoc::OnUpdateFileExport(CCmdUI* pCmdUI)
573{
574    pCmdUI->Enable(m_paTasks.GetSize() > 0 || m_paScheduledTasks.GetSize() > 0);
575}
576
577void CEraserDoc::OnFileExport()
578{
579    TRACE("CEraserDoc::OnFileExport\n");
580    CFileDialogEx fd(FALSE,
581                     szFileExtension,
582                     szFileWCard,
583                     OFN_EXPLORER | OFN_PATHMUSTEXIST |
584                     OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
585                     szFileFilter,
586                     AfxGetMainWnd());
587
588    fd.m_ofn.lpstrTitle = szExportTitle;
589
590    if (fd.DoModal() == IDOK)
591    {
592        CString strFile = fd.GetPathName();
593        Export((LPCTSTR)strFile);
594    }
595}
596
597void CEraserDoc::OnFileImport()
598{
599    TRACE("CEraserDoc::OnFileImport\n");
600// Was CfileDialogEx now with MFC7 we can change back to MFC Class
601    CFileDialog fd(TRUE,
602                     szFileExtension,
603                     szFileWCard,
604                     OFN_EXPLORER | OFN_PATHMUSTEXIST |
605                     OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
606                     szFileFilter,
607                     AfxGetMainWnd());
608
609    fd.m_ofn.lpstrTitle = szImportTitle;
610
611    if (fd.DoModal() == IDOK)
612    {
613        CString strFile = fd.GetPathName();
614        Import((LPCTSTR)strFile);
615
616        UpdateAllViews(NULL, SCHEDULER_SET_TIMERS);
617    }
618}
619
620void CEraserDoc::OnUpdateTrayEnable(CCmdUI* pCmdUI)
621{
622    pCmdUI->SetCheck(m_bSchedulerEnabled);
623}
624
625void CEraserDoc::OnTrayEnable()
626{
627    TRACE("CEraserDoc::OnTrayEnable\n");
628
629    m_bSchedulerEnabled = !m_bSchedulerEnabled;
630
631    if (m_bLog && !m_bLogOnlyErrors)
632    {
633        if (m_bSchedulerEnabled)
634            LogAction(IDS_ACTION_ENABLED);
635        else
636            LogAction(IDS_ACTION_DISABLED);
637    }
638
639    UpdateToolTip();
640}
641
642void CEraserDoc::OnUpdateTrayShowWindow(CCmdUI* pCmdUI)
643{
644    try
645    {
646        CFrameWnd *pwndMain = static_cast<CFrameWnd*>(AfxGetMainWnd());
647        pCmdUI->Enable(!pwndMain->IsWindowVisible());
648    }
649    catch (...)
650    {
651        ASSERT(FALSE);
652        pCmdUI->Enable(FALSE);
653    }
654}
655
656void CEraserDoc::OnTrayShowWindow()
657{
658    TRACE("CEraserDoc::OnTrayShowWindow\n");
659
660    try
661    {
662        CMainFrame *pwndMain = static_cast<CMainFrame*>(AfxGetMainWnd());
663
664        if (!pwndMain->IsWindowVisible())
665        {
666            pwndMain->ShowWindow(SW_SHOW);
667
668            if (pwndMain->m_pwndChild->m_iActiveViewID == VIEW_SCHEDULER)
669            {
670                // if there are processes running, update the window
671                if (m_wProcessCount > 0)
672                    pwndMain->m_pwndChild->m_pSchedulerView->EraserWipeBegin();
673            }
674        }
675    }
676    catch (...)
677    {
678        ASSERT(FALSE);
679    }
680}
681
682BOOL CEraserDoc::LogAction(CString str)
683{
684    TRACE("CEraserDoc::LogAction(CString)\n");
685
686    BOOL bResult = FALSE;
687    CString strDate, strPath;
688
689    CStdioFile sf;
690
691    strPath = m_strExePath + szLogFile;
692
693    if (sf.Open(strPath, CFile::modeReadWrite | CFile::modeCreate | CFile::modeNoTruncate | CFile::typeText))
694    {
695        strDate = GetTimeTimeZoneBased().Format();
696        str = strDate + ": " + str + "\n";
697
698
699        try
700        {
701            DWORD dwMax = m_dwMaxLogSize * 1024;
702            ULONGLONG dwCurrent = sf.GetLength() + str.GetLength();
703
704            if (m_dwMaxLogSize > 0 && dwMax < dwCurrent)
705            {
706                // must remove lines in order to keep the log
707                // file under the maximum size
708
709                CString strTmp;
710                LONGLONG dwLen = dwMax - str.GetLength();
711
712                sf.Seek(-1*dwLen, CFile::end);
713                sf.ReadString(strTmp);
714
715                LPTSTR lpszTmp = strTmp.GetBufferSetLength(dwLen);
716                ZeroMemory(lpszTmp, dwLen);
717
718                sf.Read((LPVOID)lpszTmp, dwLen);
719
720                strTmp.ReleaseBuffer();
721                strTmp += str;
722
723                sf.SetLength(0);
724                sf.SeekToBegin();
725                sf.Write(strTmp, strTmp.GetLength());
726            }
727            else
728            {
729                // write to the end of the file
730                sf.SeekToEnd();
731                sf.WriteString(str);
732            }
733
734            bResult = TRUE;
735        }
736        catch (CException* e)
737        {
738            e->ReportError();           
739        }
740        catch (...)
741        {
742            ASSERT(FALSE);
743        }
744
745        sf.Close();
746    }
747
748    return bResult;
749}
750
751BOOL CEraserDoc::LogException(CException *e)
752{
753    TRACE("CEraserDoc::LogException\n");
754
755    try
756    {
757        TCHAR szCause[255];
758        e->GetErrorMessage(szCause, 255);
759
760        return LogAction(szCause);
761    }
762    catch (...)
763    {
764        ASSERT(FALSE);
765    }
766
767    return FALSE;
768}
769
770BOOL CEraserDoc::LogAction(UINT nResourceID)
771{
772    TRACE("CEraserDoc::LogAction(UINT)\n");
773
774    CString str;
775    BOOL bResult = FALSE;
776
777    try
778    {
779        if (str.LoadString(nResourceID))
780            bResult = LogAction(str);
781    }
782    catch (CException *e)
783    {
784        ASSERT(FALSE);
785
786        if (m_bLog)
787            LogException(e);
788
789        e->Delete();
790    }
791    catch (...)
792    {
793        ASSERT(FALSE);
794    }
795
796    return bResult;
797}
798
799void CEraserDoc::CalcNextAssignment()
800{
801    TRACE("CEraserDoc::CalcNextAssignment\n");
802
803    try
804    {
805        int iSize = m_paScheduledTasks.GetSize();
806
807        if (iSize > 0)
808        {
809            iSize--;
810
811            CScheduleItem   *psiItem    = static_cast<CScheduleItem*>(m_paScheduledTasks[iSize]);
812            COleDateTime    odtEarliest = psiItem->GetNextTime();
813
814            while (iSize--)
815            {
816                psiItem = static_cast<CScheduleItem*>(m_paScheduledTasks[iSize]);
817                if (AfxIsValidAddress(psiItem, sizeof(CScheduleItem)))
818                {
819                    if (psiItem->GetNextTime() < odtEarliest)
820                        odtEarliest = psiItem->GetNextTime();
821                }
822            }
823
824            m_strNextAssignment = odtEarliest.Format();
825        }
826        else
827            m_strNextAssignment.Empty();
828    }
829    catch (CException *e)
830    {
831        ASSERT(FALSE);
832
833        if (m_bLog)
834            LogException(e);
835
836        e->Delete();
837    }
838}
839
840void CEraserDoc::UpdateToolTip()
841{
842    TRACE("CEraserDoc::UpdateToolTip\n");
843
844    CString     strFormat;
845    CString     str;
846
847    try
848    {
849        if (m_wProcessCount == 0)
850        {
851            if (m_bSchedulerEnabled)
852            {
853                if (m_strNextAssignment.IsEmpty())
854                {
855                    strFormat.LoadString(IDS_TOOLTIP_WAITING);
856                    m_stIcon.SetTooltipText(strFormat);
857                }
858                else
859                {
860                    str.LoadString(IDS_TOOLTIP_NEXT);
861                    str += m_strNextAssignment;
862
863                    m_stIcon.SetTooltipText(str);
864                }
865
866                m_stIcon.SetIcon(IDI_ICON_TRAY);
867            }
868            else
869            {
870                strFormat.LoadString(IDS_TOOLTIP_DISABLED);
871                m_stIcon.SetTooltipText(strFormat);
872
873                m_stIcon.SetIcon(IDI_ICON_TRAY_DISABLED);
874            }
875        }
876        else
877        {
878            m_stIcon.SetIcon(IDI_ICON_TRAY_RUNNING);
879
880            strFormat.LoadString(IDS_TOOLTIP_PROCESSING);
881            str.Format(strFormat, m_wProcessCount);
882
883            if (str.CompareNoCase(m_stIcon.GetTooltipText()) != 0)
884                m_stIcon.SetTooltipText((LPCTSTR)str);
885        }
886    }
887    catch (CException *e)
888    {
889        ASSERT(FALSE);
890
891        if (m_bLog)
892            LogException(e);
893
894        e->Delete();
895    }
896}
897
898#define RESULT(result, statement) \
899    ((result) = ((statement) ? (result) : FALSE))
900
901__declspec(dllimport) bool no_registry;
902
903BOOL CEraserDoc::SavePreferences()
904{
905    TRACE("CEraserDoc::SavePreferences\n");
906
907    BOOL            bResult     = TRUE;
908    CKey            kReg_reg;
909    CIniKey         kReg_ini;
910    CKey           &kReg = no_registry ? kReg_ini : kReg_reg;
911    CString         strPath;
912    OSVERSIONINFO   ov;
913
914    strPath.Format("%s\\%s", ERASER_REGISTRY_BASE, szSettingsKey);
915
916    ZeroMemory(&ov, sizeof(OSVERSIONINFO));
917    ov.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
918
919    GetVersionEx(&ov);
920
921    // Scheduler Preferences
922    if (kReg.Open(HKEY_CURRENT_USER, strPath))
923    {
924        RESULT(bResult, kReg.SetValue(m_bSchedulerEnabled, szSchedulerEnabled));
925        RESULT(bResult, kReg.SetValue(m_bLog, szLog));
926        RESULT(bResult, kReg.SetValue(m_bLogOnlyErrors, szLogOnlyErrors));
927        RESULT(bResult, kReg.SetValue(m_bStartup, szStartup));
928        RESULT(bResult, kReg.SetValue(m_bQueueTasks, szQueueTasks));
929        RESULT(bResult, kReg.SetValue(m_bNoVisualErrors, szNoVisualErrors));
930        RESULT(bResult, kReg.SetValue(m_dwMaxLogSize, szMaxLogSize));
931
932        kReg.Close();
933    }
934    else
935        bResult = FALSE;
936
937    // Scheduler Startup
938    if (!no_registry) {
939        if (m_bStartup)
940        {
941            if (kReg.Open(HKEY_CURRENT_USER, szStartupPath))
942            {
943                TCHAR szApplicationFileName[MAX_PATH + 1];
944
945                if (GetModuleFileName(AfxGetInstanceHandle(), szApplicationFileName, MAX_PATH))
946                {
947                    CString strStartupCmdLine(szApplicationFileName);
948                    strStartupCmdLine += " ";
949                    strStartupCmdLine += NOWINDOW_PARAMETER;
950
951                    RESULT(bResult, kReg.SetValue((LPCTSTR)strStartupCmdLine, szRunOnStartup));
952                }
953                else
954                    bResult = FALSE;
955
956                kReg.Close();
957            }
958            else
959                bResult = FALSE;
960        }
961        else if (kReg.Open(HKEY_CURRENT_USER, szStartupPath, FALSE))
962        {
963            kReg.DeleteValue(szRunOnStartup);
964            kReg.Close();
965        }
966    }
967
968    // General Preferences
969
970    //cancel report on recycle bin clearance if m_bShellextResults is unchecked
971    const LPCTSTR REC_BIN_PKEY = "CLSID\\";
972    const LPCTSTR REC_BIN_SKEY = "Shell\\Eraserxt\\command";
973    const CString strWthReport = "\\Eraserl.exe -recycled -results ";
974    const CString strWoReport =  "\\Eraserl.exe -recycled ";
975
976    CString strDef = _T(""), strCmd, strOld = _T("");
977    CString strRecBinGUID = REC_BIN_PKEY + findRecycledBinGUID();
978    strRecBinGUID = strRecBinGUID + "\\" + REC_BIN_SKEY;
979   
980    if (!no_registry && kReg.Open(HKEY_CLASSES_ROOT,strRecBinGUID,FALSE))
981    {
982        char buf[_MAX_PATH];
983        _getcwd(buf,_MAX_PATH); //working directory
984        strCmd = buf;
985        if (m_bShellextResults == TRUE) strCmd = strCmd + strWthReport;
986        else strCmd = strCmd + strWoReport;
987        kReg.GetValue(strOld,strDef,"");
988        if (strOld != strCmd ) kReg.SetValue(strCmd,strDef);
989        kReg.Close();
990    }
991   
992   
993    if (kReg.Open(HKEY_CURRENT_USER, ERASER_REGISTRY_BASE))
994    {
995        if (m_dwStartView != (DWORD) -1)
996            RESULT(bResult, kReg.SetValue(m_dwStartView, szStartView));
997
998        RESULT(bResult, kReg.SetValue((LPVOID)&m_rWindowRect, szWindowRect, sizeof(RECT)));
999        RESULT(bResult, kReg.SetValue(m_bResultsForFiles, ERASER_REGISTRY_RESULTS_FILES));
1000        RESULT(bResult, kReg.SetValue(m_bResultsForUnusedSpace, ERASER_REGISTRY_RESULTS_UNUSEDSPACE));
1001        RESULT(bResult, kReg.SetValue(m_bResultsOnlyWhenFailed, ERASER_REGISTRY_RESULTS_WHENFAILED));
1002        RESULT(bResult, kReg.SetValue(m_bShellextResults, ERASEXT_REGISTRY_RESULTS));
1003        RESULT(bResult, kReg.SetValue(m_bErasextEnabled, ERASEXT_REGISTRY_ENABLED));
1004        RESULT(bResult, kReg.SetValue(m_bEnableSlowPoll, ERASER_RANDOM_SLOW_POLL));
1005        RESULT(bResult, kReg.SetValue(m_bIconAnimation, szIconAnimation));
1006        RESULT(bResult, kReg.SetValue(m_bSmallIconView, szSmallIconView));
1007        RESULT(bResult, kReg.SetValue(m_dwOutbarWidth, szOutBarWidth));
1008        RESULT(bResult, kReg.SetValue(m_bNoTrayIcon, szNoTrayIcon));
1009        RESULT(bResult, kReg.SetValue(m_bHideOnMinimize, szHideOnMinimize));
1010        RESULT(bResult, kReg.SetValue(m_bViewInfoBar, szViewInfoBar));
1011        RESULT(bResult, kReg.SetValue(m_bResolveLock, szResolveLock));
1012        RESULT(bResult, kReg.SetValue(m_bResolveAskUser, szResolveAskUser));
1013       
1014        kReg.Close();
1015
1016    }
1017    else
1018        bResult = FALSE;
1019
1020    // Page File Clearing only on NT (works only if Admin so no errors here)
1021    if (ov.dwPlatformId == VER_PLATFORM_WIN32_NT)
1022    {
1023        if (kReg_reg.Open(HKEY_LOCAL_MACHINE, szClearSwapPath))
1024        {
1025            // need to set the registry key even if m_bClearSwap == false,
1026            // otherwise Windows 2000 overrides the setting when applying
1027            // local security policy
1028
1029            kReg_reg.SetValue(m_bClearSwap, szClearSwapValue);
1030            kReg_reg.Close();
1031        }
1032    }
1033
1034    return bResult;
1035}
1036
1037BOOL CEraserDoc::ReadPreferences()
1038{
1039    TRACE("CEraserDoc::ReadPreferences\n");
1040
1041    BOOL            bResult     = TRUE;
1042    CKey            kReg_reg;
1043    CIniKey         kReg_ini;
1044    CKey           &kReg = no_registry ? kReg_ini : kReg_reg;
1045    CString         strPath;
1046    OSVERSIONINFO   ov;
1047
1048    strPath.Format("%s\\%s", ERASER_REGISTRY_BASE, szSettingsKey);
1049
1050    ZeroMemory(&ov, sizeof(OSVERSIONINFO));
1051    ov.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
1052
1053    GetVersionEx(&ov);
1054
1055    // Scheduler Preferences
1056    if (kReg.Open(HKEY_CURRENT_USER, strPath))
1057    {
1058        kReg.GetValue(m_bSchedulerEnabled, szSchedulerEnabled, TRUE);
1059        kReg.GetValue(m_bLog, szLog, TRUE);
1060        kReg.GetValue(m_bLogOnlyErrors, szLogOnlyErrors, FALSE);
1061        kReg.GetValue(m_bStartup, szStartup, TRUE);
1062        kReg.GetValue(m_bQueueTasks, szQueueTasks, TRUE);
1063        kReg.GetValue(m_bNoVisualErrors, szNoVisualErrors, FALSE);
1064        kReg.GetValue(m_dwMaxLogSize, szMaxLogSize, 10);
1065
1066        kReg.Close();
1067    }
1068    else
1069        bResult = FALSE;
1070
1071    // General Preferences
1072    if (kReg.Open(HKEY_CURRENT_USER, ERASER_REGISTRY_BASE))
1073    {
1074        if (m_dwStartView == (DWORD) -1)
1075            kReg.GetValue(m_dwStartView, szStartView, VIEW_ERASER);
1076
1077        ZeroMemory(&m_rWindowRect, sizeof(RECT));
1078
1079        if (kReg.GetValueSize(szWindowRect) == sizeof(RECT))
1080            kReg.GetValue((LPVOID)&m_rWindowRect, szWindowRect);
1081
1082        kReg.GetValue(m_bResultsForFiles, ERASER_REGISTRY_RESULTS_FILES, TRUE);
1083        kReg.GetValue(m_bResultsForUnusedSpace, ERASER_REGISTRY_RESULTS_UNUSEDSPACE, TRUE);
1084        kReg.GetValue(m_bResultsOnlyWhenFailed, ERASER_REGISTRY_RESULTS_WHENFAILED, FALSE);
1085        kReg.GetValue(m_bShellextResults, ERASEXT_REGISTRY_RESULTS, TRUE);
1086        kReg.GetValue(m_bErasextEnabled, ERASEXT_REGISTRY_ENABLED, TRUE);
1087        kReg.GetValue(m_bEnableSlowPoll, ERASER_RANDOM_SLOW_POLL, FALSE);
1088        kReg.GetValue(m_bIconAnimation, szIconAnimation, FALSE);
1089        kReg.GetValue(m_bSmallIconView, szSmallIconView, FALSE);
1090        kReg.GetValue(m_dwOutbarWidth, szOutBarWidth, 0);
1091        kReg.GetValue(m_bNoTrayIcon, szNoTrayIcon, FALSE);
1092        kReg.GetValue(m_bHideOnMinimize, szHideOnMinimize, FALSE);
1093        kReg.GetValue(m_bViewInfoBar, szViewInfoBar, FALSE);
1094        kReg.GetValue(m_bResolveLock, szResolveLock, TRUE);
1095        kReg.GetValue(m_bResolveAskUser, szResolveAskUser, TRUE);
1096       
1097
1098        kReg.Close();
1099    }
1100    else
1101        bResult = FALSE;
1102
1103    // Page File Clearing only on NT
1104    m_bClearSwap = FALSE;
1105
1106    if (ov.dwPlatformId == VER_PLATFORM_WIN32_NT)
1107    {
1108        if (kReg_reg.Open(HKEY_LOCAL_MACHINE, szClearSwapPath))
1109        {
1110            kReg_reg.GetValue(m_bClearSwap, szClearSwapValue, FALSE);
1111            kReg_reg.Close();
1112        }
1113    }
1114
1115    return bResult;
1116}
1117
1118void CEraserDoc::OnEditPreferencesGeneral()
1119{
1120    TRACE("CEraserDoc::OnEditPreferencesGeneral\n");
1121
1122    ReadPreferences();
1123
1124    CPreferencesSheet propSheet;
1125
1126    // General
1127
1128   
1129
1130    propSheet.m_pgEraser.m_bResultsForFiles         = m_bResultsForFiles;
1131    propSheet.m_pgEraser.m_bResultsForUnusedSpace   = m_bResultsForUnusedSpace;
1132    propSheet.m_pgEraser.m_bResultsOnlyWhenFailed   = m_bResultsOnlyWhenFailed;
1133    propSheet.m_pgEraser.m_bShellextResults         = m_bShellextResults;
1134    propSheet.m_pgEraser.m_bErasextEnabled          = m_bErasextEnabled;
1135    propSheet.m_pgEraser.m_bEnableSlowPoll          = m_bEnableSlowPoll;
1136    propSheet.m_pgEraser.m_bClearSwap               = m_bClearSwap;
1137    propSheet.m_pgEraser.m_bResolveLock             = m_bResolveLock;
1138    propSheet.m_pgEraser.m_bResolveAskUser          = m_bResolveAskUser;               
1139
1140
1141    // Scheduler
1142
1143    propSheet.m_pgScheduler.m_bNoTrayIcon           = m_bNoTrayIcon;
1144    propSheet.m_pgScheduler.m_bHideOnMinimize       = m_bHideOnMinimize;
1145    propSheet.m_pgScheduler.m_bLog                  = m_bLog;
1146    propSheet.m_pgScheduler.m_bLogOnlyErrors        = m_bLogOnlyErrors;
1147    propSheet.m_pgScheduler.m_bStartup              = m_bStartup;
1148    propSheet.m_pgScheduler.m_bEnabled              = m_bSchedulerEnabled;
1149    propSheet.m_pgScheduler.m_bQueueTasks           = m_bQueueTasks;
1150    propSheet.m_pgScheduler.m_bNoVisualErrors       = m_bNoVisualErrors;
1151    propSheet.m_pgScheduler.m_dwMaxLogSize          = m_dwMaxLogSize;
1152
1153    if (propSheet.DoModal())
1154    {
1155        // General
1156
1157        m_bResultsForFiles          = propSheet.m_pgEraser.m_bResultsForFiles;
1158        m_bResultsForUnusedSpace    = propSheet.m_pgEraser.m_bResultsForUnusedSpace;
1159        m_bResultsOnlyWhenFailed    = propSheet.m_pgEraser.m_bResultsOnlyWhenFailed;
1160        m_bShellextResults          = propSheet.m_pgEraser.m_bShellextResults;
1161        m_bErasextEnabled           = propSheet.m_pgEraser.m_bErasextEnabled;
1162        m_bEnableSlowPoll           = propSheet.m_pgEraser.m_bEnableSlowPoll;
1163        m_bClearSwap                = propSheet.m_pgEraser.m_bClearSwap;
1164        m_bResolveLock              = propSheet.m_pgEraser.m_bResolveLock;
1165        m_bResolveAskUser           = propSheet.m_pgEraser.m_bResolveAskUser;
1166
1167        // Scheduler
1168
1169        m_bNoTrayIcon               = propSheet.m_pgScheduler.m_bNoTrayIcon;
1170        m_bHideOnMinimize           = propSheet.m_pgScheduler.m_bHideOnMinimize;
1171        m_bLog                      = propSheet.m_pgScheduler.m_bLog;
1172        m_bLogOnlyErrors            = propSheet.m_pgScheduler.m_bLogOnlyErrors;
1173        m_bStartup                  = propSheet.m_pgScheduler.m_bStartup;
1174        m_bSchedulerEnabled         = propSheet.m_pgScheduler.m_bEnabled;
1175        m_bQueueTasks               = propSheet.m_pgScheduler.m_bQueueTasks;
1176        m_bNoVisualErrors           = propSheet.m_pgScheduler.m_bNoVisualErrors;
1177        m_dwMaxLogSize              = propSheet.m_pgScheduler.m_dwMaxLogSize;
1178
1179        if (!m_bNoTrayIcon && !m_stIcon.Visible())
1180            m_stIcon.ShowIcon();
1181        else if (m_bNoTrayIcon)
1182        {
1183            if (!m_bHideOnMinimize && !AfxGetMainWnd()->IsWindowVisible())
1184                AfxGetMainWnd()->ShowWindow(SW_SHOWMINIMIZED);
1185            else if (m_bHideOnMinimize && AfxGetMainWnd()->IsIconic())
1186                AfxGetMainWnd()->ShowWindow(SW_HIDE);
1187
1188            m_stIcon.HideIcon();
1189        }
1190
1191        UpdateToolTip();
1192
1193        if (!SavePreferences())
1194        {
1195            AfxTimeOutMessageBox(IDS_ERROR_PREFERENCES_SAVE, MB_ICONERROR);
1196
1197            if (m_bLog)
1198                LogAction(IDS_ERROR_PREFERENCES_SAVE);
1199        }
1200    }
1201}
1202
1203void CEraserDoc::OnEditPreferencesEraser()
1204{
1205    TRACE("CEraserDoc::OnEditPreferencesEraser\n");
1206    eraserShowOptions(AfxGetMainWnd()->GetSafeHwnd(), ERASER_PAGE_FILES);
1207}
1208
1209void CEraserDoc::OnFileViewLog()
1210{
1211    TRACE("CEraserDoc::OnFileViewLog\n");
1212
1213    CFileStatus fs;
1214    CString strPath = m_strExePath + szLogFile;
1215
1216    if (CFile::GetStatus((LPCTSTR)strPath, fs))
1217    {
1218        if (reinterpret_cast<int>(ShellExecute(NULL, "open", (LPCTSTR)strPath,
1219                                               NULL, NULL, SW_SHOWNORMAL)) <= 32)
1220        {
1221            AfxMessageBox(IDS_ERROR_VIEWLOG, MB_ICONERROR, 0);
1222        }
1223    }
1224    else
1225    {
1226        AfxMessageBox(IDS_INFO_NOLOG, MB_ICONINFORMATION, 0);
1227    }
1228}
1229
1230BOOL CEraserDoc::Export(LPCTSTR szFile, BOOL bErrors)
1231{
1232    TRACE("CEraserDoc::Export\n");
1233
1234    // export the present items into a file
1235
1236    CFileException fe;
1237    CFile* pFile = NULL;
1238
1239    pFile = GetFile(szFile, CFile::modeCreate |
1240                    CFile::modeReadWrite | CFile::shareExclusive, &fe);
1241
1242    if (pFile == NULL)
1243    {
1244        if (bErrors)
1245            ReportSaveLoadException(szFile, &fe, TRUE, AFX_IDP_INVALID_FILENAME);
1246        return FALSE;
1247    }
1248
1249    CArchive saveArchive(pFile, CArchive::store | CArchive::bNoFlushOnDelete);
1250
1251    saveArchive.m_pDocument  = this;
1252    saveArchive.m_bForceFlat = FALSE;
1253
1254    try
1255    {
1256        CWaitCursor wait;
1257        Serialize(saveArchive);
1258
1259        saveArchive.Close();
1260        ReleaseFile(pFile, FALSE);
1261    }
1262    catch (CFileException* e)
1263    {
1264        ASSERT(FALSE);
1265
1266        ReleaseFile(pFile, TRUE);
1267
1268        if (bErrors)
1269        {
1270            try
1271            {
1272                ReportSaveLoadException(szFile, e, TRUE, AFX_IDP_FAILED_TO_SAVE_DOC);
1273            }
1274            catch (...)
1275            {
1276            }
1277        }
1278
1279        if (m_bLog)
1280            LogException(e);
1281
1282        e->Delete();
1283        return FALSE;
1284    }
1285    catch (CException *e)
1286    {
1287        ASSERT(FALSE);
1288
1289        ReleaseFile(pFile, TRUE);
1290
1291        if (bErrors)
1292            REPORT_ERROR(e);
1293
1294        if (m_bLog)
1295            LogException(e);
1296
1297        e->Delete();
1298        return FALSE;
1299    }
1300
1301    return TRUE;
1302}
1303
1304BOOL CEraserDoc::Import(LPCTSTR szFile, BOOL bErrors)
1305{
1306    TRACE("CEraserDoc::Import\n");
1307
1308    // import items from a file without removing
1309    // present items
1310
1311    CFileException fe;
1312    CFile* pFile = NULL;
1313
1314    pFile = GetFile(szFile, CFile::modeRead | CFile::shareDenyWrite, &fe);
1315
1316    if (pFile == NULL)
1317    {
1318        if (bErrors)
1319            ReportSaveLoadException(szFile, &fe, TRUE, AFX_IDP_INVALID_FILENAME);
1320        return FALSE;
1321    }
1322
1323    CArchive loadArchive(pFile, CArchive::load | CArchive::bNoFlushOnDelete);
1324
1325    loadArchive.m_pDocument  = this;
1326    loadArchive.m_bForceFlat = FALSE;
1327
1328    try
1329    {
1330        CWaitCursor wait;
1331        if (pFile->GetLength() != 0)
1332            Serialize(loadArchive);
1333
1334        loadArchive.Close();
1335        ReleaseFile(pFile, FALSE);
1336    }
1337    catch (CFileException* e)
1338    {
1339        ASSERT(FALSE);
1340
1341        ReleaseFile(pFile, TRUE);
1342
1343        if (bErrors)
1344        {
1345            try
1346            {
1347                ReportSaveLoadException(szFile, e, TRUE, AFX_IDP_FAILED_TO_SAVE_DOC);
1348            }
1349            catch (...)
1350            {
1351            }
1352        }
1353
1354        if (m_bLog)
1355            LogException(e);
1356
1357        e->Delete();
1358        return FALSE;
1359    }
1360    catch (CException *e)
1361    {
1362        ASSERT(FALSE);
1363
1364        ReleaseFile(pFile, TRUE);
1365
1366        if (bErrors)
1367            REPORT_ERROR(e);
1368
1369        if (m_bLog)
1370            LogException(e);
1371
1372        e->Delete();
1373        return FALSE;
1374    }
1375
1376    return TRUE;
1377}
1378
1379BOOL CEraserDoc::SaveTasksToDefault()
1380{
1381    CString strDefault = m_strExePath + szDefaultFile;
1382    return Export((LPCTSTR)strDefault);
1383}
1384
1385void CEraserDoc::OnCloseDocument()
1386{
1387    TRACE("CEraserDoc::OnCloseDocument\n");
1388
1389    try
1390    {
1391        SaveTasksToDefault();
1392        CDocument::OnCloseDocument();
1393    }
1394    catch (CException *e)
1395    {
1396        ASSERT(FALSE);
1397        REPORT_ERROR(e);
1398        e->Delete();
1399    }
1400}
1401
1402
1403//DEL void CEraserDoc::OnHelpReward()
1404//DEL {
1405//DEL     AfxGetApp()->WinHelp(HID_BASE_COMMAND + ID_HELP_REWARD);
1406//DEL }
1407
1408void CEraserDoc::CleanList(CPtrArray& rList, int iItemSize)
1409{
1410    int iSize = rList.GetSize();
1411    while (iSize--)
1412    {
1413        if (!AfxIsValidAddress(rList[iSize], iItemSize))
1414            rList.RemoveAt(iSize);
1415    }
1416    rList.FreeExtra();
1417}
Note: See TracBrowser for help on using the repository browser.