2452 lines
91 KiB
Plaintext
2452 lines
91 KiB
Plaintext
{*******************************************************}
|
||
{ }
|
||
{ ThdPrintWork }
|
||
{ }
|
||
{ Copyright (C) 2025 kku }
|
||
{ }
|
||
{*******************************************************}
|
||
|
||
unit ThdPrintWork;
|
||
|
||
interface
|
||
|
||
uses
|
||
Tocsg.Thread, Tocsg.Printer, System.SysUtils, System.Classes,
|
||
System.Generics.Collections, Winapi.Windows, Tocsg.Fasoo;
|
||
|
||
type
|
||
PPrtHookJobEnt = ^TPrtHookJobEnt;
|
||
TPrtHookJobEnt = record
|
||
dtReg: TDateTime;
|
||
sPName,
|
||
sPrtName,
|
||
sDocName,
|
||
sPrtDocId: String;
|
||
ullPid: ULONGLONG;
|
||
end;
|
||
TPrtHookJobEntList = TList<PPrtHookJobEnt>;
|
||
|
||
TThdPrintWork = class(TTgThread)
|
||
protected
|
||
JobList_: TList<TPrtJobInfo>;
|
||
fas_: TTgFasoo;
|
||
bIsWorking_: Boolean;
|
||
CurJob_: TPrtJobInfo;
|
||
PrintAppList_,
|
||
IgrPrtSpoolAnal_: TStringList;
|
||
bBackupSpl_: Boolean;
|
||
sWorkDir_: String;
|
||
|
||
PrtHookJobEntList_: TPrtHookJobEntList;
|
||
|
||
// 후킹방식으로 프린트 워터마크 출력 시 예외 되었는지 체크
|
||
bPrtWaterExp_: Boolean;
|
||
|
||
procedure OnPrtHe(Sender: TObject; const Item: PPrtHookJobEnt; Action: TCollectionNotification);
|
||
procedure Execute; override;
|
||
procedure ProcessPrintJob(aJob: TPrtJobInfo);
|
||
procedure AddIgrPrtSpool(sPrtName: String);
|
||
function IsSpoolAnal(sPrtName: String): Boolean;
|
||
function GetHookJob(sPrtName, sDocName: String; bFindDel: Boolean = false): PPrtHookJobEnt;
|
||
procedure RefineHookJob;
|
||
public
|
||
WordPrtPage: Integer;
|
||
Constructor Crate;
|
||
Destructor Destroy; override;
|
||
|
||
procedure AddJob(aJob: TPrtJobInfo);
|
||
function HasJob(aJob: TPrtJobInfo): Boolean;
|
||
|
||
procedure AddHookJob(sPName, sPrtName, sDocName, sPrtDocId: String; ullPid: ULONGLONG);
|
||
|
||
property IsWorking: Boolean read bIsWorking_;
|
||
property PrtWaterExp: Boolean write bPrtWaterExp_;
|
||
end;
|
||
|
||
implementation
|
||
|
||
uses
|
||
Tocsg.Exception, Tocsg.Files, Tocsg.Path, Winapi.ActiveX, Tocsg.Safe,
|
||
Tocsg.Strings, Tocsg.Shell, Tocsg.Trace, superobject, ManagerService,
|
||
GlobalDefine, IdHTTP, IdSSLOpenSSL, IdMultipartFormData, Tocsg.DateTime,
|
||
System.IniFiles, ManagerModel, ManagerPattern, Tocsg.Convert, Condition,
|
||
Winapi.WinSpool, ManagerPrint, Tocsg.Process, ThdWebUrl, Tocsg.WndUtil,
|
||
Tocsg.Registry, CrmUtil, ProcessSoftcampDRM, Tocsg.Encrypt, System.DateUtils,
|
||
Tocsg.DRM.Encrypt, Tocsg.PCRE, ManagerRule, CttSchDefine, ThdExecuteEndNoti,
|
||
ManagerCampaign, Tocsg.Valid, AppCtrlDefine, Vcl.Printers, Vcl.Graphics,
|
||
Vcl.Imaging.pngimage, DefineHelper, ManagerHook, Tocsg.FileInfo;
|
||
|
||
{ TThdPrintWork }
|
||
|
||
Constructor TThdPrintWork.Crate;
|
||
var
|
||
sPath: String;
|
||
ini: TIniFile;
|
||
begin
|
||
Inherited Create;
|
||
bPrtWaterExp_ := false;
|
||
JobList_ := TList<TPrtJobInfo>.Create;
|
||
bIsWorking_ := false;
|
||
bBackupSpl_ := false;
|
||
WordPrtPage := 0;
|
||
sWorkDir_ := 'C:\ProgramData\HE\';
|
||
|
||
PrtHookJobEntList_ := TPrtHookJobEntList.Create;;
|
||
|
||
PrintAppList_ := TStringList.Create;
|
||
PrintAppList_.CaseSensitive := false;
|
||
sPath := GetProgramFilesDir + DIR_TG + INI_FORCEHE;
|
||
var sPrtApps: String;
|
||
case CUSTOMER_TYPE of
|
||
CUSTOMER_GEC,
|
||
CUSTOMER_HDENG : sPrtApps := RPINT_SUPPORT_APPS_HEC;
|
||
else sPrtApps := PRINT_SUPPORT_APPS;
|
||
end;
|
||
|
||
if FileExists(sPath) then
|
||
begin
|
||
try
|
||
Guard(ini, TIniFile.Create(sPath));
|
||
sPrtApps := sPrtApps + '|' + ini.ReadString('Force', 'PrtWaterApp', '');
|
||
bBackupSpl_ := ini.ReadBool('Force', 'BackupSpool', false);
|
||
except
|
||
// ..
|
||
end;
|
||
end;
|
||
SplitString(sPrtApps, '|', PrintAppList_, false, true);
|
||
RefinePrintHookAppList(PrintAppList_);
|
||
|
||
IgrPrtSpoolAnal_ := TStringList.Create;
|
||
IgrPrtSpoolAnal_.CaseSensitive := false;
|
||
sPath := GetRunExePathDir + INI_HE;
|
||
if FileExists(sPath) then
|
||
begin
|
||
try
|
||
Guard(ini, TIniFile.Create(sPath));
|
||
SplitString(ini.ReadString('Print', 'IgrSpool', ''), '|', IgrPrtSpoolAnal_);
|
||
except
|
||
// ..
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
Destructor TThdPrintWork.Destroy;
|
||
begin
|
||
if fas_ <> nil then
|
||
FreeAndNil(fas_);
|
||
FreeAndNil(IgrPrtSpoolAnal_);
|
||
FreeAndNil(PrintAppList_);
|
||
FreeAndNil(JobList_);
|
||
PrtHookJobEntList_.OnNotify := OnPrtHe;
|
||
FreeAndNil(PrtHookJobEntList_);
|
||
Inherited;
|
||
end;
|
||
|
||
procedure TThdPrintWork.OnPrtHe(Sender: TObject; const Item: PPrtHookJobEnt; Action: TCollectionNotification);
|
||
begin
|
||
if Action = cnRemoved then
|
||
Dispose(Item);
|
||
end;
|
||
|
||
procedure TThdPrintWork.AddJob(aJob: TPrtJobInfo);
|
||
begin
|
||
Lock;
|
||
try
|
||
JobList_.Add(aJob);
|
||
finally
|
||
Unlock;
|
||
end;
|
||
end;
|
||
|
||
function TThdPrintWork.HasJob(aJob: TPrtJobInfo): Boolean;
|
||
begin
|
||
Result := false;
|
||
try
|
||
Lock;
|
||
try
|
||
if CurJob_ = aJob then
|
||
Exit(true);
|
||
|
||
if JobList_.IndexOf(aJob) <> -1 then
|
||
Exit(true);
|
||
finally
|
||
Unlock;
|
||
end;
|
||
except
|
||
on E: Exception do
|
||
ETgException.TraceException(Self, E, 'Fail .. HasJob()');
|
||
end;
|
||
end;
|
||
|
||
procedure TThdPrintWork.AddHookJob(sPName, sPrtName, sDocName, sPrtDocId: String; ullPid: ULONGLONG);
|
||
var
|
||
pEnt: PPrtHookJobEnt;
|
||
begin
|
||
try
|
||
New(pEnt);
|
||
ZeroMemory(pEnt, SizeOf(TPrtHookJobEnt));
|
||
pEnt.dtReg := Now;
|
||
pEnt.sPName := sPName;
|
||
pEnt.sPrtName := sPrtName;
|
||
pEnt.sDocName := sDocName;
|
||
pEnt.sPrtDocId := sPrtDocId;
|
||
pEnt.ullPid := ullPid;
|
||
|
||
Lock;
|
||
try
|
||
PrtHookJobEntList_.Add(pEnt);
|
||
finally
|
||
Unlock;
|
||
end;
|
||
except
|
||
on E: Exception do
|
||
ETgException.TraceException(Self, E, 'Fail .. AddHookJob()');
|
||
end;
|
||
end;
|
||
|
||
function TThdPrintWork.GetHookJob(sPrtName, sDocName: String; bFindDel: Boolean = false): PPrtHookJobEnt;
|
||
var
|
||
i: Integer;
|
||
pEnt: PPrtHookJobEnt;
|
||
begin
|
||
Result := nil;
|
||
try
|
||
Lock;
|
||
try
|
||
for i := 0 to PrtHookJobEntList_.Count - 1 do
|
||
begin
|
||
pEnt := PrtHookJobEntList_[i];
|
||
if (CompareText(sPrtName, pEnt.sPrtName) = 0) and
|
||
(CompareText(sDocName, pEnt.sDocName) = 0) then
|
||
begin
|
||
Result := pEnt;
|
||
if bFindDel then
|
||
PrtHookJobEntList_.Delete(i);
|
||
exit;
|
||
end;
|
||
end;
|
||
finally
|
||
Unlock;
|
||
end;
|
||
except
|
||
on E: Exception do
|
||
ETgException.TraceException(Self, E, 'Fail .. GetHookJob()');
|
||
end;
|
||
end;
|
||
|
||
procedure TThdPrintWork.RefineHookJob;
|
||
var
|
||
i: Integer;
|
||
dtNow: TDateTime;
|
||
begin
|
||
try
|
||
dtNow := Now;
|
||
Lock;
|
||
try
|
||
for i := PrtHookJobEntList_.Count - 1 downto 0 do
|
||
begin
|
||
if MinutesBetween(PrtHookJobEntList_[i].dtReg, dtNow) > 60 then
|
||
PrtHookJobEntList_.Delete(i);
|
||
end;
|
||
finally
|
||
Unlock;
|
||
end;
|
||
except
|
||
on E: Exception do
|
||
ETgException.TraceException(Self, E, 'Fail .. RefineHookJob()');
|
||
end;
|
||
end;
|
||
|
||
procedure TThdPrintWork.AddIgrPrtSpool(sPrtName: String);
|
||
begin
|
||
try
|
||
if IgrPrtSpoolAnal_.IndexOf(sPrtName) = -1 then
|
||
begin
|
||
IgrPrtSpoolAnal_.Add(sPrtName);
|
||
|
||
var i: Integer;
|
||
var sIgrPrts: String := '';
|
||
for i := 0 to IgrPrtSpoolAnal_.Count - 1 do
|
||
SumString(sIgrPrts, IgrPrtSpoolAnal_[i], '|');
|
||
|
||
var sPath: String := GetRunExePathDir + INI_HE;
|
||
var ini: TIniFile;
|
||
Guard(ini, TIniFile.Create(sPath));
|
||
ini.WriteString('Print', 'IgrSpool', sIgrPrts);
|
||
end;
|
||
except
|
||
on E: Exception do
|
||
ETgException.TraceException(Self, E, 'Fail .. AddIgrPrtSpool()');
|
||
end;
|
||
end;
|
||
|
||
function TThdPrintWork.IsSpoolAnal(sPrtName: String): Boolean;
|
||
begin
|
||
Result := not IsNoPrintSpoolWater;
|
||
exit;
|
||
if Result then
|
||
Result := IgrPrtSpoolAnal_.IndexOf(sPrtName) = -1;
|
||
end;
|
||
|
||
procedure TThdPrintWork.ProcessPrintJob(aJob: TPrtJobInfo);
|
||
var
|
||
PO, PPO: TPrefModel;
|
||
PP: TPrintPolicy;
|
||
|
||
pPhJob: PPrtHookJobEnt;
|
||
sPrtName, sDocName,
|
||
sPort, sPrtDocId,
|
||
sChk, sData,
|
||
sPName, sPPath,
|
||
sDocPath, sPrtIp,
|
||
sExtrOcrTxt, sThumbIds,
|
||
sExtrOcr180Txt,
|
||
sExtrTxt, sSpoolPath,
|
||
sEmfDir, sBlockReson: String;
|
||
ini: TIniFile;
|
||
ExcpList: TStringList;
|
||
i, nTotalPages: Integer;
|
||
bBlock, bIsDrm, bCfActive,
|
||
bWaterMark, bIgrApproval, bApprovalPost: Boolean;
|
||
PrtInfo: TPrtJobDevInfo;
|
||
OVio, OVioTemp, OEnt: ISuperObject;
|
||
PatternEntList: TPatternEntList;
|
||
bIsHook, bIsSplAnal, bSpoolEnd: Boolean;
|
||
|
||
procedure SetProcessName(sName: String);
|
||
begin
|
||
if sPName <> sName then
|
||
begin
|
||
sPName := sName;
|
||
bIsHook := IsPrintWaterHook;
|
||
if bIsHook and not IsHD then
|
||
begin
|
||
if PrintAppList_.IndexOf(sPName) = -1 then
|
||
bIsHook := false;
|
||
end;
|
||
|
||
bIsSplAnal := not bIsHook;
|
||
if bIsSplAnal then
|
||
bIsSplAnal := IsSpoolAnal(sPrtName);
|
||
end;
|
||
end;
|
||
|
||
function FindPrintingFile(sDocName: String; bIgrRB: Boolean = false): String;
|
||
var
|
||
sDir, sChk, sUserDir: String;
|
||
DList: TStringList;
|
||
FList: TModFileList;
|
||
i, n: Integer;
|
||
// Plf: TParserLinkFile;
|
||
begin
|
||
Result := '';
|
||
|
||
sDir := GetWindowsDir;
|
||
if sDir = '' then
|
||
exit;
|
||
|
||
CoInitialize(nil);
|
||
try
|
||
Guard(DList, TStringList.Create);
|
||
Guard(FList, TModFileList.Create(TModeFileComparer.Create));
|
||
|
||
sUserDir := UpperCase(sDir[1]) + ':\Users\';
|
||
ExtrDirFromDir(sUserDir, DList);
|
||
for i := 0 to DList.Count - 1 do
|
||
begin
|
||
sDir := sUserDir + DList[i] + '\AppData\Roaming\Microsoft\Windows\Recent\';
|
||
ExtrModFilesFromDir(sDir, FList);
|
||
end;
|
||
|
||
if FList.Count > 0 then
|
||
begin
|
||
FList.Sort;
|
||
|
||
if bIgrRB then
|
||
sDocName := StrsReplace(sDocName, ['(', ')', '[', ']'], '0');
|
||
|
||
for i := 0 to FList.Count - 1 do
|
||
begin
|
||
if bIgrRB then
|
||
sChk := StrsReplace(CutFileExt(FList[i].sFName), ['(', ')', '[', ']'], '0')
|
||
else
|
||
sChk := CutFileExt(FList[i].sFName);
|
||
|
||
// 최근문서 파일처리 보완 24_0722 14:54:30 kku
|
||
if (sChk.Length > 0) and (sChk[sChk.Length] = ')') then
|
||
begin
|
||
n := LastIndexOf(' (', sChk);
|
||
if n > 0 then
|
||
Delete(sChk, n, sChk.Length - n + 1);
|
||
end;
|
||
// TTgTrace.T('Check RecentFileName = "%s"', [sChk], 3);
|
||
|
||
if Pos(sChk, sDocName) > 0 then
|
||
begin
|
||
Result := GetTargetExeFromLink(FList[i].sDir + FList[i].sFName);
|
||
if Result = '' then
|
||
continue;
|
||
|
||
// 간혹 사용자 폴더가 이상하게(?) 표시되는 경우가 있다.. 보정 24_0514 10:09:24 kku
|
||
if (Result <> '') and (Pos('windows\system32\config\systemprofile', Result.ToLower) > 0) then
|
||
begin
|
||
TTgTrace.T('Replace path = "%s"', [Result], 3);
|
||
|
||
sDir := StringReplace(FList[i].sDir, '\AppData\Roaming\Microsoft\Windows\Recent\', '', [rfReplaceAll, rfIgnoreCase]);
|
||
sDir := ExtractFileName(sDir);
|
||
Result := StringReplace(Result, 'windows\system32\config\systemprofile',
|
||
Format('Users\%s', [sDir]), [rfReplaceAll, rfIgnoreCase]);
|
||
|
||
TTgTrace.T('Replace Path done = "%s"', [Result], 3);
|
||
end;
|
||
|
||
TTgTrace.T('Found Path = "%s", CheckName = "%s", RecentName = "%s"', [Result, sChk, FList[i].sFName], 3);
|
||
|
||
if DirectoryExists(Result) or not FileExists(Result) then
|
||
continue;
|
||
// Guard(Plf, TParserLinkFile.Create);
|
||
// if Plf.LoadFromFile(sDir + FList[i].sName) then
|
||
// begin
|
||
// Result := GetLfiValueFromCaption(Plf.LfiEntList, 'Base Path');
|
||
// if not FileExists(Result) then
|
||
// Result := '';
|
||
// end;
|
||
exit;
|
||
end;
|
||
end;
|
||
|
||
// PDF의 경우... 문서 이름에 파일 이름이 안들어 가는 경우가 있다...
|
||
// PDF 파일 최근파일 내역을 찾을 수 없다면 맨 첫번째 있는 PDF 파일을 넘겨준다.. 24_0418 15:10:27 kku
|
||
if Pos('.PDF', sDocName.ToUpper) > 0 then
|
||
begin
|
||
for i := 0 to FList.Count - 1 do
|
||
begin
|
||
sChk := CutFileExt(FList[i].sFName);
|
||
if GetFileExt(sChk).ToUpper = 'PDF' then
|
||
begin
|
||
Result := sChk;
|
||
exit;
|
||
end;
|
||
end;
|
||
end;
|
||
end;
|
||
finally
|
||
CoUninitialize;
|
||
end;
|
||
end;
|
||
|
||
procedure SendReqPrint(sExtrTxt, sFName, sPName: String);
|
||
var
|
||
O: ISuperObject;
|
||
sMsg: String;
|
||
begin
|
||
sExtrTxt := StringReplace(sExtrTxt, #13#10, ' ', [rfReplaceAll]);
|
||
if nTotalPages = 0 then
|
||
nTotalPages := 1;
|
||
sMsg := Format('PRINTER:%s|TEXT:%s|FILENAME:%s|TYPE:6|EVTTIME:%s|PAGE:%d|APP:%s|DESC:None|SCANRESULT:-1',
|
||
[sPrtName, sExtrTxt, sFName, FormatDateTime('yyyy-mm-dd hh:nn:ss', Now), nTotalPages, sPName]);
|
||
// DirectSendEventLog(URI_USER_ACTION, REQUEST_PRINT_EXCEPT, sMsg);
|
||
gMgSvc.SendEventLog(URI_USER_ACTION, REQUEST_PRINT_EXCEPT, sMsg);
|
||
end;
|
||
|
||
function DirectSendPtrFile(sPath: String): Boolean;
|
||
var
|
||
HTTP: TIdHTTP;
|
||
SSL: TIdSSLIOHandlerSocketOpenSSL;
|
||
ss: TStringStream;
|
||
sBoundary,
|
||
sDestFileUrl: String;
|
||
Params: TIdMultiPartFormDataStream;
|
||
msResp: TMemoryStream;
|
||
begin
|
||
Result := false;
|
||
if not FileExists(sPath) then
|
||
exit;
|
||
|
||
try
|
||
sDestFileUrl := gMgSvc.DestServerUrl;
|
||
sDestFileUrl := StringReplace(gMgSvc.DestServerUrl, 'agentLogRequest.do', 'agentPrintExcept.do', [rfReplaceAll]);
|
||
sDestFileUrl := StringReplace(sDestFileUrl, 'agentLogRequests.do', 'agentPrintExcept.do', [rfReplaceAll]);
|
||
sBoundary := Format('%X', [GetLocalIncUtcMin * 6000]);
|
||
|
||
Guard(SSL, TIdSSLIOHandlerSocketOpenSSL.Create(nil));
|
||
SSL.SSLOptions.Method := sslvSSLv23;
|
||
SSL.SSLOptions.SSLVersions := [sslvTLSv1_2, sslvTLSv1_1, sslvTLSv1];
|
||
|
||
Guard(HTTP, TIdHTTP.Create(nil));
|
||
HTTP.IOHandler := SSL;
|
||
with HTTP do
|
||
begin
|
||
HandleRedirects := true;
|
||
Request.Clear;
|
||
Request.UserAgent := 'Mozilla/5.0';
|
||
Request.ContentType := 'application/xml';
|
||
Request.AcceptCharSet := 'UTF-8';
|
||
// Request.Connection := 'Keep-Alive';
|
||
// Request.CustomHeaders.Values['Keep-Alive'] := 'timeout=300, max=100';
|
||
Request.Connection := 'close';
|
||
HTTPOptions := HTTPOptions - [hoKeepOrigProtocol];
|
||
HTTPOptions := HTTP.HTTPOptions + [hoForceEncodeParams];
|
||
ConnectTimeout := 2000;
|
||
ReadTimeout := 2000;
|
||
|
||
Request.ContentType := Format('multipart/form-data; boundary=%s; charset=utf-8', [sBoundary]);
|
||
end;
|
||
|
||
Guard(msResp, TMemoryStream.Create);
|
||
Guard(Params, TIdMultiPartFormDataStream.Create);
|
||
with Params.AddFile(ExtractFileName(sPath),
|
||
sPath, Format('application/%s', [GetFileExt(sPath)])) do
|
||
begin
|
||
ContentTransfer := '';
|
||
HeaderEncoding := '8'; //8bit
|
||
HeaderCharSet := 'utf-8';
|
||
Charset := 'utf-8';
|
||
end;
|
||
|
||
Params.Position := 0;
|
||
HTTP.Post(sDestFileUrl, Params, msResp);
|
||
Result := HTTP.ResponseCode = 200;
|
||
except
|
||
on E: Exception do
|
||
ETgException.TraceException(Self, E, 'Fail .. DirectSendPtrFile()');
|
||
end;
|
||
end;
|
||
|
||
function GetSpoolCopyPath(sSubDirName: String = 'Task'): String;
|
||
var
|
||
sHookPName,
|
||
sRecentSool,
|
||
sSpoolWorkDir: String;
|
||
i: Integer;
|
||
begin
|
||
Result := '';
|
||
try
|
||
// if CUSTOMER_TYPE = CUSTOMER_CJOV_GLOBAL then
|
||
// sSpoolWorkDir := GetRunExePathDir + 'Task\' + sSubDirName + '\' +
|
||
// IncludeTrailingPathDelimiter(GetValidFileName(sPrtName, '#'))
|
||
// else
|
||
sSpoolWorkDir := sWorkDir_ + sSubDirName + '\' +
|
||
IncludeTrailingPathDelimiter(GetValidFileName(sPrtName, '#') + Format('-%d', [GetTickCount64]));
|
||
DeleteDir(sSpoolWorkDir);
|
||
|
||
if ForceDirectories(sSpoolWorkDir) then
|
||
begin
|
||
_Trace('프린터 출력 감지 .. Spool 수집 시작. Printer=%s, Doc=%s', [sPrtName, sDocName], 2);
|
||
while (aJob <> nil) and aJob.IsSpooling2 do
|
||
begin
|
||
if i = 4000 then // 200초간 기다려준다 23_0525 08:03:11 kku
|
||
break;
|
||
|
||
Inc(i);
|
||
Sleep(50);
|
||
end;
|
||
|
||
// 스풀링 끝나고 정지가 풀리는 프린터가 있다?
|
||
// 의심되서 추가 25_0618 08:45:08 kku
|
||
aJob.PausePrtJob;
|
||
|
||
sRecentSool := GetLastSpoolPath(GetSystemDir + 'spool\PRINTERS\');
|
||
_Trace('프린터 출력 감지 .. Spool 확인. Path=%s', [sRecentSool], 2);
|
||
{$IF false}
|
||
sRecentSool := 'C:\Users\kku\Desktop\이전 바탕화면\spl2pdf_cmd\PPT그라데이션_20250911093157.spl';
|
||
if FileExists(sRecentSool) and ForceDirectories('C:\ProgramData\HE\Test_Prt\') then
|
||
begin
|
||
Result := Format('C:\ProgramData\HE\Test_Prt\%s.spl', [FormatDateTime('yyyymmddhhnnss', Now)]);
|
||
CopyFile(PChar(sRecentSool), PChar(Result), false);
|
||
end;
|
||
{$ELSE}
|
||
if FileExists(sRecentSool) then
|
||
begin
|
||
Result := sSpoolWorkDir + ExtractFileName(sRecentSool);
|
||
CopyFile(PChar(sRecentSool), PChar(Result), false);
|
||
if bBackupSpl_ and ForceDirectories('C:\ProgramData\HE\') then
|
||
CopyFile(PChar(sRecentSool), PChar(Format('C:\ProgramData\HE\%s.spl', [FormatDateTime('yyyymmddhhnnss', Now)])), false);
|
||
// Sleep(500);
|
||
|
||
// if not FileExists(Result) or (GetFileSize_path(Result) = 0) then
|
||
// begin
|
||
// // 스플 경로가 System 권한으로 접근하기 어려운 경우 현재 사용자 권한으로 다시 시도 24_1212 13:17:40 kku
|
||
// var sExe: String := GetRunExePathDir + DIR_CONF + EXE_HLP;
|
||
// if FileExists(sExe) then
|
||
// begin
|
||
// var O: ISuperObject := SO;
|
||
// O.I['Cmd'] := HPCMD_COPY_FILE;
|
||
// O.S['Src'] := sRecentSool;
|
||
// O.S['Dest'] := Result;
|
||
// SaveJsonObjToFile(O, GetRunExePathDir + DIR_CONF + DAT_PARAM);
|
||
// {$IFDEF DEBUG}
|
||
// ExecutePath(sExe);
|
||
// {$ELSE}
|
||
// ExecuteAppAsUser('explorer.exe', sExe, '', SW_SHOWNORMAL);
|
||
// {$ENDIF}
|
||
// end;
|
||
// end;
|
||
|
||
if not FileExists(Result) then
|
||
begin
|
||
Result := '';
|
||
_Trace('프린터 출력 감지 .. Spool 수집 실패. Printer=%s, Doc=%s', [sPrtName, sDocName], 2);
|
||
end else begin
|
||
_Trace('프린터 출력 감지 .. Spool 수집 성공. Printer=%s, Doc=%s, SrcSize=%d, DestSize=%d', [sPrtName, sDocName, GetFileSize_path(sRecentSool), GetFileSize_path(Result)], 2);
|
||
end;
|
||
end else
|
||
TTgTrace.T('Not found spool file..');
|
||
{$IFEND}
|
||
|
||
// 스풀링 끝나면 정확한 정보를 위해 한번더 가져오기 시도
|
||
aJob.GetJobDevInfo(PrtInfo);
|
||
bSpoolEnd := true;
|
||
// 스풀 PJL 포맷이면 정확한 부수 정보 가져오기
|
||
if FileExists(Result) and IsPJL(Result) then
|
||
begin
|
||
if not IsPJLAndLanguagePLW(sSpoolPath) then
|
||
begin
|
||
var bCollate: Boolean;
|
||
var nCopies: Integer := GetQtyFromPJL(sSpoolPath, bCollate);
|
||
if (nCopies > 1) and (PrtInfo.dwCopyCount = 1) then
|
||
begin
|
||
_Trace('PJL 포맷에서 부수정보 다름 확인 .. PJL=%d, Job=%d', [nCopies, PrtInfo.dwCopyCount], 2);
|
||
PrtInfo.dwTotalPage := PrtInfo.dwTotalPage div nCopies;
|
||
PrtInfo.dwCopyCount := nCopies;
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
if pPhJob = nil then
|
||
begin
|
||
pPhJob := GetHookJob(sPrtName, sDocName, true);
|
||
if pPhJob <> nil then
|
||
begin
|
||
bIsHook := true;
|
||
bIsSplAnal := not bIsHook;
|
||
sPPath := GetProcessPathByPid(pPhJob.ullPid);
|
||
if sPPath <> '' then
|
||
begin
|
||
sPName := ExtractFileName(sPPath);
|
||
sPPath := ExtractFilePath(sPPath);
|
||
end else
|
||
sPName := pPhJob.sPName;
|
||
sPrtDocId := pPhJob.sPrtDocId;
|
||
_Trace('프린트 Hook 프로세스 확인(ex) : %s', [sPName], 1);
|
||
end;
|
||
// else begin
|
||
// sHookPName := GetRegValueAsString(HKEY_USERS, gMgSvc.RecentUserSid + '\Software\eCrmHomeEdition', 'PrtPName');
|
||
// if sHookPName = '' then
|
||
// sHookPName := GetRegValueAsString(HKEY_USERS, gMgSvc.RecentUserSid + '\Software\WOW6432Node\eCrmHomeEdition', 'PrtPName');
|
||
//
|
||
// if sHookPName <> '' then
|
||
// begin
|
||
// _Trace('프린트 Hook 프로세스 확인 : %s', [sHookPName], 1);
|
||
// if sHookPName <> sPName then
|
||
// begin
|
||
// _Trace('프린트 Hook 프로세스와 인식된 프로세스가 다름. 조치 시도, Cur=%s, New=%s', [sPName, sHookPName], 1);
|
||
// SetProcessName(sHookPName);
|
||
// end;
|
||
// end else begin
|
||
// bIsHook := false;
|
||
// bIsSplAnal := not bIsHook;
|
||
// if bIsSplAnal then
|
||
// bIsSplAnal := IsSpoolAnal(sPrtName);
|
||
// _Trace('프린트 Hook 프로세스 아님 : %s', [sPName], 1);
|
||
// end;
|
||
// end;
|
||
end;
|
||
// DelRegValue(HKEY_USERS, gMgSvc.RecentUserSid + '\Software\eCrmHomeEdition', 'PrtPName');
|
||
// DelRegValue(HKEY_USERS, gMgSvc.RecentUserSid + '\Software\WOW6432Node\eCrmHomeEdition', 'PrtPName');
|
||
end;
|
||
except
|
||
on E: Exception do
|
||
ETgException.TraceException(Self, E, 'Fail .. GetSpoolCopyPath()');
|
||
end;
|
||
end;
|
||
|
||
function GetEmfCopyDir(sSubDirName: String = 'PrtColi'): String;
|
||
var
|
||
sRecentSool,
|
||
sSpoolWorkDir: String;
|
||
i: Integer;
|
||
begin
|
||
Result := '';
|
||
try
|
||
while (aJob <> nil) and aJob.IsSpooling2 do
|
||
begin
|
||
if i = 4000 then // 200초간 기다려준다 23_0525 08:03:11 kku
|
||
break;
|
||
|
||
Inc(i);
|
||
Sleep(50);
|
||
end;
|
||
// Sleep(500);
|
||
|
||
if DirectoryExists(sWorkDir_ + 'PrtCol\') then
|
||
begin
|
||
if DirectoryExists(sWorkDir_ + sSubDirName) then
|
||
DeleteDir(sWorkDir_ + sSubDirName);
|
||
|
||
if MoveFile_wait(sWorkDir_ + 'PrtCol\', sWorkDir_ + sSubDirName, 3, true) then
|
||
Result := IncludeTrailingPathDelimiter(sWorkDir_ + sSubDirName);
|
||
end else
|
||
if DirectoryExists(sWorkDir_ + sSubDirName) then
|
||
Result := IncludeTrailingPathDelimiter(sWorkDir_ + sSubDirName);
|
||
except
|
||
on E: Exception do
|
||
ETgException.TraceException(Self, E, 'Fail .. GetSpoolCopyPath()');
|
||
end;
|
||
end;
|
||
|
||
function GetPrintLog(sCode: String): ISuperObject;
|
||
var
|
||
O, OSub: ISuperObject;
|
||
sCompId: String;
|
||
sMsg: String;
|
||
dt: TDateTime;
|
||
begin
|
||
Result := nil;
|
||
try
|
||
if bIsHook then
|
||
bWaterMark := (PP.PrintWater <> pwNone) and not bPrtWaterExp_;
|
||
|
||
sMsg := Format('Printer : %s, Document : %s', [sPrtName, sDocName]);
|
||
|
||
PO := gMgSvc.ModePolicy;
|
||
PPO := gMgSvc.PrefModel;
|
||
dt := Now;
|
||
O := SO;
|
||
if sCode = LOGCODE_EVENT_PRINTER then
|
||
O.S['TYP_MSG'] := '@(!)_IC_M'
|
||
else
|
||
O.S['TYP_MSG'] := '@(!)_IC_P';
|
||
O.S['KEY_AGENTID'] := gMgSvc.AgentId;
|
||
O.S['KEY_EMPNO'] := gMgSvc.EmpNo;
|
||
O.S['KEY_HOSTNAME'] := gMgSvc.UserName;
|
||
O.S['KEY_SUBMITTIME'] := FormatDateTime('yyyy-mm-dd hh:nn:ss', dt);
|
||
O.S['key_submitTime'] := FormatDateTime('yyyy-MM-dd"T"hh:nn:ss.zzz', dt) + gMgSvc.UtcOffset;
|
||
O.S['KEY_LOGCODE'] := sCode;
|
||
O.S['DETECTION_DATE'] := O.S['KEY_SUBMITTIME']; // 이벤트 발생 시각. REQUEST의 경우, 예외 신청할 이벤트의 발생 시각
|
||
O.S['detectionDate'] := O.S['key_submitTime']; // 이벤트 발생 시각. REQUEST의 경우, 예외 신청할 이벤트의 발생 시각
|
||
O.S['KEY_SUMMARY'] := sMsg;
|
||
// O.S['PARENT_LA_ID'] // 상위 이벤트
|
||
O.S['POLICY_ID'] := PO.PolicyId;
|
||
// O.S['POLICY_KEY'] // 정책 위반한 경우 (PREVENT, MONITOR), 위반한 정책의 정책 키 값, 수집인 경우 (DEPLOY), 수집 요청 ID
|
||
if PO.Print.bCollectOutput then
|
||
begin
|
||
if PPO.TextLimit > 0 then
|
||
begin
|
||
if Length(sExtrTxt) > PPO.TextLimit then
|
||
SetLength(sExtrTxt, PPO.TextLimit);
|
||
if Length(sExtrOcrTxt) > PPO.TextLimit then
|
||
SetLength(sExtrOcrTxt, PPO.TextLimit);
|
||
end;
|
||
|
||
O.S['MESSAGE_BODY'] := sExtrTxt; // 정책 위반한 경우 (PREVENT, MONITOR), 원문 (본문) 컨텐츠, 수집인 경우 (DEPLOY), 수집 결과 내용, 원문 수집 정책이 비활성화인경우 수집하지 않음
|
||
O.S['OCR_BODY'] := sExtrOcrTxt; // 이미지 OCR 추출된 컨텐츠, 원문 수집 정책이 비활성화인 경우 수집하지 않음
|
||
end;
|
||
|
||
if OVio <> nil then
|
||
O.O['RULE_VIOLATED'] := OVio; // 정책 위반 규칙과 위반 개수. (LIST)
|
||
|
||
if FileExists(sDocPath) then
|
||
begin
|
||
if PO.Print.bCollectFile then
|
||
begin
|
||
sCompId := gMgSvc.MakeComponentId(ExtractFileName(sDocPath));
|
||
// SendFile(sCompId, 'printLogCollect.do', sDocPath); // 원본 파일 수집은 이걸로 하면 안됨 24_0122 16:52:00 kku
|
||
gMgSvc.SendFileNor(false, sCompId, 'quarantineLogCollect.do', sDocPath, PO.PrtMinMB, PO.PrtMaxMB);
|
||
O.S['COMPONENT_ID'] := sCompId; // 파일 고유값. 에이전트에서 임의 생성. (이벤트간 동일 파일 판단은 서버에서 하겠습니다.)
|
||
end;
|
||
|
||
O.S['COMPONENT_FILENAME'] := ExtractFileName(sDocPath); // 파일명
|
||
O.S['COMPONENT_PATH'] := ExtractFilePath(sDocPath);// 파일 절대 경로
|
||
|
||
var dtCreate, dtModify, dtAccess: TDateTime;
|
||
GetFileDateTime_Local(sDocPath, dtCreate, dtModify, dtAccess);
|
||
var dwAttr: DWORD := GetFileAttributes(PChar(sDocPath));
|
||
|
||
var OTemp: ISuperObject := SO;
|
||
OTemp.S['FILESIZE'] := IntToStr(GetFileSize_path(sDocPath));
|
||
OTemp.S['LASTMODIFIED'] := FormatDateTime('yyyy-mm-dd hh:nn:ss', dtModify);
|
||
if dwAttr <> DWORD(-1) then
|
||
OTemp.S['READONLY'] := BooleanToStr((dwAttr and FILE_ATTRIBUTE_READONLY) <> 0, 'true', 'false');
|
||
if dwAttr <> DWORD(-1) then
|
||
OTemp.S['HIDDEN'] := BooleanToStr((dwAttr and FILE_ATTRIBUTE_HIDDEN) <> 0, 'true', 'false');
|
||
// OTemp.S['AUTHOR'] // {만든 이}
|
||
// OTemp.S['LASTUSER'] // {마지막으로 저장한 사람}
|
||
// OTemp.S['FILETYPE'] // {컨텐츠 타입}
|
||
// OTemp.S['FILECLS'] // {컨텐츠 형식}
|
||
// OTemp.S['PASSWORD'] // {암호적용여부}
|
||
// OTemp.S['ENCRYPTED'] := BooleanToStr(pInfo.bDrm, 'true', 'false');
|
||
// OTemp.S['CORRUPT'] // {깨진파일/정상파일여부}
|
||
|
||
// var i: Integer;
|
||
// var StrList: TStringList;
|
||
// Guard(StrList, TStringList.Create);
|
||
// GetFileProp_all(sDocPath, StrList, true);
|
||
// for i := 0 to StrList.Count - 1 do
|
||
// OTemp.S[StrsReplace(StrList.KeyNames[i], [' '], '_')] := StrList.ValueFromIndex[i];
|
||
|
||
O.O['COMPONENT_METADATA'] := OTemp;
|
||
O.S['COMPONENT_LASTACCESS'] := FormatDateTime('yyyy-mm-dd hh:nn:ss', dtAccess);
|
||
end;
|
||
|
||
O.S['COMPONENT_THUMBNAIL_ID'] := sThumbIds; // 이미지 미리보기 혹은 이미지가 있는경우, 이미지 파일의 파일 고유값. (출력물의 경우 첫 3장 이미지, 캡쳐 이미지 등), 복수개 허용, ";" 구분
|
||
// O.S['SOURCE_IP'] // 이벤트 발생 시점의 에이전트 IP. 단, 외부에서 수신하는 이벤트의 경우, 발송지의 IP가 되고, DESTINATION_URL이 에이전트 IP가 된다
|
||
// O.S['SOURCE_PORT'] // 송신지 사용 포트
|
||
// O.S['EMAIL_SENDER'] // 메일 발신자
|
||
// O.S['DESTINATION_URL'] // 수신지 URL (혹은 IP)
|
||
O.S['DESTINATION_PORT'] := sPrtIp; // 수신지 포트
|
||
// O.S['EMAIL_RECIPIENT'] // 메일 수신자 ; 로 구분
|
||
// O.S['EMAIL_SUBJECT'] // 메일 제목
|
||
O.S['APPLICATION_NAME'] := sPName; // 사용 APP 이름
|
||
O.S['APPLICATION_PATH'] := sPPath;// 사용 APP 절대 경로 (실행 파일 exe의 절대 경로)
|
||
O.S['PRINTER_JOBNAME'] := sDocName;
|
||
OSub := SO;
|
||
OSub.S['PAGEINFO'] := Format('%d/%d', [PrtInfo.dwTotalPage, PrtInfo.dwTotalPage]);
|
||
OSub.S['COLOR'] := BooleanToStr(PrtInfo.bColor, 'true', 'false');
|
||
OSub.S['WARTERMARK'] := BooleanToStr(bWaterMark, 'true', 'false');
|
||
OSub.S['PAPERINFO'] := PrtInfo.sPaperInfo;
|
||
O.O['PRINTER_METADATA'] := OSub; // '{"PAGEINFO": "2/2", "COLOR": "true", "WARTERMARK": "false"}';
|
||
if bWaterMark then
|
||
O.S['RESPONSE_INFO'] := 'WATERMARK';
|
||
O.S['REMOVABLE_NAME'] := sPrtName; // USB등과 같은 매체 혹은 프린터 등과 같은 외부 장치 이름
|
||
// O.S['REMOVABLE_DEVICEID'] := aExptInfo.sSerial; // USB등과 같은 매체 혹은 프린터 등과 같은 외부 장치 Device ID
|
||
// O.S['DEVICE_TYPE'] := IntToStr(Integer(aExptInfo.ReqDevType)); // 의미 없어서 제외 23_0822 12:40:55 kku
|
||
// O.S['REMOVABLE_CLASSID'] // USB등과 같은 매체 혹은 프린터 등과 같은 외부 장치 Class ID
|
||
// O.S['RESPONSE_INFO'] // 적용된 대응 정보 (DELETE, DRM, POPUP, LOG, EXCEPT 등)
|
||
// O.S['RESPONSE_RESULT'] // 적용된 대응 적용 결과 (true / false / pending / decline)
|
||
// O.S['REQUEST_COMMENT'] := sComment; // 사용자가 기입하는 요청 코멘트
|
||
// O.S['REQUEST_DUEDATE'] := sDueDate; // 사용자가 기입하는 예외 기간 (언제 까지. 최종일)
|
||
// O.S['REQUEST_TARGET'] := IntToStr(nTarget); // 사용자가 기입하는 예외 대상 (0 - 해당 pc, 1 - 해당 사용자, 2 - 해당 부서, 3-전체)
|
||
|
||
O.S['actionGroupId'] := sPrtDocId; // 문서번호
|
||
O.I['printCopyCnt'] := PrtInfo.dwCopyCount; // 부수
|
||
O.I['printPageCnt'] := PrtInfo.dwTotalPage; // 장수
|
||
|
||
Result := O;
|
||
except
|
||
on E: Exception do
|
||
ETgException.TraceException(Self, E, 'Fail .. SendEventLog()');
|
||
end;
|
||
end;
|
||
|
||
procedure SendPrintLog(sCode: String);
|
||
var
|
||
O: ISuperObject;
|
||
begin
|
||
try
|
||
O := GetPrintLog(sCode);
|
||
if O = nil then
|
||
begin
|
||
_Trace('Fail .. SendPrintLog() .. 1', 3);
|
||
exit;
|
||
end;
|
||
|
||
_Trace('SendPrintLog > Code=%s, Msg=%s', [sCode, O.S['KEY_SUMMARY']], 3);
|
||
|
||
// JSON 포맷으로 잘 변환되서 보내도록 보완 24_0716 10:32:32 kku
|
||
gMgSvc.EventLog.Push(O.AsJSon);
|
||
except
|
||
on E: Exception do
|
||
ETgException.TraceException(Self, E, 'Fail .. SendEventLog()');
|
||
end;
|
||
end;
|
||
|
||
procedure CancelJob;
|
||
begin
|
||
if (aJob <> nil) and not aJob.WorkEnd then
|
||
begin
|
||
if not bSpoolEnd then
|
||
aJob.GetJobDevInfo(PrtInfo);
|
||
|
||
CurJob_ := nil;
|
||
aJob.WorkEnd := true;
|
||
// SetPrtJobFromHelperApp(aJob, JOB_CONTROL_CANCEL);
|
||
// SetPrtJobFromHelperApp(aJob, JOB_CONTROL_DELETE);
|
||
|
||
aJob.SetPrtJob(JOB_CONTROL_CANCEL);
|
||
// Sleep(1000);
|
||
// aJob.SetPrtJob(JOB_CONTROL_DELETE);
|
||
|
||
// Job을 삭제하면 aJob가 해제 되서 아래처럼 처리함 25_0522 16:33:40 kku
|
||
aJob := nil;
|
||
end;
|
||
end;
|
||
|
||
function CollectPrintInfo(sDocPath, sText, sOcrText, sVioText: String; sThumbIds: String = ''): Boolean;
|
||
var
|
||
sConv: String;
|
||
begin
|
||
Result := false;
|
||
|
||
if bIgrApproval then
|
||
exit;
|
||
|
||
if not IsApproveSupport then
|
||
exit;
|
||
|
||
// 결재자가 할당 되어 있나?
|
||
if not gMgSvc.UseApproval then
|
||
exit;
|
||
|
||
// 결재요청 정책이 있나?
|
||
if not PO.PrintApproval then
|
||
exit;
|
||
|
||
// 후킹방식은 지원하지 않음
|
||
// if IsPrintWaterHook then
|
||
// exit;
|
||
|
||
try
|
||
// 한번 멈추고 진행하도록 변경 25_1203 kku
|
||
// if PO.PrintApprovalPost then
|
||
// begin
|
||
// var PrtEnt: TPrtEnt;
|
||
// ZeroMemory(@PrtEnt, SizeOf(PrtEnt));
|
||
//// PrtEnt.dtReg := Now;
|
||
//// PrtEnt.sId := sId;
|
||
// PrtEnt.sText := sText;
|
||
// PrtEnt.sOcrText := sOcrText;
|
||
// PrtEnt.sVioText := sVioText;
|
||
// PrtEnt.sThumbIds := sThumbIds;
|
||
// PrtEnt.sPName := sPName;
|
||
// PrtEnt.sFPath := sDocPath;
|
||
//
|
||
// PrtEnt.WInfo.sPtrName := PrtInfo.sPtrName;
|
||
// PrtEnt.WInfo.sDocName := PrtInfo.sDocName;
|
||
// PrtEnt.WInfo.DevMode := TTgRtti.SetTypeToStr<TDeviceMode>(PrtInfo.DevMode);
|
||
// PrtEnt.WInfo.dwCopy := PrtInfo.dwCopyCount;
|
||
// PrtEnt.WInfo.dwTotalPage := PrtInfo.dwTotalPage;
|
||
// PrtEnt.WInfo.bPaperV := PrtInfo.bPaperV;
|
||
// PrtEnt.WInfo.bColor := PrtInfo.bColor;
|
||
// PrtEnt.WInfo.sPaperInfo := PrtInfo.sPaperInfo;
|
||
// PrtEnt.WInfo.sPrtIp := PrinterDriverToIP(PrtInfo.sDrvName);
|
||
// PrtEnt.WInfo.sPdfPath := sPort;
|
||
// PrtEnt.WInfo.bUseWM := true;
|
||
// var sUrl: String := gMgSvc.SendApproval(13, @PrtEnt);
|
||
//
|
||
// if sUrl = '' then
|
||
// begin
|
||
// TTgTrace.T('Fail .. CollectPrintInfo(PrintApprovalPost)');
|
||
// exit;
|
||
// end else begin
|
||
// var LogInfo: TLogInfo;
|
||
// ZeroMemory(@LogInfo, SizeOf(LogInfo));
|
||
// LogInfo.sCode := REQUEST_APPROVAL;
|
||
// LogInfo.sDevName := PrtEnt.WInfo.sPtrName;
|
||
// LogInfo.sPath := PrtEnt.WInfo.sDocName;
|
||
// LogInfo.sActionId := PrtEnt.WInfo.sPrtDocId;
|
||
// LogInfo.sSummary := 'Post-Approval Request : Print';
|
||
// gMgSvc.SendEventLogEx(@LogInfo, false);
|
||
//
|
||
// var sHlpExe: String := GetRunExePathDir + DIR_CONF + EXE_HLP;
|
||
// if FileExists(sHlpExe) then
|
||
// begin
|
||
// var O: ISuperObject := SO;
|
||
// O.I['RcvWnd'] := Handle;
|
||
// O.I['Cmd'] := HPCMD_EXECUTE_FILE;
|
||
// O.S['Path'] := gMgSvc.DestIPort + sUrl;
|
||
// SaveJsonObjToFile(O, GetRunExePathDir + DIR_CONF + DAT_PARAM);
|
||
// {$IFDEF DEBUG}
|
||
// ExecutePath(sHlpExe);
|
||
// {$ELSE}
|
||
// ExecuteAppAsUser('explorer.exe', sHlpExe, '', SW_SHOWNORMAL);
|
||
// {$ENDIF}
|
||
// end else
|
||
// ExecutePath(gMgSvc.DestIPort + sUrl);
|
||
//
|
||
// bBlock := false; // 차단 헤제
|
||
// bApprovalPost := true;
|
||
// end;
|
||
// end else
|
||
begin
|
||
sConv := GetRunExePathDir + DIR_CONF + EXE_SPL;
|
||
sEmfDir := GetEmfCopyDir;
|
||
if (DirectoryExists(sEmfDir) or FileExists(sConv)) and not IsHD then
|
||
begin
|
||
if (sSpoolPath = '') or not FileExists(sSpoolPath) then
|
||
begin
|
||
sSpoolPath := GetSpoolCopyPath;
|
||
_Trace('CollectPrintInfo() .. GetSpoolCopyPath() .. Path=%s', [sSpoolPath]);
|
||
end;
|
||
|
||
if FileExists(sSpoolPath) then
|
||
begin
|
||
// 워드는 부수, 한부씩인쇄 값을 가져올 수 없어서 아래처럼 처리
|
||
if CompareText('winword.exe', sPName) = 0 then
|
||
PrtInfo.DevMode.dmCollate := 1;
|
||
|
||
if IsPJL(sSpoolPath) then
|
||
begin
|
||
_Trace('CollectPrintInfo() .. PJL 포맷 확인됨', 1);
|
||
if IsPJLAndLanguagePLW(sSpoolPath) then
|
||
begin
|
||
_Trace('CollectPrintInfo() .. PJL 포맷, PLW 스플 확인됨. 결재 처리 불가.', 1);
|
||
exit;
|
||
end;
|
||
|
||
var bCollate: Boolean;
|
||
var nCopies: Integer := GetQtyFromPJL(sSpoolPath, bCollate);
|
||
if nCopies > 0 then
|
||
begin
|
||
PrtInfo.dwCopyCount := nCopies;
|
||
PrtInfo.DevMode.dmCopies := nCopies;
|
||
if bCollate then
|
||
PrtInfo.DevMode.dmCollate := 1;
|
||
_Trace('CollectPrintInfo() .. PJL 포맷 부수 정보 : %d', [nCopies], 1);
|
||
end;
|
||
end;
|
||
|
||
if aJob <> nil then
|
||
CancelJob;
|
||
|
||
if PrtInfo.sPtrName = '' then
|
||
PrtInfo.sPtrName := sPrtName;
|
||
|
||
if PrtInfo.sDocName = '' then
|
||
PrtInfo.sDocName := sDocName;
|
||
|
||
var pEnt: PPrtEnt := gMgSvc.MgPrint.AddPrintInfo(PrtInfo, sPName, sDocPath, sSpoolPath, sEmfDir, sPort, sText, sOcrText, sVioText, sThumbIds, PO.PrintApprovalPost);
|
||
Result := pEnt <> nil;
|
||
|
||
if Result and (gMgSvc.RcvHwnd <> 0) then
|
||
begin
|
||
SendMessage(gMgSvc.RcvHwnd, WM_POPUP_PRTW_PROGRESS, 3, 0);
|
||
pEnt.WInfo.sPrtDocId := sPrtDocId;
|
||
PostMessage(gMgSvc.RcvHwnd, WM_REQUEST_APPROVAL, 0, NativeInt(pEnt));
|
||
end;
|
||
end;
|
||
end;
|
||
end;
|
||
except
|
||
on E: Exception do
|
||
ETgException.TraceException(Self, E, 'Fail .. OnPtrJobNotify() > CollectPrintInfo()');
|
||
end;
|
||
end;
|
||
|
||
// function CheckBlockException(var sReason: String): Boolean;
|
||
function CheckBlockException: Boolean;
|
||
var
|
||
i: Integer;
|
||
sReason: String; // 차단 이유를 기록하기 위함이었는데 이제 사용하지 않음.. 일단 정리 전에 놔둠
|
||
begin
|
||
Result := false;
|
||
|
||
if PP.sPrinterExcepts <> '' then
|
||
begin
|
||
// 프린터 예외 확인
|
||
Guard(ExcpList, TStringList.Create);
|
||
SplitString(PP.sPrinterExcepts, '|', ExcpList);
|
||
sChk := sPrtName.ToUpper;
|
||
for i := 0 to ExcpList.Count - 1 do
|
||
begin
|
||
if Pos(ExcpList[i], sChk) > 0 then
|
||
begin
|
||
Result := true;
|
||
sReason := 'PTR';
|
||
_Trace('프린터 출력 감지 .. 프린터 종류 예외. Printer=%s, Doc=%s', [sPrtName, sDocName], 2);
|
||
exit;
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
if PO.PrinterIpExcept <> '' then
|
||
begin
|
||
// 프린터 IP 예외 추가 24_1030 13:24:10 kku
|
||
var sChkPrtIp: String := StringReplace(sPrtIp, '_', '.', [rfReplaceAll]);
|
||
var StrList: TStringList;
|
||
Guard(StrList, TStringList.Create);
|
||
SplitString(PO.PrinterIpExcept, '|', StrList);
|
||
for i := 0 to StrList.Count - 1 do
|
||
begin
|
||
if Pos(StrList[i], sChkPrtIp) > 0 then
|
||
begin
|
||
Result := true;
|
||
sReason := 'PTR_IP';
|
||
_Trace('프린터 출력 감지 .. 프린터 IP 예외. Printer=%s, IP=%s, Doc=%s', [sPrtName, sChkPrtIp, sDocName], 2);
|
||
exit;
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
if (PP.sPrintUrlExcepts <> '') and (gMgSvc.ThdWebUrl <> nil) then
|
||
begin
|
||
// 브라우저 URL 확인
|
||
Guard(ExcpList, TStringList.Create);
|
||
SplitString(PP.sPrintUrlExcepts, '|', ExcpList);
|
||
|
||
if (sPName <> '') and (Pos(LowerCase(sPName), BROWSER_LIST) > 0) then // 브라우저인지 확인
|
||
begin
|
||
var sUrl: String := '';
|
||
try
|
||
sUrl := gMgSvc.ThdWebUrl.LastUrl;
|
||
except
|
||
// ..
|
||
end;
|
||
|
||
if sUrl <> '' then
|
||
begin
|
||
sChk := UpperCase(sUrl);
|
||
for i := 0 to ExcpList.Count - 1 do
|
||
begin
|
||
if Pos(ExcpList[i], sChk) > 0 then
|
||
begin
|
||
Result := true;
|
||
sReason := 'URL|' + sUrl;
|
||
_Trace('프린터 출력 감지 .. URL 예외. Printer=%s, URO=%s, Doc=%s', [sPrtName, sUrl, sDocName], 2);
|
||
exit;
|
||
end;
|
||
end;
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
if PP.sPrintAppExcepts <> '' then
|
||
begin
|
||
// App 확인
|
||
Guard(ExcpList, TStringList.Create);
|
||
SplitString(PP.sPrintAppExcepts, '|', ExcpList);
|
||
if sPName <> '' then
|
||
begin
|
||
sChk := UpperCase(sPName);
|
||
for i := 0 to ExcpList.Count - 1 do
|
||
begin
|
||
if Pos(ExcpList[i], sChk) > 0 then
|
||
begin
|
||
Result := true;
|
||
sReason := 'APP|' + sPName;
|
||
_Trace('프린터 출력 감지 .. APP 예외. Printer=%s, PName=%s, Doc=%s', [sPrtName, sPName, sDocName], 2);
|
||
exit;
|
||
end;
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
if PP.sPrintDocExcepts <> '' then
|
||
begin
|
||
// 문서명 확인
|
||
Guard(ExcpList, TStringList.Create);
|
||
SplitString(PP.sPrintDocExcepts, '|', ExcpList);
|
||
sChk := UpperCase(sDocName);
|
||
for i := 0 to ExcpList.Count - 1 do
|
||
begin
|
||
if Pos(ExcpList[i], sChk) > 0 then
|
||
begin
|
||
Result := true;
|
||
sReason := 'APP|' + sPName;
|
||
_Trace('프린터 출력 감지 .. 문서이름 예외. Printer=%s, Doc=%s', [sPrtName, sDocName], 2);
|
||
break;
|
||
end;
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
function ProcessContentFilter_AfterExit(sTargetTxt: String; bIsOcrTxt: Boolean): Boolean;
|
||
var
|
||
i, nHits, nTotalHits,
|
||
nOrCnt, nAndCnt, nHighCnt: Integer;
|
||
sFound, sResult, sSchTxt: String;
|
||
begin
|
||
Result := false;
|
||
if OVio <> nil then
|
||
begin
|
||
// 1. 문서, 2. OCR 두번 시도될 수 있는데, 문서에서 이미 검출된게 있다면 넘어간다
|
||
exit;
|
||
end;
|
||
sFound := '';
|
||
sResult := '';
|
||
nOrCnt := 0;
|
||
nAndCnt := 0;
|
||
nHighCnt := 0;
|
||
sSchTxt := '';
|
||
|
||
nTotalHits := 0;
|
||
|
||
OVioTemp := TSuperObject.Create(stArray);
|
||
for i := 0 to PatternEntList.Count - 1 do
|
||
begin
|
||
sSchTxt := PatternEntList[i].GetSearchText;
|
||
nHits := TTgPcre.GetMatchValues(sTargetTxt, sSchTxt, sFound);
|
||
if nHits > 0 then
|
||
begin
|
||
if gMgSvc.IsNewApi then
|
||
begin
|
||
if nHits < PatternEntList[i].IfCount then
|
||
continue;
|
||
|
||
if sSchTxt.StartsWith('(?<!\d)\d{2}(01|02|03|04|') then
|
||
begin
|
||
nHits := 0;
|
||
// 주민번호 패턴이라면 검증해준다. 25_0526 15:44:47 kku
|
||
var sTemp: String := StringReplace(sFound, '"', '', [rfReplaceAll]);
|
||
var HitList: TStringList;
|
||
Guard(HitList, TStringList.Create);
|
||
SplitString(sTemp, ',', HitList);
|
||
var n: Integer;
|
||
for n := HitList.Count - 1 downto 0 do
|
||
begin
|
||
if not IsValidKoreanRegNo(HitList[n]) then
|
||
begin
|
||
HitList.Delete(n);
|
||
continue;
|
||
end;
|
||
Inc(nHits);
|
||
end;
|
||
|
||
if nHits < PatternEntList[i].IfCount then
|
||
continue;
|
||
|
||
sFound := HitList.CommaText;
|
||
end;
|
||
|
||
if PatternEntList[i].RSeverity = ManagerPattern.rsHigh then
|
||
Inc(nHighCnt)
|
||
else if PatternEntList[i].IsAnd then
|
||
Inc(nAndCnt)
|
||
else
|
||
Inc(nOrCnt);
|
||
|
||
SumString(sResult, Format('%s(%d)', [gMgSvc.MgRule.GetRuleNameFromId(PatternEntList[i].Name), nHits]), ',');
|
||
end else
|
||
SumString(sResult, Format('%s(%d)', [CttCodeToStr(PatternEntList[i].Name), nHits]), ',');
|
||
|
||
Inc(nTotalHits, nHits);
|
||
|
||
OEnt := SO;
|
||
OEnt.S['RULE_ID'] := PatternEntList[i].Name;
|
||
OEnt.S['CNT'] := IntToStr(nHits);
|
||
OEnt.S['TEXT'] := RemoveOverlapWords(sFound);
|
||
|
||
// SumString(sMaskingWords, sFound, ',', true);
|
||
if IsUsePrintMask then
|
||
begin
|
||
if gMgSvc.PrtMaskingStr = '' then
|
||
gMgSvc.PrtMaskingStr := sFound
|
||
else
|
||
gMgSvc.PrtMaskingStr := gMgSvc.PrtMaskingStr + ',' + sFound;
|
||
end;
|
||
|
||
OVioTemp.AsArray.Add(OEnt);
|
||
end;
|
||
end;
|
||
|
||
if OVioTemp.AsArray.Length > 0 then
|
||
begin
|
||
var bFoundOk: Boolean := true;
|
||
if gMgSvc.IsNewApi then
|
||
begin
|
||
if (nHighCnt = 0) and (PatternEntList.AndCount > 0) then
|
||
begin
|
||
// AND 갯수가 다르다면 X
|
||
if nAndCnt <> PatternEntList.AndCount then
|
||
bFoundOk := false;
|
||
|
||
// OR가 조건으로 있는데 검출된 OR가 없다면 X
|
||
if (PatternEntList.AndCount <> PatternEntList.Count) and (nOrCnt = 0) then
|
||
bFoundOk := false;
|
||
end;
|
||
end;
|
||
|
||
if bFoundOk then
|
||
OVio := OVioTemp
|
||
else
|
||
sResult := '';
|
||
end;
|
||
|
||
// if bIsOcrTxt and (nTotalHits = 0) then
|
||
// begin
|
||
// // 이미지 180도 돌려서 한번더 처리.. 시연을 위해 추가됨, 나중에 비활성 필요
|
||
// sFound := '';
|
||
// sResult := '';
|
||
// sExtrOcr180Txt := ExtrTextFromPrintImgFiles(sExportPath, 180);
|
||
//
|
||
// // 이거 사용할거면 위 처리처럼 바꿔야함 24_0214 14:02:37 kku
|
||
// for i := 0 to PrintPatternEnts_.Count - 1 do
|
||
// begin
|
||
// nHits := TTgPcre.GetMatchValues(sExtrOcr180Txt, PrintPatternEnts_[i].GetSearchText, sFound);
|
||
// if nHits > 0 then
|
||
// begin
|
||
// Inc(nTotalHits, nHits);
|
||
// if gMgSvc.IsNewApi then
|
||
// SumString(sResult, Format('%s(%d)', [gMgSvc.MgRule.GetRuleNameFromId(PrintPatternEnts_[i].Name), nHits]), ',')
|
||
// else
|
||
// SumString(sResult, Format('%s(%d)', [CttCodeToStr(PrintPatternEnts_[i].Name), nHits]), ',');
|
||
//
|
||
// OEnt := SO;
|
||
// OEnt.S['RULE_ID'] := PrintPatternEnts_[i].Name;
|
||
// OEnt.S['CNT'] := IntToStr(nHits);
|
||
// OEnt.S['TEXT'] := RemoveOverlapWords(sFound);
|
||
//
|
||
// if OVio = nil then
|
||
// OVio := TSuperObject.Create(stArray);
|
||
// OVio.AsArray.Add(OEnt);
|
||
// end;
|
||
// end;
|
||
//
|
||
// if nTotalHits > 0 then
|
||
// sTargetTxt := sExtrOcr180Txt;
|
||
// end;
|
||
|
||
if OVio <> nil then
|
||
begin
|
||
bBlock := (PP.PrintKind = pkBlock) and (PP.ContentFilter.nHitLimit <= nTotalHits) and not bApprovalPost;
|
||
if bBlock then
|
||
begin
|
||
if CheckBlockException then
|
||
begin
|
||
// 예외 대상인건 검출되도 차단 안함 25_1106 13:40:07 kku
|
||
_Trace('프린터 출력 감지 .. 컨텐츠 감지. 차단 예외됨. Content=%s, Printer=%s, Doc=%s, OCR=%s',
|
||
[sResult, sPrtName, sDocName, BooleanToStr(bIsOcrTxt, 'Y', 'N')], 2);
|
||
bBlock := false;
|
||
exit;
|
||
end;
|
||
|
||
if CollectPrintInfo(sDocPath, sExtrTxt, sExtrOcrTxt, OVio.AsJSon, sThumbIds) then
|
||
begin
|
||
SendPrintLog(LOGCODE_PREVENT_PRINTER);
|
||
|
||
if bIsOcrTxt then
|
||
_Trace('프린터 출력 감지 .. OCR 컨텐츠 감지, 출력 승인 요청. Content=%s, Printer=%s, Doc=%s',
|
||
[sResult, sPrtName, sDocName], 2)
|
||
else
|
||
_Trace('프린터 출력 감지 .. 컨텐츠 감지, 출력 승인 요청. Content=%s, Printer=%s, Doc=%s',
|
||
[sResult, sPrtName, sDocName], 2);
|
||
Result := true;
|
||
exit;
|
||
end;
|
||
|
||
sBlockReson := 'CTT|' + sResult;
|
||
if bIsOcrTxt then
|
||
_Trace('프린터 출력 감지 .. OCR 컨텐츠 감지 차단. Content=%s, Printer=%s, Doc=%s',
|
||
[sResult, sPrtName, sDocName], 2)
|
||
else
|
||
_Trace('프린터 출력 감지 .. 컨텐츠 감지 차단. Content=%s, Printer=%s, Doc=%s',
|
||
[sResult, sPrtName, sDocName], 2);
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
Label
|
||
LB_DoPrint;
|
||
begin
|
||
try
|
||
if (aJob = nil) or aJob.WorkEnd then
|
||
exit;
|
||
|
||
if (aJob.Document <> '') and aJob.Document.Contains(' *BSOne') then
|
||
begin
|
||
// SetPrtJobFromHelperApp(aJob, JOB_CONTROL_RESUME);
|
||
aJob.ResumePrtJob(true);
|
||
exit;
|
||
end;
|
||
|
||
try
|
||
if aJob.IsCustomPause then
|
||
begin
|
||
RefineHookJob;
|
||
pPhJob := nil;
|
||
|
||
ForceDirectories(sWorkDir_);
|
||
bIsWorking_ := true;
|
||
bApprovalPost := false;
|
||
CurJob_ := aJob;
|
||
sPrtDocId := '';
|
||
sPName := '';
|
||
bSpoolEnd := false;
|
||
|
||
sPPath := GetProcessPathFromWndHandle(aJob.Wnd);
|
||
if sPPath <> '' then
|
||
begin
|
||
SetProcessName(ExtractFileName(sPPath));
|
||
sPPath := ExtractFilePath(sPPath);
|
||
end else
|
||
SetProcessName(GetProcessNameFromWndHandle(GetForegroundWindow));
|
||
|
||
aJob.GetJobDevInfo(PrtInfo);
|
||
sPrtName := aJob.PrinterName;
|
||
if sPrtName = '' then
|
||
sPrtName := PrtInfo.sPtrName;
|
||
sDocName := aJob.Document;
|
||
if sDocName = '' then
|
||
sDocName := PrtInfo.sDocName;
|
||
sPrtIp := PrinterDriverToIP(PrtInfo.sDrvName);
|
||
|
||
if (sDocName <> '') and sDocName.Contains(' *BSOne') then
|
||
begin
|
||
// SetPrtJobFromHelperApp(aJob, JOB_CONTROL_RESUME);
|
||
aJob.ResumePrtJob(true);
|
||
exit;
|
||
end;
|
||
|
||
sPort := aJob.Port;
|
||
nTotalPages := aJob.TotalPages;
|
||
|
||
PO := gMgSvc.ModePolicy;
|
||
PPO := gMgSvc.PrefModel;
|
||
PP := PO.Print;
|
||
bCfActive := PP.ContentFilter.bActive;
|
||
OVio := nil;
|
||
|
||
if gMgSvc.IsPrtWaterExcept then
|
||
PP.PrintWater := pwNone;
|
||
|
||
sData := PPO.PrtNameH;
|
||
|
||
// 워터마크 예외 체크
|
||
if PP.PrintWater <> pwNone then
|
||
begin
|
||
var StrList: TStringList;
|
||
Guard(StrList, TStringList.Create);
|
||
|
||
if PO.PrtWtExpUrl <> '' then
|
||
begin
|
||
SplitString(UpperCase(PO.PrtWtExpUrl), '|', StrList);
|
||
if (sPName <> '') and (Pos(LowerCase(sPName), BROWSER_LIST) > 0) and (gMgSvc.ThdWebUrl <> nil) then
|
||
begin
|
||
try
|
||
sChk := UpperCase(gMgSvc.ThdWebUrl.LastUrl);
|
||
except
|
||
// ..
|
||
end;
|
||
|
||
for i := 0 to StrList.Count - 1 do
|
||
if Pos(StrList[i], sChk) > 0 then
|
||
begin
|
||
PP.PrintWater := pwNone;
|
||
break;
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
if (PP.PrintWater <> pwNone) and (PO.PrtWtExpDocName <> '') then
|
||
begin
|
||
SplitString(UpperCase(PO.PrtWtExpDocName), '|', StrList);
|
||
sChk := UpperCase(PrtInfo.sDocName);
|
||
for i := 0 to StrList.Count - 1 do
|
||
if Pos(StrList[i], sChk) > 0 then
|
||
begin
|
||
PP.PrintWater := pwNone;
|
||
break;
|
||
end;
|
||
end;
|
||
|
||
if (PP.PrintWater <> pwNone) and (PO.PrtWtExpPrtName <> '') then
|
||
begin
|
||
SplitString(UpperCase(PO.PrtWtExpPrtName), '|', StrList);
|
||
sChk := UpperCase(PrtInfo.sPtrName);
|
||
for i := 0 to StrList.Count - 1 do
|
||
if Pos(StrList[i], sChk) > 0 then
|
||
begin
|
||
PP.PrintWater := pwNone;
|
||
break;
|
||
end;
|
||
end;
|
||
|
||
if (PP.PrintWater <> pwNone) and (PO.PrtWtExpProcName <> '') then
|
||
begin
|
||
SplitString(UpperCase(PO.PrtWtExpProcName), '|', StrList);
|
||
sChk := UpperCase(sPName);
|
||
for i := 0 to StrList.Count - 1 do
|
||
if Pos(StrList[i], sChk) > 0 then
|
||
begin
|
||
PP.PrintWater := pwNone;
|
||
break;
|
||
end;
|
||
end;
|
||
|
||
if gMgSvc.MgPwe.CountHash > 0 then
|
||
begin
|
||
_Trace('프린트 워터마크 예외 경로 확인...', 2);
|
||
sDocPath := sDocName;
|
||
if not FileExists(sDocPath) then
|
||
begin
|
||
sDocPath := FindPrintingFile(sDocPath);
|
||
_Trace('프린트 워터마크 예외 경로 확인 : FindPrintingFile() .. Path="%s"', [sDocPath], 2);
|
||
end;
|
||
|
||
if (sDocPath = '') and (CompareText('notepad.exe', sPName) = 0) then
|
||
begin
|
||
// Windows 11 메모장에서 문서 이름이 현재 파일이 아닌 단순 "메모장"으로 뜨게된다. 23_0322 10:57:54 kku
|
||
sDocPath := GetWindowCaption(GetForegroundWindow);
|
||
sDocPath := FindPrintingFile(sDocPath, CompareText(sPName, 'excel.exe') = 0);
|
||
_Trace('프린트 워터마크 예외 경로 확인 : FindPrintingFile() 22.. Path="%s"', [sDocPath], 2);
|
||
end;
|
||
|
||
if FileExists(sDocPath) then
|
||
begin
|
||
_Trace('프린트 워터마크 예외 확인 .. Path="%s"', [sDocPath], 2);
|
||
if gMgSvc.MgPwe.HasFileHash(sDocPath) then
|
||
begin
|
||
_Trace('프린트 워터마크 예외 확인됨 .. Path="%s"', [sDocPath], 2);
|
||
PP.PrintWater := pwNone;
|
||
end;
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
SendMessage(gMgSvc.RcvHwnd, WM_POPUP_PRTW_PROGRESS, 1, 0);
|
||
|
||
sEmfDir := '';
|
||
sSpoolPath := '';
|
||
|
||
if ( (PP.PrintWater <> pwNone) or PP.bCollectOutput or PO.IsPrtCollectThum ) then
|
||
begin
|
||
// if PP.PrintWater <> pwNone then
|
||
// CancelJob;
|
||
|
||
// CJ에서 프린트 정지 하면 스플이 너무 빨리 사라지는 현상이 있어서 미리 구해놓음.. 24_1212 16:11:51 kku
|
||
// _Trace('ttttttttt, Path=%s', [GetSpoolCopyPath('WTask')], 9);
|
||
sSpoolPath := GetSpoolCopyPath('WTask');
|
||
_Trace('GetSpoolCopyPath(1) .. Path=%s', [sSpoolPath]);
|
||
|
||
if FileExists(sSpoolPath) and
|
||
not IsPrintWaterHook and
|
||
(PP.PrintWater <> pwNone) then
|
||
CancelJob;
|
||
|
||
sEmfDir := GetEmfCopyDir;
|
||
end;
|
||
|
||
// 후킹 처리로 생성된 값이 있는지 먼저 확인 25_1103 10:37:28 kku
|
||
sData := gMgSvc.RecentUserSid + '\Software\eCrmHomeEdition';
|
||
if sPrtDocId = '' then
|
||
begin
|
||
sPrtDocId := GetRegValueAsString(HKEY_USERS, sData, 'PrtDocId');
|
||
if sPrtDocId = '' then
|
||
begin
|
||
sData := gMgSvc.RecentUserSid + '\Software\WOW6432Node\eCrmHomeEdition';
|
||
sPrtDocId := GetRegValueAsString(HKEY_USERS, sData, 'PrtDocId');
|
||
end;
|
||
end;
|
||
// 이거 유지할지 고민... 25_1210 18:35:40 kku
|
||
DelRegValue(HKEY_USERS, gMgSvc.RecentUserSid + '\Software\eCrmHomeEdition', 'PrtDocId');
|
||
DelRegValue(HKEY_USERS, gMgSvc.RecentUserSid + '\Software\WOW6432Node\eCrmHomeEdition', 'PrtDocId');
|
||
|
||
if sPrtDocId = '' then
|
||
sPrtDocId := StrsReplace(TGUID.NewGuid.ToString, ['{', '}'], '');
|
||
|
||
try
|
||
gMgSvc.PrtMaskingStr := '';
|
||
sDocPath := '';
|
||
sExtrOcrTxt := '';
|
||
sExtrOcr180Txt := '';
|
||
sThumbIds := '';
|
||
bWaterMark := false;
|
||
bIsDrm := false;
|
||
bIgrApproval := false;
|
||
|
||
_Trace('프린터 출력 감지 .. Printer=%s, Doc=%s', [sPrtName, sDocName], 2);
|
||
bBlock := (PP.PrintKind = pkBlock) and not bCfActive;
|
||
sBlockReson := '';
|
||
|
||
// 결재요청 예외 체크
|
||
if IsApproveSupport and gMgSvc.UseApproval and PO.PrintApproval then
|
||
begin
|
||
var StrList: TStringList;
|
||
Guard(StrList, TStringList.Create);
|
||
|
||
if PO.PrtApvExpUrl <> '' then
|
||
begin
|
||
SplitString(UpperCase(PO.PrtApvExpUrl), '|', StrList);
|
||
if (sPName <> '') and (Pos(LowerCase(sPName), BROWSER_LIST) > 0) and (gMgSvc.ThdWebUrl <> nil) then
|
||
begin
|
||
try
|
||
sChk := UpperCase(gMgSvc.ThdWebUrl.LastUrl);
|
||
except
|
||
// ..
|
||
end;
|
||
|
||
for i := 0 to StrList.Count - 1 do
|
||
if Pos(StrList[i], sChk) > 0 then
|
||
begin
|
||
bIgrApproval := true;
|
||
break;
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
if not bIgrApproval and (PO.PrtApvExpDocName <> '') then
|
||
begin
|
||
SplitString(UpperCase(PO.PrtApvExpDocName), '|', StrList);
|
||
sChk := UpperCase(PrtInfo.sDocName);
|
||
for i := 0 to StrList.Count - 1 do
|
||
if Pos(StrList[i], sChk) > 0 then
|
||
begin
|
||
bIgrApproval := true;
|
||
break;
|
||
end;
|
||
end;
|
||
|
||
if not bIgrApproval and (PO.PrtApvExpPrtName <> '') then
|
||
begin
|
||
SplitString(UpperCase(PO.PrtApvExpPrtName), '|', StrList);
|
||
sChk := UpperCase(PrtInfo.sPtrName);
|
||
for i := 0 to StrList.Count - 1 do
|
||
if Pos(StrList[i], sChk) > 0 then
|
||
begin
|
||
bIgrApproval := true;
|
||
break;
|
||
end;
|
||
end;
|
||
|
||
if not bIgrApproval and (PO.PrtApvExpProcName <> '') then
|
||
begin
|
||
SplitString(UpperCase(PO.PrtApvExpProcName), '|', StrList);
|
||
sChk := UpperCase(sPName);
|
||
for i := 0 to StrList.Count - 1 do
|
||
if Pos(StrList[i], sChk) > 0 then
|
||
begin
|
||
bIgrApproval := true;
|
||
break;
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
Guard(PatternEntList, TPatternEntList.Create);
|
||
if bCfActive then
|
||
begin
|
||
if gMgSvc.PrintPatterns.Contains('scanoption') then
|
||
gMgSvc.SetPatternList(gMgSvc.PrintPatterns, PatternEntList)
|
||
else
|
||
gMgSvc.SetRuleToPtrnList(gMgSvc.PrintPatterns, PatternEntList);
|
||
end;
|
||
|
||
sDocPath := sDocName;
|
||
if not FileExists(sDocPath) then
|
||
sDocPath := FindPrintingFile(sDocPath);
|
||
|
||
var bForceSpoolWater: Boolean := false; // not IsPrintWaterHookForce and (CUSTOMER_TYPE = CUSTOMER_CJONS) and (Pos('CANON', UpperCase(PrtInfo.sPtrName)) = 0);
|
||
// if (bForceSpoolWater or not bIsHook) and (CUSTOMER_TYPE = CUSTOMER_GEC) and (PP.PrintWater <> pwNone) then
|
||
if CUSTOMER_TYPE = CUSTOMER_GEC then
|
||
begin
|
||
// sDocPath := 'D:\temp3\abc_e.docx'; //FindPrintingFile(sDocPath);
|
||
|
||
// 기본 대외비 처리 24_0513 16:28:34 kku
|
||
var sLabelName: String := 'None';
|
||
gMgSvc.RecentLabel := '대외비(Restricted)';
|
||
|
||
{$IFDEF DEBUG}
|
||
// 출력 시 AIP 원문 수집 테스트
|
||
// sDocPath := 'D:\temp3\123_label.docx';
|
||
{$ENDIF}
|
||
if FileExists(sDocPath) then
|
||
begin
|
||
// 오피스 파일은 열려 있는 상태에서 레이블 확인이 불가능하다. 복사해서 처리 24_0513 16:43:49 kku
|
||
var sTaskDir: String := sWorkDir_ + 'HEC\';
|
||
if ForceDirectories(sTaskDir) then
|
||
begin
|
||
var sDest: String := sTaskDir + ExtractFileName(sDocPath);
|
||
if CopyFileAfOpenCheck(sDocPath, sDest) then
|
||
begin
|
||
var O: ISuperObject := SO;
|
||
O.S['src'] := sDest;
|
||
O.S['dst'] := sDest + '.tmp';
|
||
O.S['regval'] := 'LabelA';
|
||
// O.S['ssid'] := RecentUserSid; // 비활성화 해서 HKEY_LOCAL_MACHINE 여기서 만들어지게
|
||
|
||
DelRegValue(HKEY_LOCAL_MACHINE, 'SOFTWARE\eCrmHomeEdition', 'LabelA');
|
||
if SendData(gMgSvc.FindAipMdWnd, 4, O.AsString) = 10 then
|
||
begin
|
||
// sLabelName := GetRegValueAsString(HKEY_USERS, RecentUserSid + 'SOFTWARE\eCrmHomeEdition', 'ALabel');
|
||
sLabelName := GetRegValueAsString(HKEY_LOCAL_MACHINE, 'SOFTWARE\eCrmHomeEdition', 'LabelA');
|
||
if sLabelName <> '' then
|
||
DelRegValue(HKEY_LOCAL_MACHINE, 'SOFTWARE\eCrmHomeEdition', 'LabelA');
|
||
|
||
if (sLabelName = '') or (Pos('anyuser', sLabelName.ToLower) > 0) then
|
||
begin
|
||
PP.PrintWater := pwNone;
|
||
gMgSvc.RecentLabel := '';
|
||
end else begin
|
||
gMgSvc.RecentLabel := sLabelName;
|
||
bIsDrm := true;
|
||
end;
|
||
end;
|
||
|
||
DeleteFile(PChar(sDest));
|
||
end;
|
||
end;
|
||
end else
|
||
_Trace('Fail .. FindPrintingFile() .000. Path="%s"', [sDocPath]);
|
||
|
||
_Trace('프린트 워터마크 레이블 확인 : FindPrintingFile() .. Path="%s", Label=%s', [sDocPath, gMgSvc.RecentLabel], 2);
|
||
end else
|
||
if fas_ <> nil then
|
||
begin
|
||
if FileExists(sDocPath) then
|
||
begin
|
||
var sTaskDir: String := sWorkDir_ + 'HEC\';
|
||
if ForceDirectories(sTaskDir) then
|
||
begin
|
||
var sDest: String := sTaskDir + ExtractFileName(sDocPath);
|
||
if CopyFileAfOpenCheck(sDocPath, sDest) then
|
||
begin
|
||
var nEncType: Integer := fas_.GetFileType(sDest);
|
||
bIsDrm := (nEncType = 103) {FSN}; // or (nEncType = 106) {NX};
|
||
if bIsDrm then
|
||
_Trace('Fasoo 암호화 확인 : Path="%s"', [sDocPath], 2);
|
||
DeleteFile(PChar(sDest));
|
||
end;
|
||
end;
|
||
end else
|
||
_Trace('Fail .. FindPrintingFile() .111222. Path="%s"', [sDocPath]);
|
||
end else
|
||
if UseSoftcampDecrypt then
|
||
begin
|
||
if FileExists(sDocPath) then
|
||
begin
|
||
// 오피스 파일은 열려 있는 상태에서 레이블 확인이 불가능하다. 복사해서 처리 24_0513 16:43:49 kku
|
||
var sTaskDir: String := sWorkDir_ + 'HEC\';
|
||
if ForceDirectories(sTaskDir) then
|
||
begin
|
||
var sDest: String := sTaskDir + ExtractFileName(sDocPath);
|
||
if CopyFileAfOpenCheck(sDocPath, sDest) then
|
||
begin
|
||
// bIsDrm := DS_IsEncrypted(sDest);
|
||
bIsDrm := DSCSIsEncryptedFile(sDest) = 1;
|
||
if bIsDrm then
|
||
_Trace('소프트캠프 암호화 확인 : Path="%s"', [sDocPath], 2);
|
||
DeleteFile(PChar(sDest));
|
||
end;
|
||
end;
|
||
end else
|
||
_Trace('Fail .. FindPrintingFile() .111. Path="%s"', [sDocPath]);
|
||
end;
|
||
|
||
if not bIsDrm then
|
||
begin
|
||
var sTaskDir: String := sWorkDir_ + 'HEC\';
|
||
var sDest: String := sTaskDir + ExtractFileName(sDocPath);
|
||
if CopyFileAfOpenCheck(sDocPath, sDest) then
|
||
begin
|
||
bIsDrm := TTgEncrypt.CheckSign(sDest, SIG_DRM);
|
||
if bIsDrm then
|
||
_Trace('BSOne 암호화 확인 : Path="%s"', [sDocPath], 2);
|
||
DeleteFile(PChar(sDest));
|
||
end;
|
||
end;
|
||
|
||
// if bBlock then
|
||
begin
|
||
if not bBlock and PP.bDateBlock then
|
||
begin
|
||
var dtNow := Now;
|
||
if ( (CompareDateTime(PP.dtBlockB, dtNow) = -1) and
|
||
(CompareDateTime(PP.dtBlockE, dtNow) = 1) ) then
|
||
begin
|
||
bBlock := true;
|
||
sBlockReson := 'DATE';
|
||
_Trace('프린터 출력 감지 .. 기간 차단. Printer=%s, Doc=%s', [sPrtName, sDocName], 2);
|
||
end;
|
||
end;
|
||
|
||
if not bBlock then
|
||
begin
|
||
if ShowTestFun and
|
||
( gMgSvc.SharePcPrintBlock or
|
||
gMgSvc.WSDPortPrintBlock or
|
||
gMgSvc.TcpIpPrintBlock or
|
||
gMgSvc.PrintSavingBlock ) then
|
||
begin
|
||
// _Trace('출력 제어 체크 ..', 5);
|
||
// var sHpExe: String := GetRunExePathDir + DIR_CONF + EXE_HP;
|
||
// var sPrtInfoPath: String := sWorkDir_ + '#pi.dat';
|
||
// if FileExists(sHpExe) then
|
||
// begin
|
||
// // "공유PC" 프린터 정보를 가져오기 위해서는 이렇게 처리해야함 25_1127 14:19:52 kku
|
||
// _Trace('출력 제어 체크 .. 사용자 권한으로 프린터 정보 요청 ..', 5);
|
||
// var O: ISuperObject := SO;
|
||
// var sParam: String := GetRunExePathDir + DIR_CONF + '#ppi.dat';
|
||
// O.I['Cmd'] := HPCDM_PRINT_INFO_LIST;
|
||
// O.S['P'] := sPrtInfoPath;
|
||
// SaveJsonObjToFile(O, sParam);
|
||
//
|
||
// {$IFDEF DEBUG}
|
||
// ExecuteAppWaitUntilTerminate(sHpExe, Format('-p "%s"', [sParam]), SW_HIDE);
|
||
// {$ELSE}
|
||
// var PInfo: TProcessInformation := ExecuteAppAsUser('explorer.exe', sHpExe, Format('-p "%s"', [sParam]), SW_HIDE);
|
||
//// Sleep(1000);
|
||
// if PInfo.dwProcessId <> 0 then
|
||
// begin
|
||
// var dwExecuteTick: DWORD := GetTickCount;
|
||
// while true do
|
||
// begin
|
||
// if WaitForSingleObject(PInfo.hProcess, 50) <> WAIT_TIMEOUT then
|
||
// break;
|
||
//
|
||
// if (GetTickCount - dwExecuteTick) > 3000 then
|
||
// begin
|
||
// TerminateProcess(PInfo.hProcess, 999);
|
||
// exit;
|
||
// end;
|
||
// end;
|
||
// end;
|
||
// {$ENDIF}
|
||
// DeleteFile(PChar(sParam));
|
||
//
|
||
// if FileExists(sPrtInfoPath) then
|
||
// _Trace('출력 제어 체크 .. 사용자 권한으로 프린터 정보 요청 .. OK', 5);
|
||
// end;
|
||
|
||
var PrintersInfo: TPrintersInfo;
|
||
var pPrtInfo: PPrinterInfo;
|
||
Guard(PrintersInfo, TPrintersInfo.Create);
|
||
// if FileExists(sPrtInfoPath) then
|
||
// begin
|
||
// PrintersInfo.LoadFromFile(sPrtInfoPath);
|
||
// DeleteFile(PChar(sPrtInfoPath));
|
||
// end else
|
||
PrintersInfo.RefreshList;
|
||
|
||
pPrtInfo := PrintersInfo.GetPrtInfoByPrtName(sPrtName);
|
||
if pPrtInfo <> nil then
|
||
begin
|
||
if gMgSvc.SharePcPrintBlock then
|
||
begin
|
||
if pPrtInfo.PortType = PTShared then
|
||
begin
|
||
bBlock := true;
|
||
sBlockReson := 'SHARE';
|
||
_Trace('프린터 출력 감지 .. 공유PC를 통한 출력 차단. Printer=%s, Doc=%s', [sPrtName, sDocName], 2);
|
||
end;
|
||
end;
|
||
|
||
if gMgSvc.WSDPortPrintBlock then
|
||
begin
|
||
if pPrtInfo.PortType = PTWsd then
|
||
begin
|
||
bBlock := true;
|
||
sBlockReson := 'WSD';
|
||
_Trace('프린터 출력 감지 .. WSD Port로 연결된 프린터 차단. Printer=%s, Doc=%s', [sPrtName, sDocName], 2);
|
||
end;
|
||
end;
|
||
|
||
if gMgSvc.TcpIpPrintBlock then
|
||
begin
|
||
if pPrtInfo.PortType <> PTTcpIp then
|
||
begin
|
||
bBlock := true;
|
||
sBlockReson := 'NoTCPIP';
|
||
_Trace('프린터 출력 감지 .. TCP/IP로 설정이 안된 프린터 차단. Printer=%s, Doc=%s', [sPrtName, sDocName], 2);
|
||
end;
|
||
end;
|
||
|
||
if gMgSvc.PrintSavingBlock then
|
||
begin
|
||
if pPrtInfo.bIsPowerSaveMode then
|
||
begin
|
||
bBlock := true;
|
||
sBlockReson := 'PSAVING';
|
||
_Trace('프린터 출력 감지 .. 절전모드 상태 프린터 차단. Printer=%s, Doc=%s', [sPrtName, sDocName], 2);
|
||
end;
|
||
end;
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
if bBlock then
|
||
bBlock := not CheckBlockException;
|
||
|
||
// if PP.PrintKind = pkBlock then
|
||
// bCfActive := bCfActive and bBlock; // 차단 정책 ON일때 예외일 경우 컨텐츠 필터도 하지 않음 25_0513 17:57:38 kku
|
||
|
||
if ( bCfActive and
|
||
(PatternEntList.Count > 0) ) or
|
||
PP.bCollectOutput then
|
||
begin
|
||
sExtrTxt := '';
|
||
sDocPath := sDocName;
|
||
_Trace('프린터 출력 감지 .. 원본 파일에서 컨텐츠 추출 .. Path=%s, Printer=%s, Doc=%s', [sDocPath, sPrtName, sDocName], 2);
|
||
if not FileExists(sDocPath) then
|
||
begin
|
||
sDocPath := FindPrintingFile(sDocPath, CompareText(sPName, 'excel.exe') = 0);
|
||
_Trace('FindPrintingFile() .. Path="%s"', [sDocPath], 2);
|
||
end;
|
||
|
||
if (sDocPath = '') and (CompareText('notepad.exe', sPName) = 0) then
|
||
begin
|
||
// Windows 11 메모장에서 문서 이름이 현재 파일이 아닌 단순 "메모장"으로 뜨게된다. 23_0322 10:57:54 kku
|
||
sDocPath := GetWindowCaption(GetForegroundWindow);
|
||
sDocPath := FindPrintingFile(sDocPath);
|
||
|
||
if sDocPath = '' then
|
||
begin
|
||
// 윈 11에서 추가 처리
|
||
sDocPath := StrsReplace(sDocName, [' - 메모장', ' - Notepad'], '');
|
||
sDocPath := FindPrintingFile(sDocPath);
|
||
end;
|
||
|
||
_Trace('FindPrintingFile() 22.. Path="%s"', [sDocPath], 2);
|
||
end;
|
||
|
||
_Trace('원본 파일에서 컨텐츠 추출 .. 1, Path = "%s"', [sDocPath], 4);
|
||
if FileExists(sDocPath) then
|
||
begin
|
||
_Trace('원본 파일에서 컨텐츠 추출 .. 2', 4);
|
||
// todo : DRM 체크. 아래는 사용중인 파일로 오류남. 보완 필요 24_0514 11:06:05 kku
|
||
// if not bIsDrm then
|
||
// bIsDrm := TTgEncrypt.CheckSign(sDocPath, SIG_DRM);
|
||
|
||
var sTaskPath: String := sWorkDir_ + 'HEC\';
|
||
if ForceDirectories(sTaskPath) then
|
||
begin
|
||
sTaskPath := sTaskPath + ExtractFileName(sDocPath);
|
||
try
|
||
if bIsDrm then
|
||
begin
|
||
{$IFDEF DEBUG}
|
||
// 출력 시 AIP 원문 수집 테스트
|
||
// sDocPath := 'D:\temp3\123_label.docx';
|
||
{$ENDIF}
|
||
try
|
||
case CUSTOMER_TYPE of
|
||
CUSTOMER_GEC :
|
||
begin
|
||
// AIP
|
||
if CopyFileAfOpenCheck(sDocPath, sTaskPath) then
|
||
begin
|
||
var sTaskDecPath: String := ExtractFilePath(sTaskPath) + 'd_' + ExtractFileName(sTaskPath);
|
||
var O: ISuperObject := SO;
|
||
O.S['src'] := sTaskPath;
|
||
O.S['dst'] := sTaskDecPath;
|
||
if SendData(gMgSvc.FindAipMdWnd, 2, O.AsString) = 10 then
|
||
begin
|
||
sExtrTxt := ExtrTextFromFile(sTaskDecPath, true);
|
||
_Trace('원본 파일에서 컨텐츠 추출 .. 3 .. 성공 (AIP 복호화), Length = %d', [Length(sExtrTxt)], 4);
|
||
end;
|
||
|
||
if FileExists(sTaskDecPath) then
|
||
DeleteFile(PChar(sTaskDecPath));
|
||
end;
|
||
end;
|
||
else begin
|
||
if UseSoftcampDecrypt then
|
||
begin
|
||
var sTaskDecPath: String := ExtractFilePath(sTaskPath) + 'd_' + ExtractFileName(sTaskPath);
|
||
if CopyFileAfOpenCheck(sDocPath, sTaskPath) then
|
||
begin
|
||
if DSCSForceDecryptFile(sTaskPath, sTaskDecPath) = 1 then
|
||
begin
|
||
sExtrTxt := ExtrTextFromFile(sTaskDecPath, true);
|
||
_Trace('원본 파일에서 컨텐츠 추출 .. 3 .. 성공 (SC 복호화), Length = %d', [Length(sExtrTxt)], 4);
|
||
end else
|
||
_Trace('원본 파일에서 컨텐츠 추출 .. 3 .. 실패 (SC 복호화), Length = %d', [Length(sExtrTxt)], 4);
|
||
end;
|
||
|
||
if FileExists(sTaskDecPath) then
|
||
DeleteFile(PChar(sTaskDecPath));
|
||
end else
|
||
if fas_ <> nil then
|
||
begin
|
||
var sTaskDecPath: String := ExtractFilePath(sTaskPath) + 'd_' + ExtractFileName(sTaskPath);
|
||
if CopyFileAfOpenCheck(sDocPath, sTaskPath) then
|
||
begin
|
||
if fas_.DoExtract(sTaskPath, sTaskDecPath) then
|
||
begin
|
||
sExtrTxt := ExtrTextFromFile(sTaskDecPath, true);
|
||
_Trace('원본 파일에서 컨텐츠 추출 .. 3 .. 성공 (Fasoo 복호화), Length = %d', [Length(sExtrTxt)], 4);
|
||
end else
|
||
_Trace('원본 파일에서 컨텐츠 추출 .. 3 .. 실패 (Fasoo 복호화), Length = %d', [Length(sExtrTxt)], 4);
|
||
end;
|
||
|
||
if FileExists(sTaskDecPath) then
|
||
DeleteFile(PChar(sTaskDecPath));
|
||
end else begin
|
||
var dec: TTgDrmDec;
|
||
Guard(dec, TTgDrmDec.Create(sTaskPath));
|
||
if dec.DecryptToFile(GetMK, sDocPath) then
|
||
begin
|
||
sExtrTxt := ExtrTextFromFile(sTaskPath, true);
|
||
_Trace('원본 파일에서 컨텐츠 추출 .. 3 .. 성공 (BS 복호화), Length = %d', [Length(sExtrTxt)], 4);
|
||
end;
|
||
end;
|
||
end;
|
||
end;
|
||
except
|
||
on E: Exception do
|
||
ETgException.TraceException(Self, E, Format('프린터 출력 감지 .. 원본파일 복호화 실패.. Path=%s', [sDocPath]));
|
||
end;
|
||
end else begin
|
||
// 오피스 파일은 열려 있으면 제대로 처리 안될 가능성 있음 24_0718 09:44:06 kku
|
||
if CopyFileAfOpenCheck(sDocPath, sTaskPath) then
|
||
begin
|
||
sExtrTxt := ExtrTextFromFile(sTaskPath, true);
|
||
_Trace('원본 파일에서 컨텐츠 추출 .. 3 .. 성공, Length = %d', [Length(sExtrTxt)], 4);
|
||
end;
|
||
end;
|
||
finally
|
||
if FileExists(sTaskPath) then
|
||
DeleteFile(PChar(sTaskPath));
|
||
end;
|
||
end;
|
||
|
||
if sExtrTxt <> '' then
|
||
_Trace('프린터 출력 감지 .. 원본 파일에서 컨텐츠 추출 성공 .. ' +
|
||
'Path=%s, Printer=%s, Doc=%s', [sDocPath, sPrtName, sDocName], 2);
|
||
end;
|
||
end;
|
||
|
||
if not bBlock and bCfActive and (PatternEntList.Count > 0) then
|
||
begin
|
||
// 출력 대상 파일에서 컨텐츠 필터 시작 =====================================
|
||
|
||
// 출력 정보 전송 23_0223 13:38:21 kku
|
||
// if FileExists(sDocPath) then
|
||
// sChk := ExtractFileName(sDocPath)
|
||
// else
|
||
// sChk := sDocName;
|
||
// SendReqPrint(sExtrTxt, sChk, sPName);
|
||
// DirectSendPtrFile(sDocPath);
|
||
|
||
// 출력 대상 파일에서 컨텐츠 필터 끝 =======================================
|
||
|
||
// 개인정보 확인
|
||
if sExtrTxt <> '' then
|
||
begin
|
||
if ProcessContentFilter_AfterExit(sExtrTxt, false) then
|
||
exit;
|
||
end else
|
||
_Trace('프린터 출력 감지 .. 원본 파일에서 컨텐츠 추출 실패 .. Path=%s, Printer=%s, Doc=%s', [sDocPath, sPrtName, sDocName], 2);
|
||
end;
|
||
end;
|
||
|
||
SendMessage(gMgSvc.RcvHwnd, WM_POPUP_PRTW_PROGRESS, 2, 0);
|
||
// todo : 출력물 수집
|
||
// sSpoolPath := '';
|
||
// if (sBlockReson = '') and (PP.bCollectOutput and (PP.PrintWater = pwNone)) then // 프린터 워터마크 처리 전 전송하도록 기능 수정 23_0913 13:05:37 kku
|
||
if PO.IsPrtCollectThum then // 프린터 워터마크 처리 전 전송하도록 기능 수정 23_0913 13:05:37 kku
|
||
begin
|
||
sEmfDir := GetEmfCopyDir;
|
||
if DirectoryExists(sEmfDir) then
|
||
begin
|
||
SendMessage(gMgSvc.RcvHwnd, WM_POPUP_PRINTWATER_PROGRESS, 0, 0);
|
||
SendMessage(gMgSvc.RcvHwnd, WM_POPUP_PRTW_PROGRESS, 2, 0);
|
||
|
||
// emf를 png로 변환 후 텍스트 추출
|
||
if PO.Print.bCollectOutput then
|
||
begin
|
||
var bDoExtr: Boolean := true;
|
||
var ExtList: TStringList := gMgSvc.PrefModel.PrtOcrTxtExtList;
|
||
if ExtList.Count > 0 then
|
||
begin
|
||
if FileExists(sDocPath) then
|
||
begin
|
||
var sExt: String := GetFileExt(sDocPath).ToUpper;
|
||
if ExtList.IndexOf(sExt) = - 1 then
|
||
bDoExtr := false;
|
||
end else
|
||
if ExtList.IndexOf('*NF') = -1 then
|
||
bDoExtr := false;
|
||
end;
|
||
|
||
if bDoExtr then
|
||
begin
|
||
_Trace('출력 이미지에서 텍스트 추출(E) ..', 3);
|
||
sExtrOcrTxt := ExtrTextFromPrintEmfFiles(sEmfDir);
|
||
_Trace('출력 이미지에서 텍스트 추출(E) .. OK', 3);
|
||
end;
|
||
SendMessage(gMgSvc.RcvHwnd, WM_POPUP_PRTW_PROGRESS, 2, 0);
|
||
end;
|
||
// emf를 png로 변환 후 수집
|
||
sThumbIds := gMgSvc.SendPrintEmfFiles(sEmfDir, sWorkDir_ + 'PrtThum\', PO.PrtCollThumLimit, crtDelete);
|
||
|
||
if bCfActive then
|
||
begin
|
||
if ProcessContentFilter_AfterExit(sExtrOcrTxt, true) then
|
||
exit;
|
||
end;
|
||
end else
|
||
if bIsSplAnal then
|
||
begin
|
||
var sConv: String := GetRunExePathDir + DIR_CONF + EXE_SPL;
|
||
if FileExists(sConv) and not IsHD then // HEC, GEC에서 OCR 처리 안함 24_0723 10:31:59 kku
|
||
begin
|
||
if (sSpoolPath = '') or not FileExists(sSpoolPath) then
|
||
begin
|
||
sSpoolPath := GetSpoolCopyPath;
|
||
_Trace('GetSpoolCopyPath(2) .. Path=%s', [sSpoolPath]);
|
||
end;
|
||
|
||
if FileExists(sSpoolPath) then
|
||
begin
|
||
if bIsSplAnal and IsPJLAndLanguagePLW(sSpoolPath) then
|
||
bIsSplAnal := false;
|
||
|
||
if not IsPrintWaterHook and (PP.PrintWater <> pwNone) then
|
||
begin
|
||
// 분석이 오래 걸려서 미리 취소 시켜준다. 25_0417 09:22:20 kku
|
||
CancelJob;
|
||
end;
|
||
|
||
var sFName: String := GetValidFileName(ExtractFileName(sDocName), '#');
|
||
var sExportPath: String := ExtractFilePath(sSpoolPath) + sFName + '.png';
|
||
|
||
if PrtInfo.sPtrName = '' then
|
||
PrtInfo.sPtrName := sPrtName;
|
||
|
||
if PrtInfo.sDocName = '' then
|
||
PrtInfo.sDocName := sDocName;
|
||
|
||
// 브라우저에서 실물 프린터 출력 시 선명도 많이 떨어진다..
|
||
// 아래처럼 옵션 추가 24_0731 15:44:42 kku
|
||
if bIsSplAnal then
|
||
SendMessage(gMgSvc.RcvHwnd, WM_POPUP_PRINTWATER_PROGRESS, 4, 0);
|
||
|
||
if bIsSplAnal and
|
||
ExtractImagesFromSpool(sConv, '-$ 65XSD4234455S4PLET58 -unicode -imgxres 150 -imgyres 150 -imgbitcount 8 "%s" "%s"',
|
||
sSpoolPath, 'col_', sExportPath, 300000, 0{PO.PrtCollThumLimit}, PP.PrintWater = pwNone) then
|
||
begin
|
||
SendMessage(gMgSvc.RcvHwnd, WM_POPUP_PRINTWATER_PROGRESS, 0, 0);
|
||
SendMessage(gMgSvc.RcvHwnd, WM_POPUP_PRTW_PROGRESS, 2, 0);
|
||
if not FileExists(sSpoolPath) then
|
||
sSpoolPath := '';
|
||
if PO.Print.bCollectOutput then
|
||
begin
|
||
var bDoExtr: Boolean := true;
|
||
var ExtList: TStringList := gMgSvc.PrefModel.PrtOcrTxtExtList;
|
||
if ExtList.Count > 0 then
|
||
begin
|
||
if FileExists(sDocPath) then
|
||
begin
|
||
var sExt: String := GetFileExt(sDocPath).ToUpper;
|
||
if ExtList.IndexOf(sExt) = - 1 then
|
||
bDoExtr := false;
|
||
end else
|
||
if ExtList.IndexOf('*NF') = -1 then
|
||
bDoExtr := false;
|
||
end;
|
||
|
||
if bDoExtr then
|
||
begin
|
||
_Trace('출력 이미지에서 텍스트 추출 ..', 3);
|
||
sExtrOcrTxt := ExtrTextFromPrintImgFiles(sExportPath);
|
||
SendMessage(gMgSvc.RcvHwnd, WM_POPUP_PRTW_PROGRESS, 2, 0);
|
||
_Trace('출력 이미지에서 텍스트 추출 .. OK', 3);
|
||
end;
|
||
end;
|
||
sThumbIds := gMgSvc.SendPrintImgFiles(sExportPath, sWorkDir_ + 'PrtThum\', PO.PrtCollThumLimit, crtDelete);
|
||
|
||
if bCfActive then
|
||
begin
|
||
if ProcessContentFilter_AfterExit(sExtrOcrTxt, true) then
|
||
exit;
|
||
end;
|
||
end else begin
|
||
SendMessage(gMgSvc.RcvHwnd, WM_POPUP_PRINTWATER_PROGRESS, 0, 0);
|
||
AddIgrPrtSpool(sPrtName);
|
||
bIsSplAnal := false;
|
||
end;
|
||
// DeleteDir(ExtractFilePath(sExportPath)); // 이거 언제 지워야 하나..
|
||
end;
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
if not bBlock and (PP.PrintWater <> pwNone) then
|
||
begin
|
||
var sConv: String := GetRunExePathDir + DIR_CONF + EXE_SPL;
|
||
|
||
// {$IFDEF DEBUG}
|
||
// bForceSpoolWater := true;
|
||
// {$ENDIF}
|
||
|
||
if (bForceSpoolWater or not bIsHook) and FileExists(sConv) then
|
||
begin
|
||
if (sSpoolPath = '') or not FileExists(sSpoolPath) then
|
||
begin
|
||
sSpoolPath := GetSpoolCopyPath('WTask');
|
||
_Trace('GetSpoolCopyPath(3) .. Path=%s', [sSpoolPath]);
|
||
end;
|
||
|
||
if FileExists(sSpoolPath) then
|
||
begin
|
||
// 워드는 부수, 한부씩인쇄 값을 가져올 수 없어서 아래처럼 처리
|
||
if CompareText('winword.exe', sPName) = 0 then
|
||
PrtInfo.DevMode.dmCollate := 1;
|
||
|
||
if bIsSplAnal and IsPJL(sSpoolPath) then
|
||
begin
|
||
_Trace('PJL 포맷 확인됨', 1);
|
||
if not IsPJLAndLanguagePLW(sSpoolPath) then
|
||
begin
|
||
var bCollate: Boolean;
|
||
var nCopies: Integer := GetQtyFromPJL(sSpoolPath, bCollate);
|
||
if nCopies > 0 then
|
||
begin
|
||
PrtInfo.dwCopyCount := nCopies;
|
||
PrtInfo.DevMode.dmCopies := nCopies;
|
||
if bCollate then
|
||
PrtInfo.DevMode.dmCollate := 1;
|
||
_Trace('PJL 포맷 부수 정보 : %d', [nCopies], 1);
|
||
end;
|
||
end else begin
|
||
_Trace('PJL 포맷, PLW 스플 확인됨. 스플 분석 중지.', 1);
|
||
bIsSplAnal := false; // PJL 포맷에서 LANGUAGE=PLW 사용하면 spl2pdf가 분석하지 못한다 25_0723 15:26:37 kku
|
||
end;
|
||
end;
|
||
|
||
if bIsSplAnal then
|
||
begin
|
||
var sFName: String := GetValidFileName(ExtractFileName(sDocName), '#');
|
||
var sExportPath: String := ExtractFilePath(sSpoolPath) + sFName + '.png';
|
||
// {$IFNDEF DEBUG}
|
||
if IsPrtSpl2Pdf then
|
||
begin
|
||
case CUSTOMER_TYPE of
|
||
CUSTOMER_SHCI,
|
||
CUSTOMER_SHSC :
|
||
begin
|
||
if (CompareText('InsideBank.exe', sPName) <> 0) and
|
||
(CompareText('excel.exe', sPName) <> 0) and
|
||
(CompareText('POWERPNT.EXE', sPName) <> 0) and
|
||
(CompareText('Hwp.exe', sPName) <> 0) then
|
||
sExportPath := CutFileExt(sExportPath) + '.pdf';
|
||
end;
|
||
// CUSTOMER_SHCI :
|
||
// begin
|
||
// if (CompareText('InsideBank.exe', sPName) <> 0) and
|
||
// (CompareText('Hwp.exe', sPName) <> 0) then
|
||
// sExportPath := CutFileExt(sExportPath) + '.pdf';
|
||
// end;
|
||
end;
|
||
end;
|
||
// {$ENDIF}
|
||
|
||
if PrtInfo.sPtrName = '' then
|
||
begin
|
||
PrtInfo.sPtrName := sPrtName;
|
||
// TTgTrace.T('[W] Force PtrName="%s"', [PrtInfo.sPtrName]);
|
||
end;
|
||
|
||
if PrtInfo.sDocName = '' then
|
||
PrtInfo.sDocName := sDocName;
|
||
|
||
var sParam: String := Format('-$ 65XSD4234455S4PLET58 -unicode -imgbitcount 24 -imgxres %d -imgyres %d', [PPO.PrtDPI, PPO.PrtDPI]) + ' "%s" "%s"';
|
||
|
||
if IsPrintWaterHook then
|
||
begin
|
||
bIsSplAnal := IsSpoolAnal(sPrtName);
|
||
if bIsSplAnal then
|
||
begin
|
||
SendMessage(gMgSvc.RcvHwnd, WM_POPUP_PRINTWATER_PROGRESS, 1,
|
||
NativeUInt(PChar(IntToStr(PrtInfo.dwTotalPage) + '|' + ExtractFilePath(sSpoolPath) + '|' + sFName)));
|
||
|
||
// 후킹방식일 경우 분석 실패 체크를 위해 여기서 분석을 해준다 25_0728 13:10:48 kku
|
||
if not ExtractImagesFromSpool(sConv, sParam, sSpoolPath, 'prt0_', sExportPath, 300000, 0) then
|
||
begin
|
||
AddIgrPrtSpool(sPrtName);
|
||
bIsSplAnal := false;
|
||
end;
|
||
end;
|
||
|
||
if not bIsSplAnal then
|
||
SendMessage(gMgSvc.RcvHwnd, WM_POPUP_PRINTWATER_PROGRESS, 0, 0);
|
||
end else begin
|
||
SendMessage(gMgSvc.RcvHwnd, WM_POPUP_PRINTWATER_PROGRESS, 1,
|
||
NativeUInt(PChar(IntToStr(PrtInfo.dwTotalPage) + '|' + ExtractFilePath(sSpoolPath) + '|' + sFName)));
|
||
end;
|
||
|
||
if bIsSplAnal then
|
||
begin
|
||
// 잡 삭제 직전에 업데이트
|
||
if (aJob <> nil) and not aJob.WorkEnd then
|
||
CancelJob;
|
||
|
||
bWaterMark := true;
|
||
TThdExecuteEndNoti.Create(gMgSvc.RcvHwnd, GetPrintLog(LOGCODE_EVENT_PRINTER), true, PrtInfo, sPort, sConv, sParam,
|
||
sSpoolPath, sExportPath, sPrtDocId).StartThread;
|
||
sSpoolPath := ''; // 삭제 안되게 빈값 처리 24_1212 16:39:40 kku
|
||
|
||
exit;
|
||
end;
|
||
end;
|
||
end else
|
||
_Trace('프린터 출력 감지 .. Spool 수집 실패... Printer=%s, Doc=%s', [sPrtName, sDocName], 2);
|
||
end else begin
|
||
// 워터마크 유효성 체크
|
||
if CheckValidPrintWater then // KOCES에서는 워터마크 안되도 차단 안되게함 23_0413 13:35:37 kku
|
||
begin
|
||
if gMgSvc.RecentPrintDocName <> sDocName then
|
||
begin
|
||
sBlockReson := 'WT';
|
||
_Trace('Fail .. PrintWatermark .. Recent="%s", Doc="%s"', [gMgSvc.RecentPrintDocName, sDocName]);
|
||
bBlock := true;
|
||
end;
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
SendMessage(gMgSvc.RcvHwnd, WM_POPUP_PRTW_PROGRESS, 3, 0);
|
||
|
||
sData := sPrtName + '|' + sDocName;
|
||
if bBlock and not bApprovalPost then
|
||
begin
|
||
if CollectPrintInfo(sDocPath, sExtrTxt, sExtrOcrTxt, '', '') then
|
||
begin
|
||
SendPrintLog(LOGCODE_PREVENT_PRINTER);
|
||
|
||
_Trace('프린터 출력 감지 .. 차단, 출력 승인 요청. Printer=%s, Doc=%s',
|
||
[sPrtName, sDocName], 2);
|
||
exit;
|
||
end;
|
||
|
||
if bApprovalPost then
|
||
begin
|
||
// 사후 결재 처리를 통해 false로 변경될 수 있다. 25_1127 09:28:25 kku
|
||
goto LB_DoPrint;
|
||
end;
|
||
|
||
CancelJob;
|
||
sData := sData + '|PV';
|
||
if sBlockReson <> '' then
|
||
sData := sData + '|' + sBlockReson;
|
||
// else if PP.PrintWater <> pwNone then
|
||
// sData := sData + '|WT';
|
||
|
||
if gMgSvc.IsNewApi then
|
||
SendPrintLog(LOGCODE_PREVENT_PRINTER)
|
||
else
|
||
gMgSvc.SendEventLog(URI_USER_ACTION, LOGCODE_PREVENT_PRINTER,
|
||
Format('Printer : %s, Document : %s', [sPrtName, sDocName]) + BooleanToStr(sBlockReson = '', '', ', ' + sBlockReson));
|
||
end else begin
|
||
LB_DoPrint :
|
||
if aJob <> nil then
|
||
begin
|
||
// 스풀중에는 resume 명령이 먹지 않아서 추가 25_0623 10:29:50 kku
|
||
while (aJob <> nil) and aJob.IsSpooling2 do
|
||
begin
|
||
if i = 4000 then // 200초간 기다려준다 23_0525 08:03:11 kku
|
||
break;
|
||
|
||
Inc(i);
|
||
Sleep(50);
|
||
end;
|
||
|
||
// SetPrtJobFromHelperApp(aJob, JOB_CONTROL_RESUME);
|
||
aJob.ResumePrtJob(true);
|
||
end;
|
||
|
||
if not bIsHook and gMgSvc.IsPrtWaterExcept then // 후킹의 경우 HPCMD_CHECK_PRINTWATER_EXCEPT_EX를 통해 처리, 초기화 함 25_1105 19:39:27 kku
|
||
gMgSvc.IsPrtWaterExcept := false;
|
||
|
||
if gMgSvc.IsNewApi then
|
||
SendPrintLog(LOGCODE_EVENT_PRINTER)
|
||
else
|
||
gMgSvc.SendEventLog(URI_USER_ACTION, LOGCODE_EVENT_PRINTER,
|
||
Format('Printer : %s, Document : %s', [sPrtName, sDocName]), false);
|
||
end;
|
||
|
||
if IsDivPopup then
|
||
begin
|
||
if bBlock then
|
||
begin
|
||
if PP.bPopup then
|
||
gMgSvc.PopupMessage(TYPE_MSG_PREVENT_PRINTER, sData);
|
||
end else begin
|
||
if PO.PrtAllowPopup then
|
||
begin
|
||
if (PP.PrintWater <> pwNone) and PPO.PrtWaterPop and (gMgSvc.RecentPrintDocName = sDocName) then
|
||
gMgSvc.PopupMessage(TYPE_MSG_EVENT_PRINTWATER, sData)
|
||
else
|
||
gMgSvc.PopupMessage(TYPE_MSG_PREVENT_PRINTER, sData);
|
||
end;
|
||
end;
|
||
end else begin
|
||
if PP.bPopup then
|
||
begin
|
||
if bBlock or (PP.PrintKind = pkLog) then
|
||
begin
|
||
gMgSvc.PopupMessage(TYPE_MSG_PREVENT_PRINTER, sData);
|
||
end else
|
||
if (PP.PrintWater <> pwNone) and PPO.PrtWaterPop then
|
||
begin
|
||
if (gMgSvc.RecentPrintDocName = sDocName) then
|
||
gMgSvc.PopupMessage(TYPE_MSG_EVENT_PRINTWATER, sData);
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
if aJob <> nil then
|
||
aJob.WorkEnd := true;
|
||
finally
|
||
Finalize(PrtInfo);
|
||
|
||
if FileExists(sSpoolPath) then
|
||
DeleteFile(PChar(sSpoolPath));
|
||
|
||
{$IFNDEF DEBUG}
|
||
if DirectoryExists(sEmfDir) then
|
||
DeleteDir(sEmfDir);
|
||
{$ENDIF}
|
||
end;
|
||
end;
|
||
finally
|
||
bIsWorking_ := false;
|
||
CurJob_ := nil;
|
||
|
||
if pPhJob <> nil then
|
||
Dispose(pPhJob);
|
||
|
||
if aJob <> nil then
|
||
aJob.ResumePrtJob(true);
|
||
end;
|
||
except
|
||
on E: Exception do
|
||
ETgException.TraceException(Self, E, 'Fail .. ProcessPrintJob()');
|
||
end;
|
||
end;
|
||
|
||
procedure TThdPrintWork.Execute;
|
||
var
|
||
Job: TPrtJobInfo;
|
||
bInitFs: Boolean;
|
||
begin
|
||
// CoInitialize(nil);
|
||
// 외부 DRM 사용준비
|
||
bInitFs := true;
|
||
fas_ := nil;
|
||
case CUSTOMER_TYPE of
|
||
CUSTOMER_WELFNI : SetDSD_CODE(DSD_CODE_WFNI);
|
||
CUSTOMER_WELFND : SetDSD_CODE(DSD_CODE_WFND);
|
||
else bInitFs := false;
|
||
end;
|
||
|
||
if bInitFs then
|
||
begin
|
||
var sFsDir: String := GetRunExePathDir + 'fsdinit';
|
||
if not DirectoryExists(sFsDir) then
|
||
sFsDir := GetRunExePathDir + DIR_CONF + 'fsdinit';
|
||
|
||
if DirectoryExists(sFsDir) then
|
||
begin
|
||
CoInitializeEx(nil, COINIT_APARTMENTTHREADED);
|
||
fas_ := TTgFasoo.Create(sFsDir);
|
||
end;
|
||
end;
|
||
|
||
while not Terminated and not GetWorkStop do
|
||
begin
|
||
try
|
||
Lock;
|
||
try
|
||
if (JobList_ <> nil) and (JobList_.Count > 0) then
|
||
begin
|
||
Job := JobList_[0];
|
||
JobList_.Delete(0);
|
||
end else
|
||
Job := nil;
|
||
finally
|
||
Unlock;
|
||
end;
|
||
|
||
if Job <> nil then
|
||
ProcessPrintJob(Job)
|
||
else Sleep(50);
|
||
except
|
||
on E: Exception do
|
||
ETgException.TraceException(Self, E, 'Fail .. Execute()');
|
||
end;
|
||
end;
|
||
// CoUninitialize;
|
||
end;
|
||
|
||
end.
|