//события NeverEvent (от потока контроля)
void __fastcall TDirThread::Execute()
{
while(!Terminated)
{
//создать Report
Report=new TVerDirectory( FForm->ExBox->Items,FForm->AddDirButton->Caption ,this);
//сбросить DirectoryNever
WaitForSingleObject( NeverMutex,INFINITE);
DirectoryNever=false;
ReleaseMutex(NeverMutex);
//отметить начало проверки
Synchronize(CheckStep);
//проверка
Report->Fill();
if (!Terminated)//если поток не завершен
{
//передать отчет главному окну
Synchronize(SetLists);
//ожидание взвода события NeverEvent
WaitForSingleObject(NeverEvent,INFINITE);
}
elsedeleteReport;//удаление отчета при завершении потока
}
}
//---------------------------------------------------------------------------
//------------------------------TNotifyThread--------------------------------------
//функция потока автоматического контроля файлов каталогов (переименование, добавление, удаление файлов)
//работает через механизм FindFirstChangeNotification - FindNextChangeNotification.
//предусмотрен механизм завершения потока - по взводу события NeverEvent
void __fastcall TNotifyThread::Execute()
{
THandleArray Handles=THandleArray(2);
HANDLE Handle;
int i;
unsigned int Num;
Handles.Add(NeverEvent);
//поставить каталог на контроль, получить дескриптор ожидания
Handle=FindFirstChangeNotification( FForm->AddDirButton->Caption.c_str(),
true,FILE_NOTIFY_CHANGE_FILE_NAME);
if (Handle!=INVALID_HANDLE_VALUE) Handles.Add(Handle);
while(!Terminated)
{
//ожидание событий (NeverEvent или Handles[1..Handles.Count-1])
Num=WaitForMultipleObjects(Handles.Count,&(Handles[0]),false,INFINITE);
if(Num==WAIT_OBJECT_0)//взвод события NeverEvent - предполагается завершение потока
{}else
if(Num>WAIT_OBJECT_0 && Num<WAIT_OBJECT_0+Handles.Count)
{ //взвод Handles[1..Handles.Count-1] - изменение файлов одного из каталогов
Num-=WAIT_OBJECT_0;//номер сработавшего HANDLE
Sleep(100);//подождать 100 мс
//взвести DirectoryNever (для перезапуска проверки, если проверка (в другом потоке) еще не закончена)
WaitForSingleObject( NeverMutex,INFINITE);
DirectoryNever=true;
ReleaseMutex(NeverMutex);
//взвести-сбросить событие NeverEvent (для запуска проверки в потоке проверки файлов)
PulseEvent(NeverEvent);
//снова поставить сработавший каталог на контроль
if(!FindNextChangeNotification(Handles[Num]))
{ //если на проверку не ставится
FindCloseChangeNotification(Handles[Num]);
Handles.Delete(Num);
}
}
}
//освободить дескрипторы ожидания
for(i=1;i<Handles.Count;i++) FindCloseChangeNotification(Handles[i]);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//-------------------------------TFForm--------------------------------------------
//конструктор формы
__fastcall TFForm::TFForm(TComponent* Owner)
: TForm(Owner)
{
Report=NULL;
AppClose=false;
}
//---------------------------------------------------------------------------
//обновляет содержимое списка DirBox при выборе файла в списке NameBox
void __fastcall TFForm::NameBoxClick(TObject *Sender)
{
if(Report && NameBox->ItemIndex>=0) Report->SetDirList(NameBox->ItemIndex,DirBox->Items);
SetExButton->Enabled=(NameBox->Items->Count>0 && NameBox->ItemIndex>=0);
ResetExButton->Enabled=(ExBox->Items->Count>0 && ExBox->ItemIndex>=0);
}
//---------------------------------------------------------------------------
//обновляет содержимое списка DirBox при выборе файла в списке ExBox
void __fastcall TFForm::ExBoxClick(TObject *Sender)
{
if(Report && ExBox->ItemIndex>=0) Report->SetDirListEx(ExBox->ItemIndex,DirBox->Items);
SetExButton->Enabled=(NameBox->Items->Count>0 && NameBox->ItemIndex>=0);
ResetExButton->Enabled=(ExBox->Items->Count>0 && ExBox->ItemIndex>=0);
}
//---------------------------------------------------------------------------
//создание запуск потоков проверки и контроля файлов каталогов
void __fastcall TFForm::CallThreads(void)
{
DirectoryNever=false;
DirThr=new TDirThread(false);
NotifyThr=newTNotifyThread(false);
}
//---------------------------------------------------------------------------
//остановка и удаление потоков проверки и контроля файлов каталогов
void __fastcall TFForm::StopThreads(void)
{
//взвести Terminated у обоих потоков
NotifyThr->Terminate();
DirThr->Terminate();
//взвести-сбросить событие NeverEvent для завершения потоков (для выхода из функций ожидания)
PulseEvent(NeverEvent);
DirThr->WaitFor();//дождаться завершения потока DirThr
deleteDirThr; //удалить DirThr
NotifyThr->WaitFor();//дождаться завершения потока NotifyThr
deleteNotifyThr; //удалить NotifyThr
//отключить мигание надписи "Запущена проверка"
Timer1->Enabled=false;
Label5->Visible=false;
}
//---------------------------------------------------------------------------
//обработчик OnActivate формы (работает только при запуске программы)
//регистрирует значок в SystemTray, инициализирует переменные, запускает потоки
void __fastcall TFForm::FormActivate(TObject *Sender)
{
NotifyData.cbSize=sizeof(NotifyData);
NotifyData.hWnd=Handle;
NotifyData.uID=0;
NotifyData.uFlags=NIF_ICON | NIF_MESSAGE | NIF_TIP;
NotifyData.uCallbackMessage=WM_SHELLMESS;
NotifyData.hIcon=Application->Icon->Handle;
strncpy(&(NotifyData.szTip[0]),"Контроль одноименных файлов",sizeof(NotifyData.szTip));
Shell_NotifyIcon(NIM_ADD,&NotifyData);
Application->Title="Контроль файлов";
OnActivate=NULL;
NeverMutex=CreateMutex( NULL,false,"");
NeverEvent=CreateEvent( NULL,true,false,"");
if( FileExists(ChangeFileExt(ParamStr(0),".inf")) )//если есть файл параметров
{//прочитать файл параметров
TStringList *S=new TStringList;
S->LoadFromFile(ChangeFileExt(ParamStr(0),".inf"));
AddDirButton->Caption=S->Strings[0]; //контролируемый каталог
for(int i=1;i<S->Count;i++) ExBox->Items->Add(S->Strings[i]);//список исключений
delete S;
}
else AddDirButton->Caption=ExtractFilePath(ParamStr(0));
SetExButton->Enabled=(NameBox->Items->Count>0 && NameBox->ItemIndex>=0);
ResetExButton->Enabled=(ExBox->Items->Count>0 && ExBox->ItemIndex>=0);
CallThreads();
}
//---------------------------------------------------------------------------
/*
Msg.LParam=
512 - кнопки мыши не нажаты
513, 514 - нажать, отпустить левую кнопку ..001,..010
516, 517 - нажать, отпустить правую кнопку ..0100,..0101
519, 520 - нажать, отпустить среднюю кнопку ..0111,..1000
*/
//обработчик событий от значка в SystemTray -
//показывает всплывающее меню при щелчке мышью на значке в SystemTray
void __fastcall TFForm::WMShellMess(TMessage &Message)
{
if(Message.WParam ==0)
switch(Message.LParam)
{
case 513:
case 516:if(!SDForm->Visible)
{
TPoint tp;
SetForegroundWindow(Handle);
GetCursorPos(&tp);
N1->Enabled=!Visible || IsIconic(Application->Handle);
PopupMenu1->Popup(tp.x,tp.y);
PostMessage(Handle,WM_NULL,0,0);
}
break;
}
}
//---------------------------------------------------------------------------
//обработчик сообщения от второй копии приложения - для открытия и показа главного окна
void __fastcall TFForm::ShowMyWin(TMessage &Message)
{
ShowWindow(Application->Handle, SW_SHOWNORMAL);
Show();
}
//---------------------------------------------------------------------------
//обработчик пуккта всплывающего меню "Отчет, настройки программы"
//открывает и показывает главное окно
void __fastcallTFForm::N1Click(TObject *Sender)
{
ShowWindow(Application->Handle, SW_SHOWNORMAL);
Show();
}
//---------------------------------------------------------------------------
//обработчик OnClose (при закрытии) формы
void __fastcall TFForm::FormClose(TObject *Sender, TCloseAction &Action)
{
Timer2->Enabled=false;
if(AppClose) {//закрытие программы разрешено - выполняет деинициализирующие действия
StopThreads();//остановка-удаление потоков
if(Report) deleteReport; //удаление отчета
CloseHandle(NeverMutex); //освобождение объектов
CloseHandle(NeverEvent); //
Shell_NotifyIcon(NIM_DELETE,&NotifyData); //удаление значка из System Tray
//сохранение параметров в файл "FileNames.inf"
TStringList *S = new TStringList();
S->Add(AddDirButton->Caption);//контролируемый каталог
for(int i=0;i<ExBox->Items->Count;i++) S->Add(ExBox->Items->Strings[i]);//список исключений
S->SaveToFile(ChangeFileExt(ParamStr(0),".inf"));
deleteS;
}
else {//закрытие программы запрещено - только скрывает окно
Action=caNone;
Hide();
ShowWindow(Application->Handle, SW_HIDE);
}
}
//---------------------------------------------------------------------------
//обработчик пуккта всплывающего меню "Закрыть программу"
//взводит признак AppClose и закрывает главное окно
void __fastcall TFForm::N2Click(TObject *Sender)
{
if(!SDForm->Visible)
{
AppClose=true;
Close();
}
}
//---------------------------------------------------------------------------
//обработчик кнопки "Скрыть окно" - скрывает главное окно
void __fastcall TFForm::Button1Click(TObject *Sender)
{
Timer2->Enabled=false;
Hide();
ShowWindow(Application->Handle, SW_HIDE);
}
//---------------------------------------------------------------------------
//обработчик таймера - осуществляет мигание надписи "Запущена проверка..."
void __fastcall TFForm::Timer1Timer(TObject *Sender)
{
Label5->Visible=!Label5->Visible;
}
//---------------------------------------------------------------------------
//Обработчик кнопки AddDirButton -
//открывает окно SDForm для смены контр-го каталога, и перезапускает потоки
void __fastcall TFForm::AddDirButtonClick(TObject *Sender)
{
AnsiString Dir=AddDirButton->Caption;
if(Dir.Length() > 3) Dir.SetLength(Dir.Length()-1);
SDForm->DriveComboBox1->Drive=Dir[1];
SDForm->DirectoryListBox1->Directory=Dir;
if(SDForm->ShowModal()==mrOk)
{
Dir=SDForm->DirectoryListBox1->Directory;
if(Dir.Length() > 3) Dir=Dir+'\';
StopThreads();
AddDirButton->Caption=Dir;
CallThreads();
}
}
//---------------------------------------------------------------------------
//Обработчик кнопки "Стрелка вниз" - передает файл из списка одноименных в список исключений
void __fastcall TFForm::SetExButtonClick(TObject *Sender)
{
if(Report->SetEx(NameBox->ItemIndex))
{
Report->SetNameList(NameBox->Items);
Report->SetExNames(ExBox->Items);
DirBox->Items->Clear();
SetExButton->Enabled=false;
ResetExButton->Enabled=false;
if(Report->NameList->Count>0) Panel2->Caption="Обнаружены одноименные файлы!";
elsePanel2->Caption="Одноименные файлы отсутствуют.";
}
}
//---------------------------------------------------------------------------
//Обработчик кнопки "Стрелка верх" - передает файл из списка исключений в список одноименных
// или удаляет файл из списка исключений
void __fastcall TFForm::ResetExButtonClick(TObject *Sender)
{
if(Report->ResetEx(ExBox->ItemIndex))
{
Report->SetNameList(NameBox->Items);
Report->SetExNames(ExBox->Items);
DirBox->Items->Clear();
SetExButton->Enabled=false;
ResetExButton->Enabled=false;
if(Report->NameList->Count>0) Panel2->Caption="Обнаружены одноименные файлы!";
elsePanel2->Caption="Одноименные файлы отсутствуют.";
}
}