Книга знаний

1С:Предприятие / Приемы программирования / Внешние компоненты

Отслеживание изменений в файловой системе и программирование потоков (threads)

Статья содержит пример использования потоков (threads) и отслеживания изменений в папке (каталоге) в файловой системе. К статье приложен пример исходного кода внешней компоненты (компилятор - Delphi 6) для 1С:Предприятие 7.7/8.0.Автор статьи: romix | Редакторы:
Последняя редакция №3 от 09.03.06 | История
URL: http://kb.mista.ru/article.php?id=119

Ключевые слова: Внешняя компонента, Delphi, поток, thread, TThread, опрос директории, отслеживание изменений в файлах, FindFirstChangeNotification, WaitForSingleObject


Отслеживание изменений в директории


При реализации обмена между программами часто требуется проинформировать принимающую систему (в нашем случае, 1С:Предприятие) о том, что файлы пришли, и их пора принимать.

Как вариант, можно сканировать папку в процедуре обработки ожидания (например, делать это каждые N секунд).

Другой, пожалуй, более правильный способ - использовать системные функции FindFirstChangeNotification, FindNextChangeNotification и FindCloseChangeNotification из Windows API (аналогичные функции есть и в ОС Unix). В данном случае, оповещения об изменении в файловой системе выполняет ядро ОС, и не надо "проделывать дырку" на жестком диске постоянными к нему обращениями.

Что мы делаем из кода 1С


///////////////////////////////////////////////////////////////////////
Процедура ПриНачалеРаботыСистемы() //Предопределенная процедура 1С

        ЗагрузитьВнешнююКомпоненту(vk_ChangeNotification.dll)
        vk=СоздатьОбъект("AddIn.vk_ChangeNotification");

    vk.ОтслеживатьПодкаталоги=0;
    vk.НачатьКонтрольИзменений("c:\"); 
КонецПроцедуры


После такой инициализации в процедуру ОбработкаВнешнегоСобытия 1С будет приходить оповещения об изменении, в данном примере, папки "c:\". Если установить параметр vk.ОтслеживатьПодкаталоги=1, то еще и вложенных папок. Отслеживаться будут только изменения в именах файлов (например, появление нового файла в директории), но не изменение содержания файлов.

///////////////////////////////////////////////////////////////////////
Процедура ОбработкаВнешнегоСобытия(Источник,Событие,Данные)//Предопределенная процедура 1С
    //Глобальный обработчик внешнего события
    Сообщить("Внешнее событие: Источник="+Источник+"  Событие="+Событие+"  Данные="+Данные);
КонецПроцедуры


Чтобы прекратить опрос изменений в директории, доступна функция

///////////////////////////////////////////////////////////////////////
Процедура ПриЗавершенииРаботыСистемы()
    vk.ЗакончитьКонтрольИзменений();
КонецПроцедуры    // ПриЗавершенииРаботыСистемы


Процедура потока в Delphi


//Процедура потока
procedure TMyThread.Execute;
var r: Cardinal;
var fn : THandle;
begin
  fn:=0;
  try
    fn := FindFirstChangeNotification(pChar(MyObject.DirName), MyObject.CheckSubfolders, FILE_NOTIFY_CHANGE_FILE_NAME);
    if fn=INVALID_HANDLE_VALUE then
      RaiseLastOSError;
      
    repeat
       r := WaitForSingleObject(fn,2000);
       if r = WAIT_OBJECT_0 then
         MyObject.iEvent.ExternalEvent(c_AddinName, 'FolderChange', MyObject.DirName);

       if not FindNextChangeNotification(fn) then begin
          RaiseLastOSError;
          break;
       end;
    until Terminated;

    FindCloseChangeNotification(fn);

  except
     on E:Exception do begin
       try
         FindCloseChangeNotification(fn);
       except
       end;
       MyObject.ShowErrorLog('Ошибка контроля папки: '+E.Message);
     end;
  end;

end;


Процедура генерирует события (ExternalEvent), как только обнаружит изменения в указанной папке файловой системы. Параметр FILE_NOTIFY_CHANGE_FILE_NAME указывает на необходимость контролировать имена файлов. См. справку по WinAPI (например, на диске MSDN), чтобы узнать, какие варианты этого параметра есть еще.

Инициализация потока


Для потока я определяю отдельный класс, унаследованный от TThread.
type
  TMyThread = class(TThread) //Новый класс
  private
    MyObject: AddInObject;

  protected
    constructor Create(prm_Obj:AddInObject);
    procedure Execute; override;
  end;

Конструктор класса описан следующим образом:
constructor TMyThread.Create(prm_Obj:AddInObject);
begin
    inherited Create(False);
    MyObject:=prm_Obj;
end;


Объект внешней компоненты содержит поле MyThread (тип - TThread).

В методе ВК я инициализирую переменную потока так:
MyThread := TMyThread.Create(Self);


В этот момент начинает выполняться наша процедура потока:
procedure TMyThread.Execute;

И выполняется она до тех пор, пока я не дам команду потоку остановиться:
        MyThread.Terminate; //завершаем поток
        MyThread.WaitFor; //ждем, когда поток закончит свое выполнение
        MyThread.Destroy;
        MyThread:=nil;

Поток может изловить ситуацию, что его хотят завершить, прочитав свойство Terminated:
    repeat
        //...
    until Terminated;


Вызов MyThread.WaitFor ждет, когда поток завершит свою работу, после чего переменную можно разрушать - MyThread.Destroy.

Заключение


Мы рассмотрели работу с потоком исполнения во внешней компоненте 1С:Предприятие.
Поток выполняет полезное действие - отслеживает изменение файлов в директории.
Вы можете заставить поток делать что-то другое: например, опрашивать FTP, почтовый ящик, опрашивать сканер штрихкодов или выполнять другие полезные действия в автоматическом режиме.

Ссылки



http://ad.cctpu.edu.ru/SSP/Prof/index.html

Книга знаний: Работа с последовательным (COM, RS-232) портом из 1С:Предприятие 7.7 и 8.0




Внешняя компонента с исходным кодом и тестовой конфигурацией для скачивания:

http://x-romix.narod.ru/vk_ChangeNotification.rar
(скачивать ЛЕВОЙ кнопкой мыши, 97 килобайт).
Закладка

Описание | Рубрикатор | Поиск | ТелепатБот | Захваченные статьи | Установки | Форум
© Станислав Митичкин (Волшебник), 2005-2011 | Mista.ru

Яндекс.Метрика