Резервное копирование информационных баз 1С 8.2 (консольное приложение на DELPHI, Клиент-Сервер)

Программа производит блокировку входа пользователей, отключает всех от базы, выгружает базу в .dt средствами 1с.
После окончания выгрузки снимает блокировку. В архиве имеются исходники.

 

Запускать можно без параметров тогда программа возьмет с файла «cfg.ini» раздел «default» если его нету то выйдет.

В  файле «cfg.ini» можно прописать несколько разделов и передавать их названия в качестве параметров.

Пример  файла «cfg.ini» :

[default]
DumpPath=C:
ServerName=uppserver
InfoBaseName=test
ClasterPortNumber=1541
InfoBasesAdminName=admin
InfoBasesAdminPass=123
ClasterAdminName=
ClasterAdminPass=
LockPermissionCode=1234

[upp]
DumpPath=C:
ServerName=server2
InfoBaseName=upp
ClasterPortNumber=1541
InfoBasesAdminName=admin
InfoBasesAdminPass=123
ClasterAdminName=
ClasterAdminPass=
LockPermissionCode=123455

Листинг кода на Delphi 7:

program backup;

//Не будем светить окном
//{$APPTYPE CONSOLE}

uses
Windows,
SysUtils,
Variants,
ComObj,
Registry,
inifiles,
ActiveX;

type
TdataZap = record
DumpPath : string;
ServerName : string;
InfoBaseName : string;
ClasterPortNumber : string;
InfoBasesAdminName : string;
InfoBasesAdminPass : string;
ClasterAdminName : string;
ClasterAdminPass : string;
LockPermissionCode : string;
end;

//Найдем путь до 1с (результат функции, пример: ‘C:Program Files1cv828.2.19.76in1cv8.exe’)
function Path1C:string;
var reg : TRegistry;
begin
reg:=TRegistry.Create;
reg.RootKey:=HKEY_CLASSES_ROOT;
reg.OpenKey(‘CLSID{5CD98F13-1050-4b43-84F2-33AD97CFC287}LocalServer32’, false);
result:=reg.ReadString(»);
reg.CloseKey;
reg.Free;
end;

