Thursday, June 15, 2006

Асинхронная работа с регистром остатков 1С: полезные алгоритмы

Асинхронная работа с регистром остатков 1С: полезные алгоритмы

Асинхронные события и их обработчики (аналог в системе Windows - очередь оконных сообщений) позволяют исключительно просто реализовать полезные алгоритмы: контроль отрицательных остатков, восстановление последовательностей, история сохранения документа, автоматическое обновление формы отчета при закрытии документа.
Автор статьи: romix | Редакторы: Волшебник
Последняя редакция №3 от 16.02.06 | История
URL: http://kb.mista.ru/article.php?id=68


Ключевые слова: ОбработкаВнешнегоСобытия, восстановление последовательности, проведение документов, отрицательные остатки


Часть информации из этой статьи систематизирует мои предыдущие разработки на эту тему: я постарался упростить код и сделать его более быстродействующим и универсальным. Вы можете придумать что-то свое и, возможно, захотите включить свои идеи в эту статью, поскольку она размещена на обновляемом ресурсе.

Как правило, пользователи 1С:Предприятие 7.7 хотят
  • Контролировать остаток товара на складе (или остаток чего-либо в другой предметной области), как минимум, выдавая сообщение при отрицательных остатках.

  • Видеть историю документа (когда, кто и что сохранял)
  • Не иметь особенных трудностей, когда нарушена последовательность документов (многие пользователи вообще с трудом понимают, что это такое)

  • Сохраняя документ, открытый из отчета, видеть заново сформированную форму отчета (например, отчета по остаткам).
  • И, разумеется, видеть остатки в справочнике номенклатуры.



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

В качестве теста я использую простую конфигурацию для учета товаров на складе, где есть приходная и расходная накладные, регистр остатков и отчет по остаткам. Речь, разумеется, может идти не только о товарах и складах. Есть множество других предметных областей, где действует этот же механизм, и применим регистр остатков (в терминологии 1С:Предприятие 8.0 – регистр накопления).

Чтобы было понятнее, о чем идет речь, откройте тестовую конфигурацию для 1С:Предприятие 7.7, ссылка на которую приведена в конце этой статьи, и проделайте следующие опыты:

1) В документе приходной накладной №1 от 09.06.2005 измените стоимость товара «Ветчина "Любительская", нарезка 360 гр.» на несколько рублей или копеек. Проведите документ. Теперь загляните в справочник «Контроль последовательности» - в нем появились ссылки на все документы, содержащие эту ветчину, которые были проведены после измененного документа. Запустите обработку «Восстановление последовательности» - она перепроведет все «некошерные» документы с ветчиной и очистит этот справочник. Я уже описывал подобный режим имитации последовательностей, хотя сильно сомневаюсь, что кто-то понял, о чем тогда шла речь – здесь приведена более простая и быстродействующая реализация, которая не «нагружает» модуль проведения, а реализует контроль движений «до» и «после» с использованием событий.

2) Откройте документ приходной накладной и нажмите на кнопку История. Обработка для ведения истории документа универсальна для документов любого вида, и фиксирует, в данном исполнении, только конечное (после завершения или отката всех транзакций) состояние документа. Сведения хранятся вне базы данных, во внешних файлах, т.к. они нужны, как и файл журнала регистрации mlg, главным образом, для успокоения пользователей, и придания им уверенности в своих действиях. Вы можете использовать этот же трюк не только для показа истории документа, но и в других областях применения, где нужно фиксировать конечное состояние объектов ИБ (по сокращению, которое я здесь применил, вы можете догадаться, какие именно области применения я имею в виду).

3) Выполните любое действие, которое приведет к отрицательному остатку на складе. Например, укажите в расходном документе вместо количества 5 значение 55 (представим, что у пользователя дрогнула рука). Программа выдаст предупреждение, что возник отрицательный остаток, и покажет таблицу с товаром, который «ушел в минус». В журнале для документа возникнет значок «Запрет печати». В реальной конфигурации вы можете запретить пользователям печатать такие документы (что не рекомендуется), а можете и разрешить, поскольку ошибка могла быть в более ранних документах. И именно их следовало запрещать печатать. К сожалению, нет способа выявить ошибку «дрогнувшей руки», если изначальный остаток был больше 55, и отрицательное значение, спустя время, «вылезло» лишь по исчерпании партии товара, когда она стала подходить близко к концу. Поэтому на складах проводят регулярную инвентаризацию: оприходуют излишки и списывают (понятно, с кого) недостачи, поскольку отрицательные остатки могут быть лишь «вершиной айсберга» накопившихся пользовательских ошибок.

4) Откройте справочник Номенклатура и посмотрите значения в колонке «Остаток». Эта колонка не обновляется из регистра, но, некоторым образом, содержит реальный остаток товара. Поэтому, в отличие от традиционной реализации этого пользовательского пожелания, когда для отображения остатков используется регистр, вы не заметите в справочнике «тормозов». Установите галочку «Имеющиеся». Вы увидите только те товары, по которым есть ненулевой остаток (и которые не помечены на удаление). Снимите эту галочку – вы опять увидите все товары. Даже если вы заблокируете (откроете на редактирование) карточку товара, то остаток по этому товару будет корректно обновлен после закрытия карточки. Про трюк с остатками в справочнике я уже рассказывал в другой статье – здесь же приведена его более универсальная и быстродействующая реализация.

5) Откройте отчет «Остатки товара». Дважды щелкните мышью по документу в отчете, например, «Расходная накладная 1». Измените количество товара (например, с 5 на 7) и проведите документ. Убедитесь, что отчет корректно обновился, и теперь показывает новые цифры. Вы не обновляли отчет, но он обновился сам после записи открытого из него документа – как такое могло быть?

Вы очень удивитесь, когда узнаете, сколько строк кода занимает реализация всех этих механизмов.

Обработки:

ДвиженияДокументаДоПроведения – 43 строки
ДвиженияДокументаПослеПроведения – 38 строк
КонтрольОтрицательногоОстатка – 47 строк
КонтрольПоследовательности – 62 строки
ИзменитьОстаткиСправочникаТоваров – 33 строки
История_Записать – 93 строки (универсальный для документов любого вида)
История_Просмотр – 45 строк (универсальный для документов любого вида)

Это полный код, включая пустые строчки, избыточный код, добавленный для ясности, и все комментарии.

Глобальный модуль - 123 строки (включая весь код)

Модули проведения документов не содержат ничего, что относилось бы к указанным функциям, а модули формы наших документов (приходной и расходной накладных) содержат дополнительные 4 строки вызова обработки в процедуре ПриЗаписи():

Если ПустоеЗначение(ТекущийДокумент())=1 Тогда
Записать();
КонецЕсли;
ОткрытьФормуМодально("Обработка.ДвиженияДокументаДоПроведения", ТекущийДокумент());


Наверное, можно было бы сократить код вызова до 1 строки, передавая контекст, но для ясности я делаю вызов в 4 строки.

Код вышеуказанных обработок универсален для всех документов, но он «заточен» под определенный регистр остатков. В данном примере, регистр остатков содержит единственное измерение «Товар» и ресурсы «Количество» и «Сумма». Если вы увеличите сложность регистра, то увеличится и объем кода, но не намного (пожалуй, добавятся по 1-2 строки кода на каждое измерение или ресурс).

Если вы увеличите число задействованных документов, то обработки не изменятся совершенно, а в модуле формы каждого из новых документов потребуется всего лишь вставить вышеуказанные 4 строки.

Принцип реализации данных обработок основан на вызове и последующей обработке внешних событий. Обработчик внешнего события выглядит следующим образом:

///////////////////////////////////////////////////////////////////////
//Предопределенная процедура
Процедура ОбработкаВнешнегоСобытия(прм_Источник,прм_Событие,прм_Данные)
//...
КонецПроцедуры


Чтобы сгенерировать событие, я использую внешнюю компоненту, которая поддерживает вызов наподобие:

fakir.ВызватьСобытие("fakir", "ИзменениеДокумента",  ЗначениеВСтрокуВнутр(док));


Генерация событий является штатным механизмом, описанным в «Технологии создания внешних компонент» для 1С:Предприятия, и поддерживается как в версии 7.7, так и в версии 8.0. Исходный код внешней компоненты на языке Delphi приложен в архиве конфигурации. Для первого запуска конфигурации в системе Windows необходимы права администратора или привилегированного пользователя.

Я использую свойство асинхронности внешних событий – их можно вызвать в любой момент времени, но сработают они после завершения работы программного кода 1С. Так, я могу сгенерировать событие в процедуре ПриЗаписи(), а сработает оно только после «устаканивания» всех транзакций, когда реальные (т.е. строго после проведения или отмены проведения документа) остатки уже можно читать из регистра. Сравнивая состояния движений регистра по документу «до» и «после», я выполняю различные полезные действия.



Конфигурация для скачивания:
http://x-romix.narod.ru/Fakir3.rar
(217 КБ, скачивать левой кнопкой мыши)

Запрет запуска ert на низком уровне

Запрет запуска ert на низком уровне

