BSOne.SFC/eCrmHE/EXE_eCrmHomeEdition/Process/ProcessPrint.pas

1538 lines
44 KiB
Plaintext

{*******************************************************}
{ }
{ ProcessPrint }
{ }
{ Copyright (C) 2025 kku }
{ }
{*******************************************************}
unit ProcessPrint;
interface
uses
Winapi.Windows, System.SysUtils, System.Classes, IdHTTP, Tocsg.Obj, System.Generics.Collections, System.JSON.Types;
type
TxPrtData = (xpdEmp, xpdPrts, xpdBill, xpdMkcd, xpdLump);
TxPrtDatas = set of TxPrtData;
// PxBillEnt = ^TxBillEnt;
// TxBillEnt = packed record
// accessUser,
// billCodeName: UTF8String;
// end;
TxBillData = class(TTgObject)
private
DcData_: TDictionary<UTF8String,UTF8String>;
// DataList_: TList<PxBillEnt>;
// StrList_: TStringList;
// procedure OnEntNoti(Sender: TObject; const Item: PxBillEnt; Action: TCollectionNotification);
public
Constructor Create;
Destructor Destroy; override;
function LoadFromFile(const sPath: String): Boolean;
procedure UpdateData(const sJsonData: String);
procedure SaveToFile(const sPath: String);
end;
TxEmpData = class(TTgObject)
private
DcData_: TDictionary<UTF8String,UTF8String>;
public
Constructor Create;
Destructor Destroy; override;
function LoadFromFile(const sPath: String): Boolean;
procedure UpdateData(const sJsonData: String);
procedure SaveToFile(const sPath: String);
end;
TxPrtInfoData = class(TTgObject)
private
DcData_: TDictionary<UTF8String,UTF8String>;
public
Constructor Create;
Destructor Destroy; override;
function LoadFromFile(const sPath: String): Boolean;
procedure UpdateData(const sJsonData: String);
procedure SaveToFile(const sPath: String);
end;
// mk-codes, lumpsum-fixed-codes 처리
TxStrData = class(TTgObject)
private
sName_: String;
DataList_: TStringList;
public
Constructor Create(sName: String);
Destructor Destroy; override;
function LoadFromFile(const sPath: String): Boolean;
procedure UpdateData(const sJsonData: String);
procedure SaveToFile(const sPath: String);
end;
procedure ProcessCheck_xPrintData(aHTTP: TIdHTTP);
function ProcessRcv_xPrintData(aHTTP: TIdHTTP; aPrtDatas: TxPrtDatas; bForceDl: Boolean = false): Boolean;
procedure CheckAndUpdate_xPrint;
implementation
uses
Tocsg.Safe, ManagerService, Tocsg.Exception, Tocsg.Process,
System.Zip, Tocsg.Shell, GlobalDefine, ProcessUninstall, Tocsg.Files,
Tocsg.Trace, Tocsg.Path, Tocsg.Strings, superobject, ManagerModel, Condition,
System.IniFiles, Tocsg.Json, System.JSON, System.JSON.Readers, Tocsg.DateTime,
Tocsg.DRM.Encrypt;
const
PASS_xDRM_HEAD: AnsiString = '#df12mf8(zfq@';
PASS_xDRM_DATA: AnsiString = 'Z!8r]Xc3$g>+Tp5L%u';
SIG_xDRM: AnsiString = 'X-PRINT';
function Is_xEncrypt(const plainPath: string): Boolean;
var
dec: TTgDrmDec;
begin
try
Result := CheckSign(plainPath, SIG_xDRM);
except
on E: Exception do
begin
Result := false;
ETgException.TraceException(E, 'Fail .. Is_xEncrypt()');
end;
end;
end;
function Do_xDecrypt(const encPath, decPath: string): Boolean;
var
dec: TTgDrmDec;
begin
Result := false;
try
if not FileExists(encPath) then
exit;
if not DirectoryExists(ExtractFilePath(decPath)) then
exit;
Guard(dec, TTgDrmDec.Create(encPath));
if not dec.CheckSig(SIG_xDRM) then
exit;
if not dec.ExtrHead(PASS_xDRM_HEAD) then
exit;
Result := dec.DecryptToFile(PASS_xDRM_DATA, decPath);
except
on E: Exception do
ETgException.TraceException(E, 'Fail .. Do_xDecrypt()');
// WriteLn(encPath + '오류 발생: ', E.Message);
end;
end;
function Do_xEncrypt(const plainPath, encPath: string): Boolean;
var
enc: TTgDrmEnc;
begin
Result := false;
if Is_xEncrypt(plainPath) then
exit;
try
Guard(enc, TTgDrmEnc.Create(encPath));
enc.SetHaed(PASS_xDRM_HEAD, SIG_xDRM, '', '', '', '', 0);
Result := enc.EncryptFromFile(PASS_xDRM_DATA, plainPath);
except
on E: Exception do
ETgException.TraceException(E, 'Fail .. Do_xEncrypt()');
end;
end;
{ TxBillData }
Constructor TxBillData.Create;
begin
Inherited Create;
DcData_ := TDictionary<UTF8String,UTF8String>.Create;
// DcData_.OnValueNotify := OnEntNoti;
// DataList_ := TList<PxBillEnt>.Create;
// DataList_.OnNotify := OnEntNoti;
// StrList_ := TStringList.Create;
end;
Destructor TxBillData.Destroy;
begin
FreeAndNil(DcData_);
// FreeAndNil(StrList_);
// FreeAndNil(DataList_);
Inherited;
end;
//procedure TxBillData.OnEntNoti(Sender: TObject; const Item: PxBillEnt; Action: TCollectionNotification);
//begin
// if Action = cnRemoved then
// Dispose(Item);
//end;
function TxBillData.LoadFromFile(const sPath: String): Boolean;
var
// O: ISuperObject;
i: Integer;
sData, sDecPath: String;
// pEnt: PxBillEnt;
// Ent: TxBillEnt;
// JSONObj: TJSONObject;
// JSONArray: TJSONArray;
// item: TJSONValue;
ms: TMemoryStream;
sr: TStreamReader;
jr: TJsonTextReader;
bArray, bObject: Boolean;
sProp, s1, s2: String;
begin
Result := false;
try
sDecPath := '';
DcData_.Clear;
// StrList_.Clear;
// DataList_.Clear;
// 속도 및 메모리 최적화를 위해 아래처럼 처리 25_1023 16:10:36 kku
Guard(ms, TMemoryStream.Create);
if Is_xEncrypt(sPath) then
begin
sDecPath := GetRunExePathDir + 'Task\';
if ForceDirectories(sDecPath) then
begin
sDecPath := sDecPath + IntToStr(GetTickCount) + '_Bil.dat';
if not Do_xDecrypt(sPath, sDecPath) then
begin
_Trace('Fail .. Do_xDecrypt() .. Path=%s', [sDecPath]);
exit;
end;
ms.LoadFromFile(sDecPath);
end else begin
_Trace('Fail .. CreateDir() .. Path=%s', [sDecPath]);
exit;
end;
end else
ms.LoadFromFile(sPath);
try
Guard(sr, TStreamReader.Create(ms, TEncoding.UTF8, true, 1 shl 16));
Guard(jr, TJsonTextReader.Create(sr));
bArray := false;
bObject := false;
// pEnt := nil;
while jr.Read do
begin
case jr.TokenType of
TJsonToken.StartArray: bArray := true;
TJsonToken.EndArray: bArray := false;
TJsonToken.StartObject:
begin
// 객체 시작: 필요한 필드 초기화
bObject := true;
// New(pEnt);
// ZeroMemory(pEnt, SizeOf(TxBillEnt));
// ZeroMemory(@Ent, SizeOf(TxBillEnt));
end;
TJsonToken.PropertyName:
sProp := jr.Value.AsString; // Delphi 11+에서 사용 가능(버전에 따라 ToString 사용)
TJsonToken.String:
if bObject then
begin
// if pEnt <> nil then
begin
if SameText(sProp, 'accessUser') then
s1 := jr.Value.AsString// ToString
else if SameText(sProp, 'billCodeName') then
s2 := jr.Value.AsString; //ToString;
end;
end;
TJsonToken.Integer:
if bObject then
begin
// if SameText(sProp, 'age') then
// nVal := StrToIntDef(jr.Value.ToString, -1);
end;
TJsonToken.EndObject:
begin
// ★ 여기서 한 레코드 처리(저장/집계/필터링 등) 후 버린다
// 예: DB Insert, 파일 Append, 통계 누적 등
// DoProcess(sVal, nVal);
bObject := false;
if s2 <> '' then
DcData_.Add(UpperCase(s2), s1 + '|' + s2);
// if pEnt <> nil then
// begin
// try
// if pEnt.accessUser <> '' then
//// DataList_.Add(pEnt)
// DcData_.Add(UpperCase(pEnt.billCodeName), pEnt)
// else
// Dispose(pEnt);
// except
// _Trace('Fail .. TxBillData.LoadFromFile() .. 중복 데이터? billCodeName=%s', [pEnt.billCodeName], 9);
// Dispose(pEnt);
// end;
// pEnt := nil;
// end;
end;
end;
end;
Result := true;
finally
if sDecPath <> '' then
DeleteFile(sDecPath);
end;
// sData := LoadStrFromFile(sPath, TEncoding.UTF8);
// JSONArray := TJSONObject.ParseJSONValue(sData) as TJSONArray;
// if JSONArray = nil then
// exit;
//
// try
// for i := 0 to JSONArray.Count - 1 do
// begin
// item := JSONArray.Items[i];
//
// New(pEnt);
// pEnt.accessUser := item.GetValue<String>('accessUser');
// pEnt.billCodeName := item.GetValue<String>('billCodeName');
// try
// if pEnt.accessUser <> '' then
// DcData_.Add(pEnt.billCodeName.ToUpper, pEnt)
// else
// Dispose(pEnt);
// except
// _Trace('Fail .. TxBillData.LoadFromFile() .. 중복 데이터? billCodeName=%s', [pEnt.billCodeName], 9);
// Dispose(pEnt);
// end;
// end;
// finally
// JSONArray.Free;
// end;
// if not LoadJsonObjFromFile(O, sPath) then
// exit;
//
// if (O.DataType <> stArray) or (O.AsArray.Length = 0) then
// exit;
//
// for i := 0 to O.AsArray.Length - 1 do
// begin
// New(pEnt);
// pEnt.accessUser := O.AsArray.O[i].S['accessUser'];
// pEnt.billCodeName := O.AsArray.O[i].S['billCodeName'];
// try
// if pEnt.accessUser <> '' then
// DcData_.Add(pEnt.billCodeName.ToUpper, pEnt)
// else
// Dispose(pEnt);
// except
// _Trace('Fail .. TxBillData.LoadFromFile() .. 중복 데이터? billCodeName=%s', [pEnt.billCodeName], 9);
// Dispose(pEnt);
// end;
// end;
except
on E: Exception do
ETgException.TraceException(Self, E, 'Fail .. LoadFromFile()');
end;
end;
procedure TxBillData.UpdateData(const sJsonData: String);
var
O: ISuperObject;
i: Integer;
sKey: String;
// pEnt: PxBillEnt;
begin
try
O := SO(sJsonData);
if O = nil then
exit;
if (O.O['created'] <> nil) and (O.O['created'].DataType = stArray) then
begin
for i := 0 to O.A['created'].Length - 1 do
begin
sKey := O.A['created'].O[i].S['billCodeName'].ToUpper;
if not DcData_.ContainsKey(sKey) then
begin
// New(pEnt);
// pEnt.billCodeName := O.A['created'].O[i].S['billCodeName'];
// pEnt.accessUser := O.A['created'].O[i].S['accessUser'];
// DcData_.Add(sKey, pEnt);
DcData_.Add(sKey, O.A['created'].O[i].S['accessUser'] + '|' + O.A['created'].O[i].S['billCodeName']);
_Trace('billcodes.UpdateData() .. created, billCodeName=%s, accessUser=%s', [O.A['created'].O[i].S['billCodeName'], O.A['created'].O[i].S['accessUser']], 5);
end else begin
// pEnt := DcData_[sKey];
// pEnt.accessUser := O.A['created'].O[i].S['accessUser'];
DcData_[sKey] := O.A['created'].O[i].S['accessUser'] + '|' + O.A['created'].O[i].S['billCodeName'];
_Trace('billcodes.UpdateData() .. created(mod), billCodeName=%s, accessUser=%s', [O.A['created'].O[i].S['billCodeName'], O.A['created'].O[i].S['accessUser']], 5);
end;
end;
end;
if (O.O['updated'] <> nil) and (O.O['updated'].DataType = stArray) then
begin
for i := 0 to O.A['updated'].Length - 1 do
begin
sKey := O.A['updated'].O[i].S['billCodeName'].ToUpper;
if not DcData_.ContainsKey(sKey) then
begin
// New(pEnt);
// pEnt.billCodeName := O.A['updated'].O[i].S['billCodeName'];
// pEnt.accessUser := O.A['updated'].O[i].S['accessUser'];
// DcData_.Add(sKey, pEnt);
DcData_.Add(sKey, O.A['updated'].O[i].S['accessUser'] + '|' + O.A['updated'].O[i].S['billCodeName']);
_Trace('billcodes.UpdateData() .. updated(new), billCodeName=%s, accessUser=%s', [O.A['updated'].O[i].S['billCodeName'], O.A['updated'].O[i].S['accessUser']], 5);
end else begin
// pEnt := DcData_[sKey];
// pEnt.accessUser := O.A['updated'].O[i].S['accessUser'];
DcData_[sKey] := O.A['updated'].O[i].S['accessUser'] + '|' + O.A['updated'].O[i].S['billCodeName'];
_Trace('billcodes.UpdateData() .. updated, billCodeName=%s, accessUser=%s', [O.A['updated'].O[i].S['billCodeName'], O.A['updated'].O[i].S['accessUser']], 5);
end;
end;
end;
if (O.O['deleted'] <> nil) and (O.O['deleted'].DataType = stArray) then
begin
for i := 0 to O.A['deleted'].Length - 1 do
begin
sKey := O.A['deleted'].O[i].S['billCodeName'].ToUpper;
if DcData_.ContainsKey(sKey) then
begin
DcData_.Remove(O.A['deleted'].O[i].S['billCodeName'].ToUpper);
_Trace('billcodes.UpdateData() .. deleted, billCodeName=%s, accessUser=%s', [O.A['deleted'].O[i].S['billCodeName'], O.A['deleted'].O[i].S['accessUser']], 5);
end;
end;
end;
except
on E: Exception do
ETgException.TraceException(Self, E, 'Fail .. UpdateData()');
end;
end;
procedure TxBillData.SaveToFile(const sPath: String);
var
// OA, O: ISuperObject;
enum: TEnumerator<UTF8String>;
sData, sEnt, sU, sB: String;
n: Integer;
begin
try
sData := '';
// OA := TSuperObject.Create(stArray);
// Guard(enum, StrList_.GetEnumerator);
Guard(enum, DcData_.Values.GetEnumerator);
// Guard(enum, DataList_.GetEnumerator);
while enum.MoveNext do
begin
// SumString(sData, TTgJson.ValueToJsonAsString<TxBillEnt>(enum.Current^), ',');
// sEnt := JsonEscapeString(enum.Current);
sEnt := enum.Current;
n := Pos('|', sEnt);
if n > 0 then
begin
sU := Copy(sEnt, 1, n - 1);
Delete(sEnt, 1, n);
sB := sEnt;
SumString(sData, Format('{"accessUser":"%s","billCodeName":"%s"}', [sU, sB]), ',');
end;
// O := TTgJson.ValueToJsonObject<TxBillEnt>(enum.Current^);
// OA.AsArray.Add(O);
end;
SaveStrToFile(sPath, '[' + sData + ']', TEncoding.UTF8);
// SaveJsonObjToFile(OA, sPath);
except
on E: Exception do
ETgException.TraceException(Self, E, 'Fail .. SaveToFile()');
end;
end;
{ TxEmpData }
Constructor TxEmpData.Create;
begin
Inherited Create;
DcData_ := TDictionary<UTF8String,UTF8String>.Create;
end;
Destructor TxEmpData.Destroy;
begin
FreeAndNil(DcData_);
Inherited;
end;
function TxEmpData.LoadFromFile(const sPath: String): Boolean;
var
O: ISuperObject;
i: Integer;
sKey: String;
begin
Result := false;
try
if Is_xEncrypt(sPath) then
begin
var sDecPath: String := GetRunExePathDir + 'Task\';
if ForceDirectories(sDecPath) then
begin
sDecPath := sDecPath + IntToStr(GetTickCount) + '_Emp.dat';
try
if not Do_xDecrypt(sPath, sDecPath) then
begin
_Trace('Fail .. Do_xDecrypt() .. Path=%s', [sDecPath]);
exit;
end;
if not LoadJsonObjFromFile(O, sDecPath) then
begin
_Trace('Fail .. TxEmpData.LoadJsonObjFromFile()');
exit;
end;
finally
if FileExists(sDecPath) then
DeleteFile(sDecPath);
end;
end else begin
_Trace('Fail .. CreateDir() .. Path=%s', [sDecPath]);
exit;
end;
end else
if not LoadJsonObjFromFile(O, sPath) then
begin
_Trace('Fail .. TxEmpData.LoadJsonObjFromFile()');
exit;
end;
if (O.DataType <> stArray) or (O.AsArray.Length = 0) then
begin
_Trace('Fail .. TxEmpData.InvalidData()');
exit;
end;
for i := 0 to O.AsArray.Length - 1 do
begin
sKey := O.AsArray.O[i].S['empId'].ToUpper;
try
if sKey <> '' then
DcData_.Add(sKey, O.AsArray.O[i].AsJSon);
except
_Trace('Fail .. TxEmpData.LoadFromFile() .. 중복 데이터? Key=%s', [sKey], 9);
end;
end;
Result := true;
except
on E: Exception do
ETgException.TraceException(Self, E, 'Fail .. LoadFromFile()');
end;
end;
procedure TxEmpData.UpdateData(const sJsonData: String);
var
O: ISuperObject;
i: Integer;
sKey: String;
begin
try
O := SO(sJsonData);
if O = nil then
exit;
if (O.O['created'] <> nil) and (O.O['created'].DataType = stArray) then
begin
for i := 0 to O.A['created'].Length - 1 do
begin
sKey := O.A['created'].O[i].S['empId'].ToUpper;
if not DcData_.ContainsKey(sKey) then
begin
DcData_.Add(sKey, O.A['created'].O[i].AsJSon);
_Trace('emps.UpdateData() .. created, empId=%s', [O.A['created'].O[i].S['empId']], 5);
end else begin
DcData_[sKey] := O.A['created'].O[i].AsJSon;
_Trace('emps.UpdateData() .. created(mod), empId=%s', [O.A['created'].O[i].S['empId']], 5);
end;
end;
end;
if (O.O['updated'] <> nil) and (O.O['updated'].DataType = stArray) then
begin
for i := 0 to O.A['updated'].Length - 1 do
begin
sKey := O.A['updated'].O[i].S['empId'].ToUpper;
if not DcData_.ContainsKey(sKey) then
begin
DcData_.Add(sKey, O.A['updated'].O[i].AsJSon);
_Trace('emps.UpdateData() .. updated(new), empId=%s', [O.A['updated'].O[i].S['empId']], 5);
end else begin
DcData_[sKey] := O.A['updated'].O[i].AsJSon;
_Trace('emps.UpdateData() .. updated, empId=%s', [O.A['updated'].O[i].S['empId']], 5);
end;
end;
end;
if (O.O['deleted'] <> nil) and (O.O['deleted'].DataType = stArray) then
begin
for i := 0 to O.A['deleted'].Length - 1 do
begin
sKey := O.A['deleted'].O[i].S['empId'].ToUpper;
if DcData_.ContainsKey(sKey) then
begin
DcData_.Remove(O.A['deleted'].O[i].S['empId'].ToUpper);
_Trace('emps.UpdateData() .. deleted, empId=%s', [O.A['deleted'].O[i].S['empId']], 5);
end;
end;
end;
except
on E: Exception do
ETgException.TraceException(Self, E, 'Fail .. UpdateData()');
end;
end;
procedure TxEmpData.SaveToFile(const sPath: String);
var
enum: TEnumerator<UTF8String>;
sData, sEnt: String;
begin
try
sData := '';
Guard(enum, DcData_.Values.GetEnumerator);
while enum.MoveNext do
begin
sEnt := enum.Current;
if sEnt <> '' then
SumString(sData, sEnt, ',');
end;
SaveStrToFile(sPath, '[' + sData + ']', TEncoding.UTF8);
except
on E: Exception do
ETgException.TraceException(Self, E, 'Fail .. SaveToFile()');
end;
end;
{ TxPrtInfoData }
Constructor TxPrtInfoData.Create;
begin
Inherited Create;
DcData_ := TDictionary<UTF8String,UTF8String>.Create;
end;
Destructor TxPrtInfoData.Destroy;
begin
FreeAndNil(DcData_);
Inherited;
end;
function TxPrtInfoData.LoadFromFile(const sPath: String): Boolean;
var
O: ISuperObject;
i: Integer;
sKey: String;
begin
Result := false;
try
if Is_xEncrypt(sPath) then
begin
var sDecPath: String := GetRunExePathDir + 'Task\';
if ForceDirectories(sDecPath) then
begin
sDecPath := sDecPath + IntToStr(GetTickCount) + '_Prt.dat';
try
if not Do_xDecrypt(sPath, sDecPath) then
begin
_Trace('Fail .. Do_xDecrypt() .. Path=%s', [sDecPath]);
exit;
end;
if not LoadJsonObjFromFile(O, sDecPath) then
begin
_Trace('Fail .. TxPrtInfoData.LoadJsonObjFromFile()');
exit;
end;
finally
if FileExists(sDecPath) then
DeleteFile(sDecPath);
end;
end else begin
_Trace('Fail .. CreateDir() .. Path=%s', [sDecPath]);
exit;
end;
end else
if not LoadJsonObjFromFile(O, sPath) then
begin
_Trace('Fail .. TxPrtInfoData.LoadJsonObjFromFile()');
exit;
end;
if (O.DataType <> stArray) or (O.AsArray.Length = 0) then
begin
_Trace('Fail .. TxPrtInfoData.InvalidData()');
exit;
end;
for i := 0 to O.AsArray.Length - 1 do
begin
sKey := O.AsArray.O[i].S['p_code'].ToUpper;
try
if sKey <> '' then
DcData_.Add(sKey, O.AsArray.O[i].AsJSon);
except
_Trace('Fail .. xPrtInfoData.LoadFromFile() .. 중복 데이터? Key=%s', [sKey], 9);
end;
end;
Result := true;
except
on E: Exception do
ETgException.TraceException(Self, E, 'Fail .. LoadFromFile()');
end;
end;
procedure TxPrtInfoData.UpdateData(const sJsonData: String);
var
O: ISuperObject;
i: Integer;
sKey: String;
begin
try
O := SO(sJsonData);
if O = nil then
exit;
if (O.O['created'] <> nil) and (O.O['created'].DataType = stArray) then
begin
for i := 0 to O.A['created'].Length - 1 do
begin
sKey := O.A['created'].O[i].S['p_code'].ToUpper;
if not DcData_.ContainsKey(sKey) then
begin
DcData_.Add(sKey, O.A['created'].O[i].AsJSon);
_Trace('xprint-printers.UpdateData() .. created, p_code=%s', [O.A['created'].O[i].S['p_code']], 5);
end else begin
DcData_[sKey] := O.A['created'].O[i].AsJSon;
_Trace('xprint-printers.UpdateData() .. created(mod), p_code=%s', [O.A['created'].O[i].S['p_code']], 5);
end;
end;
end;
if (O.O['updated'] <> nil) and (O.O['updated'].DataType = stArray) then
begin
for i := 0 to O.A['updated'].Length - 1 do
begin
sKey := O.A['updated'].O[i].S['p_code'].ToUpper;
if not DcData_.ContainsKey(sKey) then
begin
DcData_.Add(sKey, O.A['updated'].O[i].AsJSon);
_Trace('xprint-printers.UpdateData() .. updated(new), p_code=%s', [O.A['updated'].O[i].S['p_code']], 5);
end else begin
DcData_[sKey] := O.A['updated'].O[i].AsJSon;
_Trace('xprint-printers.UpdateData() .. updated, p_code=%s', [O.A['updated'].O[i].S['p_code']], 5);
end;
end;
end;
if (O.O['deleted'] <> nil) and (O.O['deleted'].DataType = stArray) then
begin
for i := 0 to O.A['deleted'].Length - 1 do
begin
sKey := O.A['deleted'].O[i].S['p_code'].ToUpper;
if DcData_.ContainsKey(sKey) then
begin
DcData_.Remove(O.A['deleted'].O[i].S['p_code'].ToUpper);
_Trace('xprint-printers.UpdateData() .. deleted, p_code=%s', [O.A['deleted'].O[i].S['p_code']], 5);
end;
end;
end;
except
on E: Exception do
ETgException.TraceException(Self, E, 'Fail .. UpdateData()');
end;
end;
procedure TxPrtInfoData.SaveToFile(const sPath: String);
var
enum: TEnumerator<UTF8String>;
sData, sEnt: String;
begin
try
sData := '';
Guard(enum, DcData_.Values.GetEnumerator);
while enum.MoveNext do
begin
sEnt := enum.Current;
if sEnt <> '' then
SumString(sData, sEnt, ',');
end;
SaveStrToFile(sPath, '[' + sData + ']', TEncoding.UTF8);
except
on E: Exception do
ETgException.TraceException(Self, E, 'Fail .. SaveToFile()');
end;
end;
{ TxStrData }
Constructor TxStrData.Create(sName: String);
begin
Inherited Create;
sName_ := sName;
DataList_ := TStringList.Create;
DataList_.CaseSensitive := false;
end;
Destructor TxStrData.Destroy;
begin
FreeAndNil(DataList_);
Inherited;
end;
function TxStrData.LoadFromFile(const sPath: String): Boolean;
var
O: ISuperObject;
i: Integer;
sKey: String;
begin
try
if Is_xEncrypt(sPath) then
begin
var sDecPath: String := GetRunExePathDir + 'Task\';
if ForceDirectories(sDecPath) then
begin
sDecPath := sDecPath + IntToStr(GetTickCount) + Format('_%s.dat', [sName_]);
try
if not Do_xDecrypt(sPath, sDecPath) then
begin
_Trace('Fail .. Do_xDecrypt() .. %s, Path=%s', [sName_, sDecPath]);
exit;
end;
if not LoadJsonObjFromFile(O, sDecPath) then
begin
_Trace('Fail .. TxStrData.LoadJsonObjFromFile()-' + sName_);
exit;
end;
finally
if FileExists(sDecPath) then
DeleteFile(sDecPath);
end;
end else begin
_Trace('Fail .. CreateDir() .. %s, Path=%s', [sName_, sDecPath]);
exit;
end;
end else
if not LoadJsonObjFromFile(O, sPath) then
begin
_Trace('Fail .. TxStrData.LoadJsonObjFromFile()-' + sName_);
exit;
end;
if (O.DataType <> stArray) or (O.AsArray.Length = 0) then
exit;
for i := 0 to O.AsArray.Length - 1 do
DataList_.Add(O.AsArray.S[i]);
except
on E: Exception do
ETgException.TraceException(Self, E, 'Fail .. LoadFromFile()');
end;
end;
procedure TxStrData.UpdateData(const sJsonData: String);
var
O: ISuperObject;
i, n: Integer;
sEnt: String;
begin
try
O := SO(sJsonData);
if O = nil then
exit;
if (O.O['created'] <> nil) and (O.O['created'].DataType = stArray) then
begin
for i := 0 to O.A['created'].Length - 1 do
begin
sEnt := O.A['created'].S[i];
if DataList_.IndexOf(sEnt) = -1 then
begin
DataList_.Add(sEnt);
_Trace('%s.UpdateData() .. created, Ent=%s', [sName_, sEnt], 5);
end;
end;
end;
if (O.O['updated'] <> nil) and (O.O['updated'].DataType = stArray) then
begin
// 수정은 없을거 같지만... created와 똑같이 처리하는걸로 해준다
for i := 0 to O.A['updated'].Length - 1 do
begin
sEnt := O.A['updated'].S[i];
if DataList_.IndexOf(sEnt) = -1 then
begin
DataList_.Add(sEnt);
_Trace('%s.UpdateData() .. updated, Ent=%s', [sName_, sEnt], 5);
end;
end;
end;
if (O.O['deleted'] <> nil) and (O.O['deleted'].DataType = stArray) then
begin
for i := 0 to O.A['deleted'].Length - 1 do
begin
sEnt := O.A['deleted'].S[i];
n := DataList_.IndexOf(sEnt);
if n <> -1 then
begin
DataList_.Delete(n);
_Trace('%s.UpdateData() .. deleted, Ent=%s', [sName_, sEnt], 5);
end;
end;
end;
except
on E: Exception do
ETgException.TraceException(Self, E, 'Fail .. UpdateData()');
end;
end;
procedure TxStrData.SaveToFile(const sPath: String);
var
OA: ISuperObject;
i: Integer;
begin
try
OA := TSuperObject.Create(stArray);
for i := 0 to DataList_.Count - 1 do
OA.AsArray.Add(DataList_[i]);
SaveJsonObjToFile(OA, sPath);
except
on E: Exception do
ETgException.TraceException(Self, E, 'Fail .. SaveToFile()');
end;
end;
function GetTimestampFromJsonStr(sJsonStr: String): String;
var
O: ISuperObject;
begin
Result := '';
try
O := SO(sJsonStr);
Result := O.S['timestamp'];
except
on E: Exception do
ETgException.TraceException(E, 'Fail .. GetTimestampFromJsonStr(), Data=' + sJsonStr);
end;
end;
procedure ProcessCheck_xPrintData(aHTTP: TIdHTTP);
var
ss: TStringStream;
ReqPrtDatas: TxPrtDatas;
sUpDt: String;
begin
try
if CUSTOMER_TYPE <> CUSTOMER_KIMCHANG then
exit;
// 24시간에 한번만 업데이트 되도록 임시 보완 25_0924 14:55:13 kku
// if (gMgSvc.dtOneDay_ <> 0) and (HoursBetween(gMgSvc.dtOneDay_, Now) < 24) then
// exit;
ReqPrtDatas := [];
sUpDt := GetTimestampFromJsonStr(aHTTP.Get(gMgSvc.DestIPort + 'aapi/emps/latest-timestamp'));
if (sUpDt <> '') and (gMgSvc.EmpsUpDt <> sUpDt) then
Include(ReqPrtDatas, xpdEmp);
sUpDt := GetTimestampFromJsonStr(aHTTP.Get(gMgSvc.DestIPort + 'aapi/billcodes/latest-timestamp'));
if (sUpDt <> '') and (gMgSvc.BillUpDt <> sUpDt) then
Include(ReqPrtDatas, xpdBill);
sUpDt := GetTimestampFromJsonStr(aHTTP.Get(gMgSvc.DestIPort + 'aapi/xprint-printers/latest-timestamp'));
if (sUpDt <> '') and (gMgSvc.PrtsUpDt <> sUpDt) then
Include(ReqPrtDatas, xpdPrts);
sUpDt := GetTimestampFromJsonStr(aHTTP.Get(gMgSvc.DestIPort + 'aapi/mk-codes/latest-timestamp'));
if (sUpDt <> '') and (gMgSvc.MkcdUpDt <> sUpDt) then
Include(ReqPrtDatas, xpdMkcd);
sUpDt := GetTimestampFromJsonStr(aHTTP.Get(gMgSvc.DestIPort + 'aapi/lumpsum-fixed-codes/latest-timestamp'));
if (sUpDt <> '') and (gMgSvc.LumpUpDt <> sUpDt) then
Include(ReqPrtDatas, xpdLump);
if ReqPrtDatas <> [] then
ProcessRcv_xPrintData(aHTTP, ReqPrtDatas);
except
on E: Exception do
ETgException.TraceException(E, 'Fail .. ProcessCheck_xPrintData()');
end;
end;
function ProcessRcv_xPrintData(aHTTP: TIdHTTP; aPrtDatas: TxPrtDatas; bForceDl: Boolean = false): Boolean;
var
sXPrtDir, sUpDt, sToDt, sPath: String;
ss: TStringStream;
bUpdate, bEncData: Boolean;
procedure EncFile(const sPath: String);
var
sEncPath: String;
begin
if not bEncData then
exit;
if not FileExists(sPath) then
exit;
sEncPath := GetRunExePathDir + 'Task\';
if ForceDirectories(sEncPath) then
begin
sEncPath := sEncPath + '$xEnTmp.dat';
DeleteFile(sEncPath);
if Do_xEncrypt(sPath, sEncPath) then
begin
DeleteFile(sPath);
MoveFile_wait(sEncPath, sPath, 3);
end;
end;
end;
begin
Result := false;
try
TTgTrace.T('ProcessRcv_xPrintData() ..', 1);
sXPrtDir := GetCommonDataDir + 'bsoneprint\';
if not FileExists(sXPrtDir + EXE_xPrintSvc) then
begin
TTgTrace.T('Fail .. ProcessRcv_xPrintData() .. xPrint Client를 찾을 수 없음.', 1);
exit;
end;
sXPrtDir := sXPrtDir + 'data\';
if not ForceDirectories(sXPrtDir) then
begin
TTgTrace.T('Fail .. ProcessRcv_xPrintData() .. data 폴더 생성 실패, Path=%s', [sXPrtDir], 1);
exit;
end;
bEncData := true;
try
sPath := GetProgramFilesDir + DIR_TG + INI_FORCEHE;
if FileExists(sPath) then
begin
var ini: TIniFile;
Guard(ini, TIniFile.Create(sPath));
bEncData := not ini.ReadBool('Force', 'xPrintDataNoEnc', false);
end;
except
//
end;
bUpdate := false;
Guard(ss, TStringStream.Create('', TEncoding.UTF8));
if xpdEmp in aPrtDatas then
begin
sPath := sXPrtDir + 'xEmp.dat';
sUpDt := GetTimestampFromJsonStr(aHTTP.Get(gMgSvc.DestIPort + 'aapi/emps/latest-timestamp'));
if not bForceDl and FileExists(sPath) and (sUpDt <> '') and (gMgSvc.EmpsUpDt <> '') then
begin
sToDt := '2099-12-31T23:59:59Z';
aHTTP.Get(gMgSvc.DestIPort + Format('aapi/emps?include=attribute&from=%s&to=%s&include=changeType&groupBy=changeType', [gMgSvc.EmpsUpDt, sToDt]), ss);
end else
aHTTP.Get(gMgSvc.DestIPort + 'aapi/emps?include=attribute&isRetired=false&isDeleted=false', ss);
// aHTTP.Get(gMgSvc.DestIPort + 'aapi/emps?include=attribute', ss);
if ss.Size > 0 then
begin
if not bForceDl and FileExists(sPath) then
begin
var xEmpData: TxEmpData;
Guard(xEmpData, TxEmpData.Create);
xEmpData.LoadFromFile(sPath);
xEmpData.UpdateData(ss.DataString);
xEmpData.SaveToFile(sPath);
TTgTrace.T('emps 데이터 업데이트 완료', 1);
end else begin
if bForceDl and FileExists(sPath) then
DeleteFile(sPath);
ss.SaveToFile(sPath);
TTgTrace.T('emps 데이터 전체 다운로드 완료', 1);
end;
EncFile(sPath);
end;
if sUpDt <> '' then
begin
gMgSvc.EmpsUpDt := sUpDt;
bUpdate := true;
end;
end;
if xpdBill in aPrtDatas then
begin
sPath := sXPrtDir + 'xBil.dat';
ss.Clear;
sUpDt := GetTimestampFromJsonStr(aHTTP.Get(gMgSvc.DestIPort + 'aapi/billcodes/latest-timestamp'));
if not bForceDl and FileExists(sPath) and (sUpDt <> '') and (gMgSvc.BillUpDt <> '') then
begin
sToDt := '2099-12-31T23:59:59Z';
aHTTP.Get(gMgSvc.DestIPort + Format('aapi/billcodes?from=%s&to=%s&include=changeType&groupBy=changeType', [gMgSvc.BillUpDt, sToDt]), ss);
end else
aHTTP.Get(gMgSvc.DestIPort + 'aapi/billcodes?isDeleted=false', ss);
// aHTTP.Get(gMgSvc.DestIPort + 'aapi/billcodes', ss);
if ss.Size > 0 then
begin
if not bForceDl and FileExists(sPath) then
begin
var xBillData: TxBillData;
Guard(xBillData, TxBillData.Create);
xBillData.LoadFromFile(sPath);
xBillData.UpdateData(ss.DataString);
xBillData.SaveToFile(sPath);
TTgTrace.T('billcodes 데이터 업데이트 완료', 1);
end else begin
if bForceDl and FileExists(sPath) then
DeleteFile(sPath);
ss.SaveToFile(sPath);
TTgTrace.T('billcodes 데이터 전체 다운로드 완료', 1);
end;
EncFile(sPath);
end;
if sUpDt <> '' then
begin
gMgSvc.BillUpDt := sUpDt;
bUpdate := true;
end;
end;
if xpdPrts in aPrtDatas then
begin
sPath := sXPrtDir + 'xPti.dat';
ss.Clear;
sUpDt := GetTimestampFromJsonStr(aHTTP.Get(gMgSvc.DestIPort + 'aapi/xprint-printers/latest-timestamp'));
if not bForceDl and FileExists(sPath) and (sUpDt <> '') and (gMgSvc.PrtsUpDt <> '') then
begin
sToDt := '2099-12-31T23:59:59Z';
aHTTP.Get(gMgSvc.DestIPort + Format('aapi/xprint-printers?from=%s&to=%s&include=changeType&groupBy=changeType', [gMgSvc.PrtsUpDt, sToDt]), ss);
end else
aHTTP.Get(gMgSvc.DestIPort + 'aapi/xprint-printers?isDeleted=false', ss);
// aHTTP.Get(gMgSvc.DestIPort + 'aapi/xprint-printers', ss);
if ss.Size > 0 then
begin
if not bForceDl and FileExists(sPath) then
begin
var xPrtInfoData: TxPrtInfoData;
Guard(xPrtInfoData, TxPrtInfoData.Create);
xPrtInfoData.LoadFromFile(sPath);
xPrtInfoData.UpdateData(ss.DataString);
xPrtInfoData.SaveToFile(sPath);
TTgTrace.T('xprint-printers 데이터 업데이트 완료', 1);
end else begin
if bForceDl and FileExists(sPath) then
DeleteFile(sPath);
ss.SaveToFile(sPath);
TTgTrace.T('xprint-printers 데이터 전체 다운로드 완료', 1);
end;
EncFile(sPath);
end;
if sUpDt <> '' then
begin
gMgSvc.PrtsUpDt := sUpDt;
bUpdate := true;
end;
end;
if xpdMkcd in aPrtDatas then
begin
sPath := sXPrtDir + 'xMkc.dat';
ss.Clear;
sUpDt := GetTimestampFromJsonStr(aHTTP.Get(gMgSvc.DestIPort + 'aapi/mk-codes/latest-timestamp'));
if not bForceDl and FileExists(sPath) and (sUpDt <> '') and (gMgSvc.MkcdUpDt <> '') then
begin
sToDt := '2099-12-31T23:59:59Z';
aHTTP.Get(gMgSvc.DestIPort + Format('aapi/mk-codes?from=%s&to=%s&include=changeType&groupBy=changeType', [gMgSvc.MkcdUpDt, sToDt]), ss);
end else
aHTTP.Get(gMgSvc.DestIPort + 'aapi/mk-codes?isDeleted=false', ss);
// aHTTP.Get(gMgSvc.DestIPort + 'aapi/mk-codes', ss);
if ss.Size > 0 then
begin
if not bForceDl and FileExists(sPath) then
begin
var xStrData: TxStrData;
Guard(xStrData, TxStrData.Create('mk-codes'));
xStrData.LoadFromFile(sPath);
xStrData.UpdateData(ss.DataString);
xStrData.SaveToFile(sPath);
TTgTrace.T('mk-codes 데이터 업데이트 완료', 1);
end else begin
if bForceDl and FileExists(sPath) then
DeleteFile(sPath);
ss.SaveToFile(sXPrtDir + 'xMkc.dat');
TTgTrace.T('mk-codes 데이터 전체 다운로드 완료', 1);
end;
EncFile(sPath);
end;
if sUpDt <> '' then
begin
gMgSvc.MkcdUpDt := sUpDt;
bUpdate := true;
end;
end;
if xpdLump in aPrtDatas then
begin
sPath := sXPrtDir + 'xLum.dat';
ss.Clear;
sUpDt := GetTimestampFromJsonStr(aHTTP.Get(gMgSvc.DestIPort + 'aapi/lumpsum-fixed-codes/latest-timestamp'));
if not bForceDl and FileExists(sPath) and (sUpDt <> '') and (gMgSvc.LumpUpDt <> '') then
begin
sToDt := '2099-12-31T23:59:59Z';
aHTTP.Get(gMgSvc.DestIPort + Format('aapi/lumpsum-fixed-codes?from=%s&to=%s&include=changeType&groupBy=changeType', [gMgSvc.LumpUpDt, sToDt]), ss);
end else
aHTTP.Get(gMgSvc.DestIPort + 'aapi/lumpsum-fixed-codes?isDeleted=false', ss);
// aHTTP.Get(gMgSvc.DestIPort + 'aapi/lumpsum-fixed-codes', ss);
if ss.Size > 0 then
begin
if not bForceDl and FileExists(sPath) then
begin
var xStrData: TxStrData;
Guard(xStrData, TxStrData.Create('lumpsum-fixed-codes'));
xStrData.LoadFromFile(sPath);
xStrData.UpdateData(ss.DataString);
xStrData.SaveToFile(sPath);
TTgTrace.T('lumpsum-fixed-codes 데이터 업데이트 완료', 1);
end else begin
if bForceDl and FileExists(sPath) then
DeleteFile(sPath);
ss.SaveToFile(sPath);
TTgTrace.T('lumpsum-fixed-codes 데이터 전체 다운로드 완료', 1);
end;
EncFile(sPath);
end;
if sUpDt <> '' then
begin
gMgSvc.LumpUpDt := sUpDt;
bUpdate := true;
end;
end;
if bUpdate then
begin
var ini: TIniFile;
Guard(ini, TIniFile.Create(GetRunExePathDir + 'xPrint.ini'));
ini.WriteString('DateTime', 'EmpsUpDt', gMgSvc.EmpsUpDt);
ini.WriteString('DateTime', 'PrtsUpDt', gMgSvc.PrtsUpDt);
ini.WriteString('DateTime', 'BillUpDt', gMgSvc.BillUpDt);
ini.WriteString('DateTime', 'MkcdUpDt', gMgSvc.MkcdUpDt);
ini.WriteString('DateTime', 'LumpUpDt', gMgSvc.LumpUpDt);
gMgSvc.dtOneDay_ := Now;
ini.WriteDateTime('DateTime', 'xOneDayDT', gMgSvc.dtOneDay_);
end;
Result := true;
TTgTrace.T('ProcessRcv_xPrintData() .. OK', 1);
except
on E: Exception do
ETgException.TraceException(E, 'Fail .. ProcessRcv_xPrintData()');
end;
end;
procedure CheckAndUpdate_xPrint;
var
sRes,
sNewVer,
sCurVer: String;
NewVers,
CurVers: TStringList;
i: Integer;
OVer: ISuperObject;
bDoUpdate: Boolean;
PO: TPrefModel;
begin
try
if gMgSvc.ThdxPrintLog = nil then
exit;
PO := gMgSvc.PrefModel;
if not PO.xPrintUpEnable then
exit;
sNewVer := PO.xPrintUpVer;
if sNewVer = '' then
exit;
sCurVer := gMgSvc.xPrintVer;
if sCurVer = '' then
sCurVer := '1.0.0';
if sNewVer = sCurVer then
exit;
bDoUpdate := false;
if not PO.xPrintUpFixedVer then
begin
Guard(NewVers, TStringList.Create);
Guard(CurVers, TStringList.Create);
if SplitString(sNewVer, '.', NewVers) = 0 then
exit;
if SplitString(sCurVer, '.', CurVers) = 0 then
begin
bDoUpdate := StrToIntDef(NewVers[0], 0) > StrToIntDef(sCurVer, 0);
exit;
end;
for i := 0 to NewVers.Count - 1 do
begin
if i >= CurVers.Count then
begin
bDoUpdate := true;
break;
end;
if StrToIntDef(NewVers[i], 0) < StrToIntDef(CurVers[i], 0) then
break;
if StrToIntDef(NewVers[i], 0) > StrToIntDef(CurVers[i], 0) then
begin
bDoUpdate := true;
break;
end;
end;
end else
bDoUpdate := sNewVer <> sCurVer;
if bDoUpdate then
begin
// 다운로드, 업데이트 실패해도 재시도 하지 않게 버전 정보 업데이트 25_0730 15:32:07 kku
gMgSvc.xPrintVer := sNewVer;
TTgTrace.T('xPrint 업데이트 시작 .. Ver=%s, NewVer=%s', [sCurVer, sNewVer]);
var sUrl: String := gMgSvc.DestIPort + 'aapi/comps/xprint?ver=' + sNewVer;
var nOldTO: Integer := gMgSvc.HTTP.ReadTimeout;
var sPtPath: String := GetProgramFilesDir + DIR_TG;
var sZName: String := 'x_patch.zip';
var fs: TFileStream := TFileStream.Create(sPtPath + sZName, fmCreate);
gMgSvc.HTTP.ReadTimeout := 120000;
try
gMgSvc.HTTP.Get(sUrl, fs);
Sleep(500);
if FileExists(sPtPath + sZName) then
begin
FreeAndNil(fs);
if GetFileSize_path(sPtPath + sZName) = 0 then
begin
TTgTrace.T('Fail .. CheckAndUpdate_xPrint() .. 다운로드 실패, 크기 0');
DeleteFile(PChar(sPtPath + sZName));
exit;
end;
if not UninstallXPrt(true) then
begin
gMgSvc.xPrintVer := sCurVer;
TTgTrace.T('Fail .. CheckAndUpdate_xPrint() .. 제거 실패.');
exit;
end;
var sXPrtPath: String := 'C:\ProgramData\bsoneprint\';
if ForceDirectories(sXPrtPath) then
begin
TZipFile.ExtractZipFile(sPtPath + sZName, sXPrtPath);
DeleteFile(PChar(sPtPath + sZName));
ExecutePath_hide(sXprtPath + EXE_xPrintSvc, '-install');
end;
end;
finally
if fs <> nil then
FreeAndNil(fs);
gMgSvc.HTTP.ReadTimeout := nOldTO;
end;
TTgTrace.T('xPrint 업데이트 완료 .. Ver=%s, NewVer=%s', [sCurVer, sNewVer]);
end;
except
on E: Exception do
ETgException.TraceException(E, 'Fail .. CheckAndUpdate_xPrint()');
end;
end;
//procedure CheckAndUpdate_xPrint;
//var
// sRes,
// sNewVer,
// sCurVer: String;
// NewVers,
// CurVers: TStringList;
// i: Integer;
// OVer: ISuperObject;
// bDoUpdate: Boolean;
//begin
// try
// if gMgSvc.ThdxPrintLog = nil then
// exit;
//
// sRes := gMgSvc.HTTP.Get(gMgSvc.DestIPort + 'aapi/comps/xprint/info');
// if sRes = '' then
// exit;
// try
// OVer := SO(sRes);
// except
// exit;
// end;
//
// sNewVer := OVer.S['ver'];
// if sNewVer = '' then
// exit;
//
// sCurVer := gMgSvc.xPrintVer;
// if sCurVer = '' then
// sCurVer := '1.0.0';
//
// if sNewVer = sCurVer then
// exit;
//
// Guard(NewVers, TStringList.Create);
// Guard(CurVers, TStringList.Create);
// if SplitString(sNewVer, '.', NewVers) = 0 then
// exit;
//
// bDoUpdate := false;
// if SplitString(sCurVer, '.', CurVers) = 0 then
// begin
// bDoUpdate := StrToIntDef(NewVers[0], 0) > StrToIntDef(sCurVer, 0);
// exit;
// end;
//
// for i := 0 to NewVers.Count - 1 do
// begin
// if i >= CurVers.Count then
// begin
// bDoUpdate := true;
// break;
// end;
//
// if StrToIntDef(NewVers[i], 0) < StrToIntDef(CurVers[i], 0) then
// break;
//
// if StrToIntDef(NewVers[i], 0) > StrToIntDef(CurVers[i], 0) then
// begin
// bDoUpdate := true;
// break;
// end;
// end;
//
// if bDoUpdate then
// begin
// // 다운로드, 업데이트 실패해도 재시도 하지 않게 버전 정보 업데이트 25_0730 15:32:07 kku
// gMgSvc.xPrintVer := sNewVer;
// TTgTrace.T('xPrint 업데이트 시작 .. Ver=%s, NewVer=%s', [sCurVer, sNewVer]);
//
// var sUrl: String := gMgSvc.DestIPort + 'aapi/comps/xprint';
// var nOldTO: Integer := gMgSvc.HTTP.ReadTimeout;
// var sPtPath: String := GetProgramFilesDir + DIR_TG;
// var sZName: String := 'x_patch.zip';
// var fs: TFileStream := TFileStream.Create(sPtPath + sZName, fmCreate);
// gMgSvc.HTTP.ReadTimeout := 120000;
// try
// gMgSvc.HTTP.Get(sUrl, fs);
// Sleep(500);
// if FileExists(sPtPath + sZName) then
// begin
// FreeAndNil(fs);
// if GetFileSize_path(sPtPath + sZName) = 0 then
// begin
// TTgTrace.T('Fail .. CheckAndUpdate_xPrint() .. 다운로드 실패, 크기 0');
// DeleteFile(PChar(sPtPath + sZName));
// exit;
// end;
//
// if not UninstallXPrt(true) then
// begin
// gMgSvc.xPrintVer := sCurVer;
// TTgTrace.T('Fail .. CheckAndUpdate_xPrint() .. 제거 실패.');
// exit;
// end;
//
// var sXPrtPath: String := 'C:\ProgramData\bsoneprint\';
// if ForceDirectories(sXPrtPath) then
// begin
// TZipFile.ExtractZipFile(sPtPath + sZName, sXPrtPath);
// DeleteFile(PChar(sPtPath + sZName));
//
// ExecutePath_hide(sXprtPath + EXE_xPrintSvc, '-install');
// end;
// end;
// finally
// if fs <> nil then
// FreeAndNil(fs);
// gMgSvc.HTTP.ReadTimeout := nOldTO;
// end;
//
// TTgTrace.T('xPrint 업데이트 완료 .. Ver=%s, NewVer=%s', [sCurVer, sNewVer]);
// end;
// except
// on E: Exception do
// ETgException.TraceException(E, 'Fail .. CheckAndUpdate_xPrint()');
// end;
//end;
end.