//выполнить запуск с ожиданием завершения процесса
function ExecAndWait(const FileName,
Params: ShortString;
const WinState: Word): boolean; export;
var
StartInfo: TStartupInfo;
ProcInfo: TProcessInformation;
CmdLine: ShortString;
begin
{ Помещаем имя файла между кавычками, с соблюдением всех пробелов в именах Win9x }
CmdLine := ‘»‘ + Filename + ‘» ‘ + Params;
FillChar(StartInfo, SizeOf(StartInfo), #0);
with StartInfo do
begin
cb := SizeOf(StartInfo);
dwFlags := STARTF_USESHOWWINDOW;
wShowWindow := WinState;
end;
Result := CreateProcess(nil, PChar( String( CmdLine ) ), nil, nil, false,
CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS, nil,
PChar(ExtractFilePath(Filename)),StartInfo,ProcInfo);
{ Ожидаем завершения приложения }
if Result then
begin
WaitForSingleObject(ProcInfo.hProcess, INFINITE);
{ Free the Handles }
CloseHandle(ProcInfo.hProcess);
CloseHandle(ProcInfo.hThread);
end;
end;

procedure Zapusk(dataR:TdataZap);
var
bin1c,LockMessageText,FullPathName,sDate1,sDate2:string;
FindInfoBase:boolean;
ComConnector,ServerAgent,Clasters,WorkingProcesses,
connecttoworkprocess,InfoBases,InfoBase,Connections:Variant;
lK,lW,lB,lC: LongWord;
begin
bin1c := Path1C; //прочитаем путь до 1с из реестра

LockMessageText := ‘База закрыта на БЭКАП’;
FindInfoBase:=false;
DateTimeToString(sDate1, ‘yyyy-mm-dd’, now());
DateTimeToString(sDate2, ‘HH-NN’, now());
FullPathName:=dataR.DumpPath+sdate1+’_’+sdate2+’_’+dataR.InfoBaseName+’.dt’;

ComConnector :=UnAssigned;
ComConnector := CreateOLEObject(‘V82.ComConnector’);
ServerAgent := ComConnector.ConnectAgent(dataR.ServerName);
//Получим массив кластеров сервера
Clasters := ServerAgent.GetClusters;
for lK := 0 to VarArrayHighBound(Clasters, 1) do
//проверка на нужный порт кластера(если больше одного)
If Clasters[lK].MainPort = dataR.ClasterPortNumber Then
begin
ServerAgent.Authenticate(Clasters[lK],dataR.ClasterAdminName,dataR.ClasterAdminPass);
//Получим список рабочих процессов
WorkingProcesses := ServerAgent.GetWorkingProcesses(Clasters[lK]);
for lW := 0 to VarArrayHighBound(WorkingProcesses, 1) do
If WorkingProcesses[lW].Running = 1 Then
begin
connecttoworkprocess := ComConnector.ConnectWorkingProcess(‘tcp://’+WorkingProcesses[lW].HostName + ‘:’ + inttostr(WorkingProcesses[lW].MainPort));
connecttoworkprocess.AuthenticateAdmin(dataR.ClasterAdminName, dataR.ClasterAdminPass);
connecttoworkprocess.AddAuthentication(dataR.InfoBasesAdminName, dataR.InfoBasesAdminPass);
If Not FindInfoBase Then
begin
InfoBases := connecttoworkprocess.GetInfoBases;
for lB := 0 to VarArrayHighBound(InfoBases, 1) do
if LowerCase(InfoBases[lB].Name) = LowerCase(dataR.InfoBaseName) then
begin
InfoBase:=InfoBases[lB];
FindInfoBase:=true;
end;
end;
end;
end;

//Заблокируем базу
if FindInfoBase then
begin
InfoBase.ConnectDenied := True;
InfoBase.ScheduledJobsDenied := True;
InfoBase.DeniedFrom := now();
InfoBase.DeniedTo :=now()+300/86400; //Блокировка на 5 минут
InfoBase.DeniedMessage := ‘Блокировка базы’;
InfoBase.PermissionCode := dataR.LockPermissionCode;
connecttoworkprocess.UpdateInfoBase (InfoBase);
end;

//Отключим все соединения с базой
if FindInfoBase then
begin
Connections := connecttoworkprocess.GetInfoBaseConnections(InfoBase);
for lC := 0 to VarArrayHighBound(Connections, 1) do
If Connections[lC].AppId <> ‘SrvrConsole’ Then connecttoworkprocess.Disconnect(Connections[lC]);
//Запускаем архивацию с ожиданием выполнения
ExecAndWait( bin1c,
‘ CONFIG /S’ + dataR.ServerName + » + dataR.InfoBaseName +
‘ /N’ + dataR.InfoBasesAdminName + ‘ /P’ + dataR.InfoBasesAdminPass +
‘ /UC’ + dataR.LockPermissionCode + ‘ /DisableStartupMessages /DumpIB’ +'»‘+ FullPathName+'»‘, SW_SHOWNORMAL);
end;

//разблокируем базу
if FindInfoBase then
begin
InfoBase.ConnectDenied := False;
InfoBase.ScheduledJobsDenied := False;
connecttoworkprocess.UpdateInfoBase (InfoBase);
end;

end;

procedure Zagruzka(paramStrP,paramstr: string);
var dataR:TdataZap;
Ini: Tinifile;
begin
Ini := TiniFile.Create(extractfilepath(ParamStrP)+’cfg.ini’);
dataR.DumpPath := Ini.ReadString(paramstr,’DumpPath’,’-‘);
dataR.ServerName := Ini.ReadString(paramstr,’ServerName’,’-‘);
dataR.InfoBaseName := Ini.ReadString(paramstr,’InfoBaseName’,’-‘);
dataR.ClasterPortNumber := Ini.ReadString(paramstr,’ClasterPortNumber’,’-‘);
dataR.InfoBasesAdminName := Ini.ReadString(paramstr,’InfoBasesAdminName’,’-‘);
dataR.InfoBasesAdminPass := Ini.ReadString(paramstr,’InfoBasesAdminPass’,’-‘);
dataR.ClasterAdminName := Ini.ReadString(paramstr,’ClasterAdminName’,’-‘);
dataR.ClasterAdminPass := Ini.ReadString(paramstr,’ClasterAdminPass’,’-‘);
dataR.LockPermissionCode := Ini.ReadString(paramstr,’LockPermissionCode’,’-‘);
Ini.Free;
if NOT(dataR.ServerName=’-‘) then Zapusk(dataR);
end;

begin
CoInitialize(nil);
if ParamCount>0 then
Zagruzka(ParamStr(0),ParamStr(1))
else
Zagruzka(ParamStr(0),’default’);
CoUnInitialize;
end.

 

7 Comments

  1. ksvd

    Работает. Спасибо. Для себя узнал — что можно искать путь к 1cv8.exe по CLSID.

    Reply
  2. Astafan

    Как во-время, сейчас стоит задача запуска резервного копирования баз в формате DT. Ознакомлюсь с возможностями.

    Reply
  3. zqzq

    Вообще-то сама 1С в документации рекомендует для клиент-сервера копии делать через СУБД. Тогда и выгонять никого не надо и проблем меньше. dt* это для загрузки в файловую и обратно, а не для резервного копирования.

    Reply
  4. TrinitronOTV

    а я просто копирую папку базы в файловом варианте, наверное этого достаточно…

    Reply
  5. dock

    нда… конечно информация полезная — автоматическая выгрузка в .dt

    но практическое применение… под сомнением.

    1) при sql-версии все прекрасно выгружается средствами СУБД.

    2) при файловом варианте достаточно копировать папку (опять таки, есть средства БЕЗ отключения пользователей)…

    Reply
  6. Astafan

    (5) dock,

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

    Reply
  7. ressurect83

    Не стартует, выдало ошибку EOleSysError in module backup.exe at 00014B4D

    Не допустимая строка с указанием класса.

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *