В статье рассматривается пример программной блокировки файла таблицы журнала 1С: Предприятие 7.7. Обращение к Win-API выполняется связыванием через ActivX-компоненту DynamicWrapperX.
В сети уже довольно много написано о блокировках таблиц программы 1С: Предприятие 7.7 и о том, как их избежать путем оптимизации железа и обработок проведения документов. Данная статья, наоборот, описывает, как программно вызвать блокировку одной или нескольких ее таблиц. Зачем это нужно? — возникает закономерный вопрос. Какая польза от того, что в таблицу нельзя будет ничего записать ни методами 1С: Предприятие 7.7, ни прямым запросом, при помощи OLEDB и ODBC — драйвера? Но, это не так. Оказывается, уже лет десять, как есть исправленный vfpoledb-драйвер, в котором вырезаны все функции блокировки файла таблицы таким образом, что можно выполнять прямые запросы, в том числе и на запись данных в таблицу, не запрашивая информацию о наложенных на файл блокировках и без попыток самому их наложить.
Итак, приготовились. Запустили дополнительный сеанс 1С: Предприятие для тестирования блокировки проведения.
Необходимый для работы набор констант:
Скрипт = СоздатьОбъект("MSScriptControl.ScriptControl");
Скрипт.Language = "JScript";
Скрипт.AddCode("
|GENERIC_READ = 0x80000000;
|GENERIC_WRITE = 0x40000000;
|GENERIC_READ_WRITE = GENERIC_READ|GENERIC_WRITE;
|FILE_SHARE_READ = 1;
|FILE_SHARE_WRITE = 2;
|FILE_SHARE_READ_WRITE = FILE_SHARE_READ|FILE_SHARE_WRITE;
|OPEN_EXISTING = 3;
|OPEN_ALWAYS = 4;
|FILE_ATTRIBUTE_NORMAL = 128");
Модуль = Скрипт.Modules("Global").CodeObject;
Подключение функций Win-API
WinAPI= СоздатьОбъект("DynamicWrapperX.2");
Открытие таблицы журнала 1С: Предприятие 7.7 (1sjourn.dbf). Подключение необходимых функций библиотеки:
WinAPI.Register("KERNEL32.DLL", "CreateFile", "i=sllllll", "r=l");
WinAPI.Register("KERNEL32.DLL", "LockFile", "i=hllll", "r=l");
WinAPI.Register("KERNEL32.DLL", "UnlockFile", "i=hllll", "r=l");
Открытие таблицы в режиме GENERIC_READ_WRITE, FILE_SHARE_READ_WRITE, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL:
Хендл = WinAPI.CreateFile(СтрЗаменить(СтрЗаменить(КаталогИБ() + "1sjourn.dbf", "\", "\\"), "\\\\", "\\"),
Модуль.GENERIC_READ_WRITE, Модуль.FILE_SHARE_READ_WRITE, 0, Модуль.OPEN_EXISTING, Модуль.FILE_ATTRIBUTE_NORMAL, 0);
Установка блокировки на запись в журнал
Если Хендл <> -1 Тогда
Рез = WinAPI.LockFile(Хендл, 1073741823, 0, 1, 0);
Если Рез <> - 1 Тогда
Рез = WinAPI.LockFile(Хендл, 1073741824, 0, 1073741823, 0);
Иначе
Сообщить("Не удалось заблокировать таблицу");
КонецЕсли;
Иначе
Сообщить("Не удалось заблокировать таблицу");
КонецЕсли;
Подключим функцию ожидания
WinAPI.Register("KERNEL32.DLL", "Sleep", "i=l", "f=s");
Подержим блокировку 15 секунд
WinAPI.Sleep(15000);
При попытки проведения в другом сеансе, в строке состояния на весь период блокировки будет высвечиваться «Ожидание захвата таблицы ‘Журналы’ для начала транзакции». Если в параметрах программы в сеансе для проведения настроить параметр «время ожидания захвата таблиц базы данных» меньше отведенных в обработке 15-ти секунд, тогда по истечении времени ожидания система выдаст сообщение: При выполнении транзакции произошла ошибка! Таблица: 1SJOURN Ошибка обращения к данным при транзакции, выполняемой другим пользователем. Повторить попытку выполнить транзакцию? Таким образом, видим, механизм работает. Без снятия блокировки, записать данные в таблицу невозможно. К слову сказать, мы тоже не можем ничего писать в эту таблицу, даже если заменим режим ожидания на попытки программно выполнить запись или проведение документа Разблокируем таблицу:
Если Хендл <> -1 Тогда
Рез = WinAPI.UnlockFile(Хендл, 1073741823, 0, 1, 0);
Если Рез <> - 1 Тогда
Рез = WinAPI.UnlockFile(Хендл, 1073741824, 0, 1073741823, 0);
Иначе
Сообщить("Не удалось снять блокировку таблицы");
КонецЕсли;
Иначе
Сообщить("Не удалось снять блокировку таблицы");
КонецЕсли;
Установка блокировки на чтение в журнал. Блокировка на запись в таблице 1С не так чревата последствиями как, вполне ожидаемо, блокировка на чтение. Блокировка на чтение в таблицу:
Если Хендл <> -1 Тогда
Рез = WinAPI.LockFile(Хендл, 1073741772, 0, 1, 0);
Если Рез <> - 1 Тогда
Рез = WinAPI.LockFile(Хендл, 1073741773, 0, 50, 0);
Иначе
Сообщить("Не удалось заблокировать таблицу");
КонецЕсли;
Иначе
Сообщить("Не удалось заблокировать таблицу");
КонецЕсли;
Подержим блокировку 15 секунд:
WinAPI.Sleep(15000);
При попытке просмотра записей таблицы журнала документов, будет отображаться в строке состояния надпись «Ожидание захвата таблицы ‘Журналы’ для чтения». В случае, если приложение на сможет получить доступ к таблице базы данных достаточно продолжительное время, оно завершит свою работу. Разблокируем таблицу:
Если Хендл <> -1 Тогда
Рез = WinAPI.UnlockFile(Хендл, 1073741772, 0, 1, 0);
Если Рез <> - 1 Тогда
Рез = WinAPI.UnlockFile(Хендл, 1073741773, 0, 50, 0);
Иначе
Сообщить("Не удалось снять блокировку таблицы");
КонецЕсли;
Иначе
Сообщить("Не удалось снять блокировку таблицы");
КонецЕсли;
Закроем хендл таблицы:
WinAPI.Register("KERNEL32.DLL", "CloseHandle", "i=h", "r=l");
Рез = WinAPI.CloseHandle(Хендл);