Статья описывает возможность запрета на программный и интерактивный доступ к внешним ert средствами внешней компоненты (ВК). Приведен пример внешней компоненты с исходным кодом.
Автор статьи: romix | Редакторы: jbond
Последняя редакция №4 от 08.04.06 | История
URL: http://kb.mista.ru/article.php?id=114


Ключевые слова: ert, внешний отчет, внешняя обработка, запрет, безопасность, защитить


см. также
Книга знаний: Взлом и защита 1С:Предприятие 7.7

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

Другими словами, штатные средства 1С:Предприятие позволяют заблокировать только интерактивный, но не программный доступ к ert.

Приведенная ниже внешняя компонента позволяет блокировать доступ (как программный, так и интерактивный) к внешним отчетам и обработкам вне папки ExtForms конфигурации (в этой же папке должна находиться и компонента StopErt.dll).

Внешняя компонента перехватывает системный вызов CreateFile (эта функция используется в системе Windows для создания или открытия файлов) и блокирует доступ к ert, путь которых не принадлежит требуемой папке или содержит "..". Две точки как в Windows, так и в Unix используются для выхода в вышестоящую папку, что необходимо учитывать во избежание "хитрых" действий пользователя по обходу защиты.

Методика программного перехвата функций DLL подробно описана в книге Джеффри Рихтера "Windows для профессионалов".

Инициализация внешней компоненты



        ФайлВК=КаталогИБ()+"ExtForms\StopErt.dll";
Если ЗагрузитьВнешнююКомпоненту(ФайлВК)=0 Тогда
Сообщить("Не удается загрузить "+ФайлВК);
Возврат;
КонецЕсли;


Больше ничего делать не нужно.
Первый запуск конфигурации необходимо производить под правами администратора или привилегированного пользователя Windows.




Внешняя компонента для скачивания:

http://x-romix.narod.ru/StopErt.rar
(~63К, скачивать ЛЕВОЙ кнопкой мыши).

В комплекте с компонентой идет описание, тестовый пример конфигурации с внешними отчетами и исходный код (компилятор - Delphi 6).

Вариант с использованием ВК 1С++ 2.0.2 или FormEx 2.0.2:



ПриЗагрузкеВнешнегоОтчета / OnLoadAsExternalForm
Синтаксис: ПриЗагрузкеВнешнегоОтчета(ИмяФайлаОтчета)
Параметры:
• ИмяФайлаОтчета - полный путь к файлу отчета (вместе с собственно именем файла).
Описание: Предопределенная процедура глобального модуля вызывается при загрузке внешнего отчета. Если в процедуре установить статус возврата в ноль, то внешний отчет не будет загружен.
Пример:

Процедура ПриЗагрузкеВнешнегоОтчета(ИмяФайлаОтчета)
// разрешен запуск внешних отчетов только из определенной папки
РазрешенныйПуть = КаталогИБ() + "\ВнешниеОтчеты\";
Если Врег(Лев(ИмяФайлаОтчета,СтрДлина(РазрешенныйПуть))) <> Врег(РазрешенныйПуть) Тогда
Сообщить("Запуск внешних отчетов разрешен только из каталога """+РазрешенныйПуть+"""");
СтатусВозврата(0);
КонецЕсли;
КонецПроцедуры


Как всегда 1С++ рулит по полной программе!

(от romix: функционал 1C++ в части ПриЗагрузкеВнешнегоОтчета был дополнен по результатам достаточно горячего обсуждения этой статьи Запрет запуска ert на низком уровне (статья+ВК)).

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

Работа с последовательным (COM, RS-232) портом из 1С:Предприятие 7.7 и 8.0
Последовательный порт на практике служит для подключения к компьютеру считывателей штрих-кодов, электронных весов, а также другого внешнего оборудования. Статья описывает работу с последовательным портом в 1С:Предприятие 7.7 и 8.0. Приведен пример исходного кода внешней компоненты (Delphi 6), которая заменяет типовую компоненту scanopos.dll. Автор статьи: romix | Редакторы: Волшебник
Последняя редакция №7 от 25.04.06 | История
URL: http://kb.mista.ru/article.php?id=77

Ключевые слова: последовательный порт, COM, RS232, четность, кабель, сканер, RS-232, асинхронный, USB, ОбработкаВнешнегоСобытия, внешняя компонента, Delphi, scanopos.dll, TThread, торговое оборудование, связь


Интерфейс RS-232 был разработан в 1969 году рядом крупных промышленных корпораций и опубликован Ассоциацией электронной промышленности США (Electronic Industries Association — EIA). (http://ru.wikipedia.org/wiki/RS-232).

Стандартные установки последовательного порта

При экспериментах я устанавливал следующие (стандартные) настройки порта: скорость 9600 бит/с, 1 стоповый бит, нет контроля четности, 8 бит/байт). Для своих опытов я использовал кабель для соединения портов COM1 и COM2. Вы можете спаять такой кабель по схеме http://subscribe.ru/archive/tech.electronics/200104/21033223.html), или приобрести его на рынке примерно за 70 рублей.

Чувствительность к "горячему" подключению

Следует отметить, что COM и LPT-порты чувствительны к "горячему" подключению - соединяя включенные устройства, вы можете спалить порты (или что-то еще). Поэтому перед подключением устройства я рекомендую отключать их от сети питания, и только потом их выполнять их электрическое соединение.
USB этим недостатком не страдает, и дозволяет "горячее" подключение устройств.

Эмуляция COM-порта при наличии USB-соединения

Имеется возможность представить порт USB "под именем" свободного COM-порта, например, при помощи драйвера (FTDI, сайт http://www.ftdichip.com), и работать с ним как с новым COM-портом.

Посылка тестовых данных в COM-порт

Имея тестовый кабель, вы уже можете экспериментировать с внешними компонентами для 1С:Предприятие.
Посылку тестовых данных в порт я производил из пакетного (.BAT) файла MS-DOS. Содержимое моего файла test.bat:

mode com2 baud=9600 parity=n data=8 stop=1
type c:\test.txt >com2


В файле c:\test.txt введите несколько символов (например, 1234567890) и завершите - обязательно! - их символом перевода строки (нажатием Enter).

Программа, подключенная к другому концу кабеля, может быть тестовой программой TestComPort.exe (скачайте комплект, приведенный в конце статьи; в программе надо выбрать порт - в данном случае COM1, нажать Открыть, и уже можно посылать в нее символы при помощи BAT-файла, в большом окне вы увидите принятые текстовые строки), конфигурацией для 1С:Предприятие, приложенной в этом же архиве, или стандартной конфигурацией наподобие "1С:Торговля и Склад", где активизирована работа со сканером, подключенным в последовательный порт (внешняя компонента scanopos.dll).

Получение внешнего события в 1С:Предприятие

Внешнее событие, например, со сканера, с другого внешнего оборудования, или просто сгенерированное программно, приходит в 1С (как 7.7, так и 8.0) в предопределенную процедуру
ОбработкаВнешнегоСобытия().

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

Данные="+Данные);
КонецПроцедуры



Эта процедура может располагаться в глобальном модуле или модуле формы 1С:Предприятие 7.7 или 8.0. Процедура принимает три входящих параметра: Источник, Событие и Данные. Это три текстовые строки, которые могут принимать произвольные значения - в качестве Источника можно установить имя внешней компоненты, в качестве события - строку-идентификатор события, например, "BarCodeValue", а в качестве данных - данные от устройства, например, считанный штрихкод.

Инициализация внешней компоненты

Код процедуры ПриНачалеРаботыСистемы() в тестовой конфигурации выглядит следующим образом:

///////////////////////////////////////////////////////////////////////
Процедура ПриНачалеРаботыСистемы() //Предопределенная процедура 1С
ок=1;
Если глЗагрузитьВнешнююКомпоненту("vk_rs232")=0 Тогда
Сообщить("Внешняя компонента не была загружена!","!");
Иначе
rs232=СоздатьОбъект("AddIn.vk_rs232");
КонецЕсли;

ИмяПорта=""+Константа.ComPort;

Сообщить("Константа.ComPort: "+ИмяПорта);
Сообщить("При считывании кода, который завершается символами #13#10, здесь должны

появляться считанные строки.");

//Начинаем слушать порт
rs232.ОткрытьПорт(ИмяПорта);

КонецПроцедуры



Первый запуск конфигурации необходимо производить под правами администратора или привилегированного пользователя Windows. Это необходимо для любых внешних компонент или OLE-объектов, чтобы компонента (DLL) могла "прописать" себя в системный реестр Windows.

Пример работы с COM-портом

Рассмотренные ниже примеры работы с последовательным (COM-) портом будут использовать средства Windows API (системные функции CreateFile и т.д.). Для компиляции примеров потребуется Delphi версии 6 (впрочем, вы легко сможете переделать примеры под любой язык программирования, который поддерживает вызовы Windows API).

В конце статьи приведена ссылка, по которой вы можете скачать работающие примеры кода внешней компоненты (vk_rs232.dll) и упрощенного тестового примера (TestComPort.exe, который содержит 120 строк тестового кода). Рассмотренная в качестве примера внешняя компонента для 1С:Предприятие
умеет читать текстовые строки из последовательного порта, и представлять их как событие считывания штрихкода "BarCodeValue". Поэтому компоненту можно без изменений использовать, например, в конфигурации "Торговля и Склад" в качестве замены для штатной компоненты для считывания штрихкодов. Также компонента умеет записывать "встречные" данные в последовательный порт, если это необходимо для работы с устройствами (для сканеров штрих-кодов это не нужно).

Пример расчитан на передачу в устройство или из устройства текстовых строк, разделенных символами 13,10, что характерно, например, для сканеров штрихкодов. Я использую фиксированные настройки (скорость - 9600, один стоп-бит, без бита четности, 8 бит в одном байте), а также фиксированные настройки таймаута (чтение "отваливается" через относительно короткий промежуток времени, чтобы избежать зависания). Вы можете переделать эти умолчания под ваше оборудование и требования к программному обеспечению.

Настройка сканера

Вы можете настроить сканер на те или иные завершающие коды (#13#10 и другие), а также изменить его настройки при помощи установочных штрихкодов, которые обычно поставляются в комплекте устройства.

Общая идеология работы с RS-232 в системе Windows

В MS-DOS (и ранних версиях Windows, включая 95 и 98), работа с последовательными портами часто производилась напрямую через порты ввода-вывода командами Ассемблера IN и OUT. Этот способ не поддерживают современные операционные системы, начиная с Windows NT. В них остается (надо сказать, довольно древняя) возможность работы с этими портами как с файлами.

Например, достаточно открыть файл с именем "COM1", чтобы можно было писать в него данные для внешнего устройства, и читать из него данные от этого устройства (входной и выходной поток данных не пересекаются).

hCom:=CreateFile("COM2", ... );

ok:=WriteFile( //uses Windows
hCom, //Файл
Buff[1], //Буфер откуда пишем
nBytes, //Число байтов для считывания
wr_cnt, //Число записанных байтов
nil
);

ok:=ReadFile( //uses Windows
hCom, //Файл
Buff, //Буфер куда считываем
100, //Число байтов для считывания
rd_cnt, //Число считанных байтов
nil
);

CloseHandle(hCom);




Настройки параметров и таймаутов COM-порта производятся при помощи функций SetCommState и SetCommTimeOuts соответственно. Ссылка на работающий пример кода, который показывает эту идею более развернуто, приведена в конце статьи.

Конечно, есть возможность работать с COM-портом и "более простыми средствами" - вплоть до открытия файла с именем "COM2", записи строк в этот файл и чтения встречных данных от устройства из этого же файла.

Внешняя компонента, по сравнению с этим "простым" решением, добавляет возможность генерировать события считывания данных (например, штрихкодов со сканера) в асинхронном режиме, когда 1С не "замирает" до очередного считывания штрихкода, и не "крутится" в бесконечном цикле чтения, а получает внешние события, и реагирует на них в предопределенной процедуре ОбработкаВнешнегоСобытия(). Это удобно для пользователя, и не заставляет его нажимать на клавиатуре лишние клавиши перед считыванием штрихкода.

MSDN

В качестве официальной справки по различным функциям Windows используйте MSDN, который можно приобрести на DVD или на 3-х CD. В качестве "источника и составной части" он входит в комплект средств разработки от Microsoft, или приобретается отдельно. Кроме того, MSDN выложен в интернете, и как правило, находится в первых строках запросов в поисковике Google по контрастному запросу наподобие "SetCommState".

Последние изменения (08.03.2006)

Компонента теперь использует потоки (объект TThread) вместо таймера. Компонента содержит тестовый пример для работы с двумя объектами (например, двумя сканерами).


Заключение

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

Скачать тестовую конфигурацию и исходный код внешней компоненты

Скачать тестовую конфигурацию и исходный код внешней компоненты вы можете по этой ссылке:
http://x-romix.narod.ru/vk_rs232.rar

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

Отслеживание изменений в файловой системе и программирование потоков (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 килобайт).

Взлом и защита 1С:Предприятие 7.7

Взлом и защита 1С:Предприятие 7.7

В статье описаны как штатные механизмы защиты 1С:Предприятие 7.7 от обхода встроенной системы разграничения прав доступа, так и параметры настройки реестра Windows, а также программные ограничения WH_CBT (Computer Base Training - блокировки для обучающих программ). Показано сокрытие кнопки Пуск и рабочего стола средствами Windows API.
Автор статьи: romix | Редакторы: Волшебник
Последняя редакция №9 от 26.04.06 | История
URL: http://kb.mista.ru/article.php?id=55


Ключевые слова: WH_CBT, Computer Base Training, защитить базу от скачивания, настроить права доступа, скрыть рабочий стол, скрыть кнопку Пуск, заблокировать диалоги открытия, заблокировать диспетчер задач, заблокировать Windows+E, заблокировать Windows+R, NoWinKeys, DisableTaskMgr


Блокируем запуск внешнего кода на языке 1С


Оказывается, 1С:Предприятие 7.7 не выполняет проверок прав доступа со стороны программного кода – все проверки выполняются только в интерактивном (пользовательском) режиме. Поэтому для защиты необходимо полностью закрыть любые возможности для выполнения любого поступающего извне программного кода, что вполне обеспечивают средства администрирования 1С (и системы Windows NT/2000/XP).

Откроем в Конфигураторе информационную базу и зайдем на вкладку Права. Дважды щелкнем на название имеющегося набора прав (или создадим новый набор). Из контекстного меню при клике на корневом элементе появившегося «дерева» выберем единственный пункт «Свойства». В списке перечислены потенциально опасные действия пользователей. Рассмотрим некоторые из них.

Настройка: Административные функции


Уберите эту галочку, и пользователи не смогут под своим паролем изменять конфигурацию (файл конфигурации MD).

Разумеется, типичный Темный Пользователь может пойти обходным путем, и изменить непосредственно файл MD (например, при помощи плагина для FAR DocFile Browser, который умеет читать и изменять Compound-файлы Microsoft). Поэтому, файл MD необходимо открыть пользователям для доступа по сети только на чтение. Аналогично следует поступать с текстовыми файлами, которые извлечены из MD посредством директивы #ЗагрузитьИзФайла или внешней компоненты TurboMD.

Настройка: Использование в качестве OLE Automation сервера


Информационную базу можно «поюзать» через механизм OLE. Закройте для Темного Пользователя еще одну дверь, которая позволила бы ему видеть и изменять в информационной базе все.

Настройка: Использование любых Внешних Отчетов и Обработок



Уберите эту галочку, и Темные Пользователи не смогут запускать программный код 1С в виде привнесенных извне отчетов и обработок (файлов ert). Эта возможность тоже, независимо от прав, позволяет делать с информационной базой практически все.

Настройка: Использование общих Внешних Отчетов и Обработок


Общие внешние отчеты и обработки находятся в папке ExtForms. На эту папку, разумеется, необходимо установить права доступа «только на чтение». Иначе Темные Пользователи положат в эту папку нужные им обработки, и выполнят произвольный программный код.

Настройка: Использование функций в табло и формульном калькуляторе


Малоизвестная возможность, но она тоже позволяет «сделать все», не имея никаких других прав.
Откройте пункт меню Сервис-Табло. Наберите в появившемся Табло (засветите в него) следующий программный код:
ОткрытьФорму("Отчет",," Тест.ert") 

Если в каталоге информационной базы лежит внешний отчет Тест.ert, то он будет открыт и выполнен, независимо от установленных у пользователя прав на выполнение Внешних Отчетов и Обработок. Аналогичная возможность имеется для калькулятора, если в меню Сервис-Параметры, на вкладке Общие, Темный Пользователь установил для него формульный режим.

Методы ОткрытьФорму/ОткрытьФормуМодально



Аналогичная уязвимость может существовать для конфигураций: если они выполняют встроенную функцию 1С наподобие
ОткрытьФорму("Отчет", , ИмяФайлаОтчета);
ОткрытьФормуМодально("Отчет", , ИмяФайлаОтчета);

не проверяя пользовательские права, то Темный 1С-ник может сделать с информационной базой опять же все, что захочет, ибо для него информационная база полностью открыта. Поэтому закройте в систему и эти «врата», и у Темного 1С-ника будет меньше шансов выполнить свое черное дело.

Защита таблицы


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

ОбработкаЯчейкиТаблицы


Темный 1С-ник может занести в поле Расшифровка таблицы совсем не то, что предусматривал разработчик.
Например, "Отчет.КарточкаСчета". Таким способом, он может открыть "неположенный" ему по должности отчет.

Блокируем чтение и изменение таблиц данных


Информационную базу (особенно, в DBF-варианте) злоумышленник может скопировать и унести целиком, ибо в сжатом виде она может «весить» совсем немного. После этого, злоумышленник может просто удалить папку с паролями, и получить к своей копии базы полный, ничем не ограниченный доступ.

SQL-вариант информационной базы тоже может быть скопирован, но для этого надо знать имя сервера и пароль пользователя sa (или логин и пароль dbo). Как же узнать эту информацию? Она хранится (в зашифрованном виде) в файле DBA информационной базы, и поддается расшифровке при помощи небольшой «хакерской» утилиты (название не помню).

Впрочем, во многих случаях пароль sa назначен пустым, или представляет собой любимое многими администраторами значение 123. Чтобы выяснить этот факт, достаточно воспользоваться сетевым сканером безопасности, который выявит в вашей сети эти и подобные огрехи. Удачным сканером безопасности является программа x-spider.

Однако, про утилитку, извлекающую из информации о подключении логины и пароли, Темные Пользователи, разумеется, уже знают, поэтому пустой или не пустой пароль sa - особой роли уже не играет. Факт в том, что при любом пароле Темные Пользователи могут делать с информационной базой 1С все, что угодно: копировать всю базу, а также изменять или удалять отдельные записи. Правда, это придется делать на более низком уровне (правкой таблиц информационной базы), но ничего невозможного или сверхсложного в этом нет. Таблицы есть таблицы, просматривать и редактировать их можно небольшими утилитами или скриптами (в т.ч. из комплекта Microsoft Office), а связи между элементами данных прописаны в текстовом файле DD/DDS.

Защита при помощи сервера терминалов



Поэтому, пожалуй, единственным способом защититься от подобных атак является запрет запуска в пользовательском сеансе 1С других программ, за исключением 1С:Предприятие (это может быть реализовано, например, на сервере терминалов). Защита от запуска посторонних программ реализуется при помощи ключа реестра RestrictRun (или соответствующих настроек в групповой политике домена).
HKCU Software  Microsoft   Windows    CurrentVersion     Policies      Explorer\RestrictRun 


Строковые параметры с именами в виде чисел по возрастанию указывают, запуск каких программ необходимо разрешить (запуск остальных будет запрещен), например:
1=c:\Program Files\1Cv77\BIN\1cv7s.exe
2=c:\program files\msoffice\winword.exe

При экспериментах разрешите себе запуск regedit.exe.

Прописывайте полные пути, иначе Темный Пользователь сможет назвать именем 1cv7s.exe произвольный софт.

Скрываем кнопку Пуск и Рабочий стол



Пример программы, которая скрывает кнопку Пуск (вместе с панелью задач) и рабочий стол.
Чтобы от панели задач не оставалась «дырка» в окне Windows, включите ее (панели задач) автоскрытие.

Компилятор – Delphi 6.
Имя файла – HideStartButton.dpr.
Program HideStartButton;

uses Windows;

var h1, h2 : THandle;

begin
h1 := FindWindow('ProgMan', nil);
h1 := GetWindow(h1, GW_CHILD);
ShowWindow(h1, SW_HIDE);

h2 := FindWindow('Shell_TrayWnd', nil);
ShowWindow(h2, SW_HIDE);

MessageBox(0, 'Рабочий стол и кнопка Пуск были скрыты.', 'HideStartButton', MB_ICONINFORMATION);

ShowWindow(h1, SW_SHOW);
ShowWindow(h2, SW_SHOW);

MessageBox(0, 'Рабочий стол и кнопка Пуск были восстановлены.', 'HideStartButton', MB_ICONINFORMATION);

end.

Скомпилированные примеры кода приведены в конце этой статьи.

Блокируем окна «Открыть» и «Сохранить как», а также меню Пуск


Пример программы, которая блокирует окна «Открыть» и «Сохранить как», а также запрещает открытие меню кнопки Пуск по нажатию Ctrl-Esc и кнопки Windows.

Компилятор – Delphi 6.
Имя файла – HookCreateWindow.dpr.
Program HookCreateWindow;
uses Windows;

var HookHandle: hHook;

///////////////////////////////////////////////////////////////////////
//Ловушка WH_CBT (Computer Base Training - блокировки для обучающих программ)
function CBTProc(Code: integer; WParam: word; LParam: Integer): Longint; stdcall;

type PCBT_CREATEWND=^CBT_CREATEWND;
var s: pchar;
var z: PCBT_CREATEWND;
var ok: Integer;
begin
if Code<0 then begin
Result := CallNextHookEx(HookHandle, code, WParam, LParam);
exit;
end;

case Code of
HCBT_CREATEWND: begin //Перехватываем создание окна

z:=PCBT_CREATEWND(LParam);

//Получаем заголовок окна
s:=z.lpcs.lpszName;


if s<>nil then begin

ok:=0;

//Сравнение заголовка окна и подстроки
if s^<>'О' then ok:=1; inc(s);
if s^<>'т' then ok:=1; inc(s);
if s^<>'к' then ok:=1; inc(s);
if s^<>'р' then ok:=1; inc(s);
if s^<>'ы' then ok:=1; inc(s);
if s^<>'т' then ok:=1; inc(s);
if s^<>'ь' then ok:=1; inc(s);
if s^<>#0 then ok:=1;



if ok=0 then begin //Если подстрока найдена..
Result:=1; //.. то запрещаем открытие окна
exit;
end;

end;

end;// HCBT_CREATEWND:

HCBT_SYSCOMMAND: begin
case WParam of

//Блокируем меню Пуск по Ctrl-Esc и клавише Windows
SC_TASKLIST: begin
Result:=1; //Запрещаем действие
exit;
end;

end;//case WParam

end; // HCBT_SYSCOMMAND:
end;//case

Result := 0;//Разрешаем действие
end;

///////////////////////////////////////////////////////////////////////
begin
//Устанавливаем ловушку на сообщения WH_CBT
HookHandle := SetWindowsHookEx(WH_CBT, @CBTProc, HInstance, 0);

if HookHandle<=0 then begin
MessageBox(0,'Ошибка - ловушка не была установлена!','HookCreateWindow',MB_ICONERROR);
Exit;
end;

MessageBox(0, 'Ловушка установлена. Проверьте диалоги открытия и записи файла.', 'HookCreateWindow', MB_ICONINFORMATION);

//Убираем ловушку
if HookHandle <> 0 then
UnhookWindowsHookEx(HookHandle);

MessageBox(0, 'Ловушка снята. Диалоги открытия и записи файла снова доступны.', 'HookCreateWindow', MB_ICONINFORMATION);
end.

Скомпилированные примеры кода приведены в конце этой статьи.

Автозапуск примеров



Автозапуск примеров из меню "Пуск-Программы-Автозагрузка" может быть отключен Темным пользователем удерживанием при старте клавиши Shift. Поэтому, автозапуск необходимо поместить "поглубже" в реестр.
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run]
"HideDesktop"="E:\\Защита1С\\WinHooks\\HideStartButton\\HideStartButton.exe /i"
"HookCreateWindow"="E:\\Защита1С\\WinHooks\\HookCreateWindow\\HookCreateWindow.exe /i"

Для их автозапуска для всех пользователей -
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run]

(однако, будьте с этим осторожны, чтобы не заблокировать все себе).

Ключ /i отключает окна с вопросами и заставляет программу "заснуть".
  if ParamStr(1)='/i' then begin
repeat
sleep(10000);
until false;
end;

Это не самый лучший способ оставить программу в памяти, но он работает (не хотелось усложнять примеры). Другой вариант сделать то же самое - запустить их как службу (если вы, конечно, знаете, как это проделать).

Автозапуск примеров для текущего пользователя


"HideDesktop"="E:\\Защита1С\\WinHooks\\HideStartButton\\HideStartButton.exe /i"
"HookCreateWindow"="E:\\Защита1С\\WinHooks\\HookCreateWindow\\HookCreateWindow.exe /i"


Блокируем нажатия Windows-E и Windows-R


Они открывают, соответственно, проводник и окно «Запуск программы», которые позволят Темному Пользователю сделать свое черное дело.
Ключ реестра NoWinKeys блокирует горячие клавиши Windows:
HKCU Software  Microsoft   Windows    CurrentVersion     Policies      Explorer\NoWinKeys = dword:1m


Отключение запуска диспетчера задач по Ctrl-Alt-Del


Еще одна лазейка для Темного Пользователя.
Ключ реестра DisableTaskMgr блокирует диспетчер задач:
HKCU Software  Microsoft   Windows    CurrentVersion     Policies      System\DisableTaskMgr = dword:1 


Блокируем изменение программных файлов 1С:Предприятие


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

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

При терминальном доступе данной проблемы не существует (конечно, при условии, что права терминального пользователя не позволяют ему патчить программные файлы).




Скомпилированные примеры кода из статьи приведены здесь:
http://x-romix.narod.ru/WinHooks.rar
Скачивать левой кнопкой мыши (20К).


-----
см. также:
http://www.i2r.ru/static/530/out_13477.shtml
Книга знаний: Запрет запуска ert на низком уровне

Защита сервера терминалов

Защита сервера терминалов

Поэтому, пожалуй, единственным способом защититься от подобных атак является запрет запуска в пользовательском сеансе 1С других программ, за исключением 1С:Предприятие (это может быть реализовано, например, на сервере терминалов). Защита от запуска посторонних программ реализуется при помощи ключа реестра RestrictRun (или соответствующих настроек в групповой политике домена).
HKCU Software  Microsoft   Windows    CurrentVersion     Policies      Explorer\RestrictRun 


Строковые параметры с именами в виде чисел по возрастанию указывают, запуск каких программ необходимо разрешить (запуск остальных будет запрещен), например:
1=c:\Program Files\1Cv77\BIN\1cv7s.exe
2=c:\program files\msoffice\winword.exe

При экспериментах разрешите себе запуск regedit.exe.

Прописывайте полные пути, иначе Темный Пользователь сможет назвать именем 1cv7s.exe произвольный софт.