Резервное копирование информационных баз 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 не будет опубликован. Обязательные поля помечены *