~TVerDirectory(void); //-деструктор
void __fastcall Clear(void); //-очистка отчета
void __fastcallFill(void); //-главная функция для подготовки отчета
bool __fastcall WorkFile(int PathNum,AnsiString Name); //-проверка файла
bool __fastcall WorkDir(AnsiString Path); //-проверка каталога
// (с рекурсивными вызовами для подкаталогов)
void __fastcallSetNameList(TStrings * DestList); //-для передачи в оконный компонент списка одноименных файлов
void __fastcallSetExNames(TStrings * DestList); //-для передачи в оконный компонент списка исключений
void __fastcallSetDirList(intNameNum,TStrings * DestList);//-для передачи в оконный компонент списка путей расположения
// выбранного файла (с номером NameNum в списке NameList)
void __fastcallSetDirListEx(intNameNum,TStrings * DestList);//-для передачи в оконный компонент списка путей расположения
// выбранного файла (с номером NameNum в списке ExNames)
bool __fastcall SetEx(int Index); //передатьфайлиз NameList в ExNames
bool __fastcall ResetEx(int Index); //передать файл из ExNames в NameList
};
//---------------------------------------------------------------------------
//тип - форма главного окна
class TFForm : public TForm
{
__published: // IDE-managed Components
TButton *Button1;
TPopupMenu *PopupMenu1;
TMenuItem *N1;
TMenuItem *N2;
TPanel *Panel1;
TLabel *Label1;
TListBox *NameBox;
TLabel *Label2;
TListBox *DirBox;
TPanel *Panel2;
TLabel *Label3;
TButton *AddDirButton;
TTimer *Timer1;
TLabel *Label5;
TListBox *ExBox;
TLabel *Label4;
TSpeedButton *SetExButton;
TSpeedButton *ResetExButton;
TTimer *Timer2;
void __fastcall NameBoxClick(TObject *Sender);
void __fastcall FormActivate(TObject *Sender);
void __fastcall N1Click(TObject *Sender);
void __fastcall FormClose(TObject *Sender, TCloseAction &Action);
void __fastcall N2Click(TObject *Sender);
void __fastcall Button1Click(TObject *Sender);
void __fastcall Timer1Timer(TObject *Sender);
void __fastcall ExBoxClick(TObject *Sender);
void __fastcall AddDirButtonClick(TObject *Sender);
void __fastcall SetExButtonClick(TObject *Sender);
void __fastcall ResetExButtonClick(TObject *Sender);
private: // User declarations
void __fastcall WMShellMess(TMessage &Message); //обработчик WM_SHELLMESS
void __fastcall ShowMyWin(TMessage &Message); //обработчик WM_SHOWMYWIN
public: // User declarations
TVerDirectory *Report; //подготовленный отчет по одноименным файлам
TDirThread *DirThr; //поток проверки каталогов
TNotifyThread *NotifyThr; //поток автоматического контроля каталогов
TNotifyIconDataNotifyData; //структура для регистрации значка в SystemTray
boolAppClose; //признак выхода из программы
__fastcallTFForm(TComponent* Owner);//конструктор
void __fastcallCallThreads(void); //создание и запуск потоков контроля и проверки каталогов
void __fastcallStopThreads(void); //завершение и удаление потоков контроля и проверки каталогов
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_SHELLMESS, TMessage, WMShellMess)
MESSAGE_HANDLER(WM_SHOWMYWIN, TMessage, ShowMyWin)
END_MESSAGE_MAP(TForm)
};
//---------------------------------------------------------------------------
extern PACKAGE TFForm *FForm;
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#endif
Файл FMain.cpp
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "FMain.h"
#include "FSelectDirForm.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TFForm *FForm;
boolDirectoryNever; //признак необходимости перезапуска проверки каталогов
void *NeverMutex, //мъютекс для синхронизации доступа к DirectoryNever (для записи)
*NeverEvent; //событие для синхронизации потоков проверки файлов и контроля файлов
//---------------------------------------------------------------------------
//------------------------TGlobalList,TNameList---------------------------------
int __fastcall TGlobalList::At(int Index) {return (int)Objects[Index];}
TIntArray * __fastcall TNameList::At(int Index) {return (TIntArray *)Objects[Index];}
//---------------------------------------------------------------------------
//------------------------TVerDirectory----------------------------------------
TVerDirectory::TVerDirectory(TStrings * fExNames, AnsiString fPath, TDirThread * aOwner)
{
Path=fPath;
Owner=aOwner;
DirList= new TStringList();
GlobalList = new TGlobalList(); GlobalList->Sorted=true;
NameList = new TNameList(); NameList->Sorted=true;
ExNames = new TNameList(); ExNames->Sorted=true;
ExNames->AddStrings(fExNames);
}
//---------------------------------------------------------------------------
TVerDirectory::~TVerDirectory(void)
{
Clear();
delete DirList;
delete GlobalList;
delete NameList;
delete ExNames;
}
//---------------------------------------------------------------------------
void __fastcall TVerDirectory::Clear(void)
{
for(int i=0; i<NameList->Count;i++) delete NameList->At(i);
for(int i=0; i<ExNames->Count;i++)
if (ExNames->At(i) != NULL)
{
delete ExNames->At(i);
ExNames->Objects[i]=NULL;
}
NameList->Clear();
GlobalList->Clear();
DirList->Clear();
}
//---------------------------------------------------------------------------
//главная функция для проверки каталогов и подготовки отчета
//если проверка была прервана в связи с изменением состава файлов (взведен DirectoryNever)-
//проверка начинается сначала.
//если проверка была прервана в связи с завершением родительского потока - выход из функции
void __fastcall TVerDirectory::Fill(void)
{
bool cc=true;
while (!Owner->Term() && cc)
{
//проверка
cc=!WorkDir(Path);
if(cc)
{
Clear();
WaitForSingleObject( NeverMutex,INFINITE);
DirectoryNever=false;
ReleaseMutex(NeverMutex);
}
}
}
//---------------------------------------------------------------------------
//проверка-регистрация в отчете файла (по имени и номеру подкаталога)
//при изменении состава файлов(взведен DirectoryNever) или при завершении
//родительского потока - досрочный выход с результатом - false
bool __fastcall TVerDirectory::WorkFile(int PathNum,AnsiString Name)
{
//выход при необходимости
if (DirectoryNever || Owner->Term() ) return false;
int i, j,k;
TIntArray *T;
j=ExNames->IndexOf(Name);
if(j>=0)//имя в списке исключений
{
if(ExNames->At(j) == NULL) {//создать массив
T = new TIntArray(3);
ExNames->Objects[j]=(TObject *)T;
}
(ExNames->At(j))->Add(PathNum);//добавить номер каталога
}
else
{
i=GlobalList->IndexOf(Name);
if(i>=0)//такой файл уже есть
{
j = NameList->IndexOf(Name);
if(j>=0) (NameList->At(j))->Add(PathNum);//добавить номер каталога в массив
else { //создать и заполнить массив номеров каталогов
T = new TIntArray(3);
T->Add(GlobalList->At(i));
T->Add(PathNum);
//включить файл в список одинаковых
NameList->AddObject(Name,(TObject *)T);
}
}
else GlobalList->AddObject(Name,(TObject *)PathNum);//включить файл в общий список
}
//выход
returntrue;
}
//---------------------------------------------------------------------------
//проверка-регистрация в отчете каталога (а также его содержимого, для подкаталогов - рекурсивные вызовы)
//при изменении состава файлов(взведен DirectoryNever) или при завершении
//родительского потока - досрочный выход с результатом - false
bool __fastcall TVerDirectory::WorkDir(AnsiString Path)
{
//выход при необходимости
if (DirectoryNever || Owner->Term() ) return false;
TSearchRec SRec;
bool Result=true;
TStringList *FList = new TStringList(),*DList= new TStringList();
FList->Sorted=true;
DList->Sorted=true;
//заполнить списки файлов и каталогов
if(FindFirst(Path+"*.*",faAnyFile,SRec)==0)
do{
if(SRec.Name!="." && SRec.Name!="..")
{
if (SRec.Attr & faDirectory) DList->Add(SRec.Name);
else FList->Add(SRec.Name);
}
}while(FindNext(SRec)==0);
FindClose(SRec);
//обработка себя самого
DirList->Add(Path);
//обработка файлов
for(int i=0;i<FList->Count;i++)
if(!WorkFile(DirList->Count-1,FList->Strings[i])) {Result=false;break;}
delete FList;
//обработка подкаталогов
if(Result)
for(int i=0;i<DList->Count;i++)
if (!WorkDir(Path+DList->Strings[i]+"\")) {Result=false;break;};
delete DList;
//выход
return Result;
}
//---------------------------------------------------------------------------
void __fastcall TVerDirectory::SetNameList(TStrings * DestList)
{
DestList->Clear();
for(int i=0;i<NameList->Count;i++) DestList->Add(NameList->Strings[i]);
}
//---------------------------------------------------------------------------
void __fastcall TVerDirectory::SetExNames(TStrings * DestList)
{
DestList->Clear();
for(int i=0;i<ExNames->Count;i++) DestList->Add(ExNames->Strings[i]);
}
//---------------------------------------------------------------------------
void __fastcall TVerDirectory::SetDirList(int NameNum,TStrings * DestList)
{
DestList->Clear();
for(int i=0;i<NameList->At(NameNum)->Count;i++)
DestList->Add(DirList->Strings[NameList->At(NameNum)->Items[i]] );
}
//---------------------------------------------------------------------------
void __fastcall TVerDirectory::SetDirListEx(int NameNum,TStrings * DestList)
{
DestList->Clear();
if (ExNames->At(NameNum) == NULL) DestList->Add("ФАЙЛ ОТСУТСТВУЕТ"); else
for(int i=0;i<ExNames->At(NameNum)->Count;i++)
DestList->Add(DirList->Strings[ExNames->At(NameNum)->Items[i]] );
}
//---------------------------------------------------------------------------
bool __fastcall TVerDirectory::SetEx(int Index)
{
if(Index>=0 && Index<NameList->Count)
{
ExNames->AddObject(NameList->Strings[Index],NameList->Objects[Index]);
NameList->Delete(Index);
return true;
} else return false;
}
//---------------------------------------------------------------------------
bool __fastcall TVerDirectory::ResetEx(int Index)
{
if(Index>=0 && Index<ExNames->Count)
{
if(ExNames->At(Index)==NULL)
{
if(Application->MessageBoxA(((AnsiString)"Выбранный файл отсутствует в контролируемом каталоге.\n"+
"Удалить его из списка исключений?").c_str(),"Предупреждение",MB_YESNO | MB_ICONWARNING)==IDYES)
{
ExNames->Delete(Index);
return true;
}
} else
if(ExNames->At(Index)->Count==1)
{
if(Application->MessageBoxA(((AnsiString)"Выбранный файл в контролируемом каталоге присутствует в единственном числе.\n"+
"Удалить его из списка исключений?").c_str(),"Предупреждение",MB_YESNO | MB_ICONWARNING)==IDYES)
{
delete ExNames->At(Index);
ExNames->Delete(Index);
return true;
}
} else {
NameList->AddObject(ExNames->Strings[Index],ExNames->Objects[Index]);
ExNames->Delete(Index);
return true;
}
}
returnfalse;
}
//---------------------------------------------------------------------------
//------------------------------TDirThread--------------------------------------
//включает мигание надписи "Запущена проверка"
void __fastcall TDirThread::CheckStep(void)
{
FForm->Timer1->Enabled=true;
FForm->Label5->Visible=true;
}
//---------------------------------------------------------------------------
//передает подготовленный отчет главному окну программы
//(с открытием и активизацией главного окна)
void __fastcall TDirThread::SetLists(void)
{
//отключить мигание надписи "Запущена проверка"
FForm->Timer1->Enabled=false;
FForm->Label5->Visible=false;
TVerDirectory *OldReport=FForm->Report;
bool First=(OldReport == NULL);//First=true при подготовке потоком первого отчета
FForm->Report=Report; //передача нового отчета
//настройка оконных компонентов под новый отчет
FForm->Report->SetNameList(FForm->NameBox->Items);
FForm->ExBox->ItemIndex=-1;
FForm->DirBox->Clear();
FForm->SetExButton->Enabled=false;
FForm->ResetExButton->Enabled=false;
if(Report->NameList->Count>0)
FForm->Panel2->Caption="Обнаружены одноименные файлы!";
else FForm->Panel2->Caption="Одноименные файлы отсутствуют.";
//открытие и активизация главного окна приложения
if(!First && (Report->NameList->Count>0 || OldReport->NameList->Count>0))
if(FForm->Visible) {
//Второй запуск самого себя - только такой путь, чтобы вытащить окно на передний
//план (SetForegroundWindow из другого процесса)
WinExec(ParamStr(0).c_str(),SW_SHOWNORMAL);
}
else {//открыть окно
ShowWindow(Application->Handle, SW_SHOW);
FForm->Show();
}
if(!First) delete OldReport; //удалить старый отчет
//при подг-ке первого отчета (одноименных файлов нет) - скрыть окно через 2 сек.
else if (Report->NameList->Count==0) FForm->Timer2->Enabled=true;
}
//---------------------------------------------------------------------------
//главная функция потока проверки файлов
//первую проверку выполняет безусловно, последующие проверки - по взводу