BSOne.SFC/Tocsg.Module/PrinterMon/ThdExecuteEndNoti.pas

580 lines
18 KiB
Plaintext

{*******************************************************}
{ }
{ ThdExecuteEndNoti }
{ }
{ Copyright (C) 2023 kku }
{ }
{*******************************************************}
unit ThdExecuteEndNoti;
interface
uses
{$IFDEF _HE_}
ManagerPrint,
{$ENDIF}
System.SysUtils, System.Classes, Tocsg.Thread, Winapi.Messages,
Winapi.Windows, Tocsg.Printer, Vcl.Graphics, superobject;
{$I Define.inc}
const
WM_NOTIEXECUTE_END = WM_USER + 2654;
type
TThdExecuteEndNoti = class(TTgThread)
private
hRcvWnd_: HWND;
sExePath_, sParam_,
sSrcPath_, sDestPath_: String;
// pAssoc_: Pointer;
bUseWM_: Boolean;
OLog_: ISuperObject;
sPrtDocId_,
sPortInfo_: String;
PrtInfo_: TPrtJobDevInfo;
{$IFDEF _HE_}
PrtEnt_: PPrtEnt;
{$ENDIF}
protected
procedure Execute; override;
public
Constructor Create(hRcvWnd: HWND; OLog: ISuperObject; bUseWM: Boolean; sExePath, sParam, sSrcPath, sDestPath: String; pAssoc: Pointer); overload;
Constructor Create(hRcvWnd: HWND; OLog: ISuperObject; bUseWM: Boolean; aPrtInfo: TPrtJobDevInfo; sPortInfo, sExePath, sParam, sSrcPath, sDestPath, sPrtDocId: String); overload;
{$IFDEF _HE_}
Constructor Create(hRcvWnd: HWND; OLog: ISuperObject; aPrtEnt: PPrtEnt; sExePath, sParam, sSrcPath, sDestPath: String; pAssoc: Pointer); overload;
{$ENDIF}
// property Assoc: Pointer read pAssoc_;
property DestPath: String read sDestPath_;
property PrtInfo: TPrtJobDevInfo read PrtInfo_;
{$IFDEF _HE_}
property PrtEnt: PPrtEnt read PrtEnt_;
{$ENDIF}
property PortInfo: String read sPortInfo_;
property OLog: IsuperObject read OLog_;
property UseWM: Boolean read bUseWM_;
property PrtDocId: String read sPrtDocId_;
property WorkState: TTgThreadState read GetWorkState;
end;
function ExtractImagesFromSpool(sExePath, sParam, sSrcPath, sHeadStr: String; var sDestPath: String;
nWaitMSec: Integer; nExtrMax: Integer = 0 ; bDelSrcPath: Boolean = true): Boolean;
function ExtractJpgFromTiff(sTifPath: String): Integer;
function ExtractPngFromTiff(sTifPath: String; aTiff: TWICImage = nil): Integer;
function ExtractPngFromPng(sPngPath: String): Integer;
implementation
uses
{$IFDEF _HE_}
ManagerService,
{$ENDIF}
Tocsg.Process, Tocsg.Path, Tocsg.Trace, Tocsg.Exception,
GlobalDefine, Tocsg.Files, PngImageList, Tocsg.Safe,
Vcl.Imaging.pngimage, Vcl.Imaging.jpeg, Winapi.ActiveX, ManagerModel,
Condition, CttSchDefine, ManagerCampaign;
Constructor TThdExecuteEndNoti.Create(hRcvWnd: HWND; OLog: ISuperObject; bUseWM: Boolean; sExePath, sParam, sSrcPath, sDestPath: String; pAssoc: Pointer);
begin
Inherited Create;
ZeroMemory(@PrtInfo_, SizeOf(PrtInfo_));
sPortInfo_ := '';
sPrtDocId_ := '';
OLog_ := OLog;
bUseWM_ := bUseWM;
hRcvWnd_ := hRcvWnd;
sExePath_ := sExePath;
sParam_ := sParam;
sSrcPath_ := sSrcPath;
sDestPath_ := sDestPath;
// pAssoc_ := pAssoc;
{$IFDEF _HE_}
PrtEnt_ := nil;
{$ENDIF}
FreeOnTerminate := true;
end;
Constructor TThdExecuteEndNoti.Create(hRcvWnd: HWND; OLog: ISuperObject; bUseWM: Boolean; aPrtInfo: TPrtJobDevInfo; sPortInfo, sExePath, sParam, sSrcPath, sDestPath, sPrtDocId: String);
begin
Create(hRcvWnd, OLog, bUseWM, sExePath, sParam, sSrcPath, sDestPath, nil);
PrtInfo_ := aPrtInfo;
sPortInfo_ := sPortInfo;
sPrtDocId_ := sPrtDocId;
end;
{$IFDEF _HE_}
Constructor TThdExecuteEndNoti.Create(hRcvWnd: HWND; OLog: ISuperObject; aPrtEnt: PPrtEnt; sExePath, sParam, sSrcPath, sDestPath: String; pAssoc: Pointer);
begin
Create(hRcvWnd, OLog, aPrtEnt.WInfo.bUseWM, sExePath, sParam, sSrcPath, sDestPath, pAssoc);
PrtEnt_ := aPrtEnt;
sPortInfo_ := PrtEnt_.WInfo.sPdfPath;
end;
{$ENDIF}
procedure ExtractSpoolLib(var nWaitMSec: Integer);
var
sTempDir, sConfDir: String;
begin
nWaitMSec := -1;
sConfDir := '';
sTempDir := '';
try
{$IFDEF _HE_}
sConfDir := GetRunExePathDir + DIR_CONF + 'spl2pdf_lib';
if not DirectoryExists(sConfDir) and (gMgSvc <> nil) then
begin
sTempDir := GetWindowsDir;
if sTempDir <> '' then
begin
sTempDir := sTempDir[1] + Format(':\Users\%s\AppData\Local\Temp\VeryPDF\spl2pdf_lib', [ExtractFileName(gMgSvc.UserName)]);
if not FileExists(sTempDir + 'pcl.dll') then
sTempDir := GetWindowsDir + 'Temp\VeryPDF\spl2pdf_lib';
if DirectoryExists(sTempDir) and not DirectoryExists(sConfDir) then
begin
TTgTrace.T('프린터 출력 감지 .. Spool 에서 문서 추출 .. 라이브러리 추출 ..', 2);
CopyDirSub(sTempDir, sConfDir);
end else begin
nWaitMSec := 5000;
TTgTrace.T('프린터 출력 감지 .. Spool 에서 문서 추출 .. 라이브러리 추출 .. 대기', 2);
end;
end;
end;
{$ELSE}
sConfDir := GetRunExePathDir + 'spl2pdf_lib';
if not DirectoryExists(sConfDir) then
begin
sTempDir := GetUserDir;
if sTempDir <> '' then
begin
sTempDir := IncludeTrailingPathDelimiter(sTempDir) + 'AppData\Local\Temp\VeryPDF\spl2pdf_lib';
if DirectoryExists(sTempDir) and not DirectoryExists(sConfDir) then
CopyDirSub(sTempDir, sConfDir)
else
nWaitMSec := 5000;
end;
end;
{$ENDIF}
except
on E: Exception do
ETgException.TraceException(E, 'Fail .. ExtractSpoolLib()');
end;
end;
function ExtractJpgFromTiff(sTifPath: String): Integer;
var
tif: TWICImage;
jpg: TJpegImage;
sDestJpgPath: String;
ms: TMemoryStream;
begin
Result := 0;
try
sDestJpgPath := CutFileExt(sTifPath);
Guard(ms, TMemoryStream.Create);
ms.LoadFromFile(sTifPath);
Guard(jpg, TJpegImage.Create);
Guard(tif, TWICImage.Create);
Repeat
try
tif.LoadFromStream(ms);
jpg.Assign(tif);
jpg.SaveToFile(Format('%s-%.3d.jpg', [sDestJpgPath, Result + 1]));
Inc(Result);
tif.FrameIndex := Result;
except
on E: Exception do
begin
ETgException.TraceException(E, 'Fail .. ExtractJpgFromTiff() ... extract');
break;
end;
end;
Until Result >= tif.FrameCount;
except
on E: Exception do
ETgException.TraceException(E, 'Fail .. ExtractJpgFromTiff()');
end;
end;
function ExtractPngFromTiff(sTifPath: String; aTiff: TWICImage = nil): Integer;
var
tif: TWICImage;
png: TPngImage;
sDestPngPath: String;
bFreeTfi: Boolean;
ms: TMemoryStream;
begin
Result := 0;
try
sDestPngPath := CutFileExt(sTifPath);
bFreeTfi := false;
Guard(png, TPngImage.Create);
if aTiff = nil then
begin
tif := TWICImage.Create;
bFreeTfi := true;
end else begin
tif := aTiff;
tif.FrameIndex := 0;
end;
Guard(ms, TMemoryStream.Create);
try
ms.LoadFromFile(sTifPath);
Repeat
try
tif.LoadFromStream(ms);
png.Assign(tif);
png.SaveToFile(Format('%s-%.3d.png', [sDestPngPath, Result + 1]));
Inc(Result);
tif.FrameIndex := Result;
except
on E: Exception do
begin
ETgException.TraceException(E, 'Fail .. ExtractPngFromTiff() ... extract');
break;
end;
end;
Until Result >= tif.FrameCount;
finally
if bFreeTfi then
FreeAndNil(tif);
end;
except
on E: Exception do
ETgException.TraceException(E, 'Fail .. ExtractPngFromTiff()');
end;
end;
// spl2pdf.exe 버그로 png 파일이 하나로 합쳐져서 내보내기가 됨.
// 나눠주는 작업을 하기 위해 추가 24_0207 14:53:04 kku
function ExtractPngFromPng(sPngPath: String): Integer;
const
SIG_PNG: array [0..3] of Byte = ($89, $50, $4E, $47);
var
ms: TMemoryStream;
fs: TFileStream;
png: TPngImage;
arrChk: array [0..3] of Byte;
llPos, llPngSt, llRead: LONGLONG;
sIgExtPath: String;
begin
Result := 0;
try
if not FileExists(sPngPath) then
exit;
Guard(ms, TMemoryStream.Create);
ms.LoadFromFile(sPngPath);
sIgExtPath := CutFileExt(sPngPath);
llPos := 0;
llPngSt := -1;
while ms.Position < ms.Size do
begin
ms.Position := llPos;
if ms.Read(arrChk, 4) <> 4 then
break;
if CompareMem(@SIG_PNG, @arrChk, 4) then
begin
if llPngSt <> -1 then
begin
// 파일 끝, 저장
Inc(Result);
Guard(fs, TFileStream.Create(sIgExtPath + Format('_%.4d.png', [Result]), fmCreate));
llPos := ms.Position - 4;
ms.Position := llPngSt;
llRead := llPos - llPngSt;
if (ms.Position + llRead) < ms.Size then
fs.CopyFrom(ms, llRead)
else
fs.CopyFrom(ms, ms.Size - ms.Position);
llPngSt := llPos;
Inc(llPos, 4);
end else
llPngSt := ms.Position - 4;
end;
Inc(llPos);
end;
// if (llPngSt <> -1) and (Result > 0) then // 이렇게 하면 안됨.. spl2pdf에서 파일을 여러개 나눴을 경우 두번째가 _0002 이기 때문에 첫번째 파일을 _0001로 바꿔줘야함 24_0208 08:14:46 kku
if llPngSt <> -1 then
begin
Inc(Result);
Guard(fs, TFileStream.Create(sIgExtPath + Format('_%.4d.png', [Result]), fmCreate));
ms.Position := llPngSt;
fs.CopyFrom(ms, ms.Size - ms.Position);
end;
except
on E: Exception do
ETgException.TraceException(E, 'Fail .. ExtractPngFromPng()');
end;
end;
function ExtractImagesFromSpool(sExePath, sParam, sSrcPath, sHeadStr: String; var sDestPath: String;
nWaitMSec: Integer; nExtrMax: Integer = 0 ; bDelSrcPath: Boolean = true): Boolean;
Label
LB_TryExtrDoc;
var
nTry, nTO: Integer;
nDefCnt, nProcCnt: Integer;
sExt,
sDestDir: String;
function ExtractImgWaitUntilTerminate(sPath, sParam: String; dwVisible: DWORD; nTimeOutMilSec: Integer = -1): Boolean;
var
PI: TProcessInformation;
StartupInfo: TStartupInfo;
sDir,
sName: String;
dwWaitResult,
dwExecuteTick: DWORD;
begin
ZeroMemory(@PI, SizeOf(PI));
ZeroMemory(@StartupInfo, SizeOf(StartupInfo));
StartupInfo.cb := Sizeof(StartupInfo);
StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USEPOSITION;
StartupInfo.wShowWindow := dwVisible;
sDir := ExtractFilePath(sPath);
sName := ExtractFileName(sPath);
Result := CreateProcess(nil,
PChar(Format('%s %s', [sPath, sParam])), { pointer to command line string }
nil, { pointer to process security attributes }
nil, { pointer to thread security attributes }
false, { handle inheritance flag }
CREATE_NEW_CONSOLE or { creation flags }
NORMAL_PRIORITY_CLASS,
nil, { pointer to new environment block }
nil, { pointer to current directory name }
StartupInfo, { pointer to STARTUPINFO }
PI); { pointer to PROCESS_INF }
if Result then
begin
dwExecuteTick := GetTickCount;
while true do
begin
dwWaitResult := WaitForSingleObject(PI.hProcess, 50);
if dwWaitResult <> WAIT_TIMEOUT then
break;
if nExtrMax > 0 then
begin
nProcCnt := CountFileExt(sDestDir, [sExt]) - nDefCnt;
if nProcCnt >= nExtrMax then
begin
TerminateProcess(PI.hProcess, 999);
exit;
end;
end;
// 메세지 없이 계속 돌아가는 상황을 위해서 빠져나오는 타임아웃을 추가함 (tcptunnel.exe 관련을 위해 추가)
if (nTimeOutMilSec > 0) and ((GetTickCount - dwExecuteTick) > nTimeOutMilSec) then
begin
TerminateProcess(PI.hProcess, 999);
exit;
end;
end;
// GetExitCodeProcess(PI.hProcess, dwExitCode);
end;
end;
begin
Result := false;
try
TTgTrace.T('프린터 출력 감지 .. Spool 에서 문서 추출 ..', 2);
ExtractSpoolLib(nWaitMSec);
nTry := 0;
sExt := GetFileExt(sDestPath);
sDestDir := ExtractFilePath(sDestPath);
sDestPath := sDestDir + sHeadStr + FormatDateTime('yyyymmddhhnnss', Now) + '.' + sExt;
if nExtrMax > 0 then
nDefCnt := CountFileExt(sDestDir, [sExt]);
LB_TryExtrDoc :
nProcCnt := 0;
// {$IFDEF _SPL2PDF_}
// sDestPath := CutFileExt(sDestPath) + '.pdf';
// ExtractImgWaitUntilTerminate(sExePath, Format('-$ 65XSD4234455S4PLET58 -unicode -imgxres 600 -imgyres 600 -imgbitcount 24 "%s" "%s"', [sSrcPath, sDestPath]), SW_HIDE, nWaitMSec);
//
// Exit(true);
// {$ELSE}
ExtractImgWaitUntilTerminate(sExePath, Format(sParam, [sSrcPath, sDestPath]), SW_HIDE, nWaitMSec);
// {$ENDIF}
nTO := 0;
while not FileExists(sDestPath) do
begin
if nTO >= 20 then
break;
Inc(nTO);
Sleep(100);
end;
if FileExists(sDestPath) or FileExists(CutFileExt(sDestPath) + '_0001.' + sExt) then
begin
if ExtractPngFromPng(sDestPath) > 0 then
DeleteFile(PChar(sDestPath));
if not FileExists(sDestPath) then
sDestPath := CutFileExt(sDestPath) + '_0001.' + sExt;
Result := CountFileExt(ExtractFilePath(sDestPath), [sExt]) > 0;
// Result := ExtractPngFromTiff(sDestPath, aTiff) > 0;
end else begin
if nTry < 2 then
begin
Inc(nTry);
TTgTrace.T('프린터 출력 감지 .. Spool 에서 문서 추출 .. 실패 .. 다시 시도 %d', [nTry], 2);
ExtractSpoolLib(nWaitMSec);
Sleep(500);
goto LB_TryExtrDoc;
end;
end;
// CJ::
if bDelSrcPath then
DeleteFile(PChar(sSrcPath));
except
on E: Exception do
ETgException.TraceException(E, 'Fail .. ExtractImagesFromSpool()');
end;
end;
procedure TThdExecuteEndNoti.Execute;
Label
LB_TryExtrDoc;
var
PO: TPrefModel;
begin
try
// CoInitialize(nil);
// try
SetWorkState(tsWorking);
PO := gMgSvc.ModePolicy;
if sDestPath_ = '' then
begin
// EMF 방식
if PO.IsPrtCollectThum then
begin
var sEmfDir: String := gMgSvc.MgPrt.DataDir + PrtEnt_.sId + '\';
if DirectoryExists(sEmfDir) then
begin
SendMessage(gMgSvc.RcvHwnd, WM_POPUP_PRTW_PROGRESS, 2, 0);
if (OLog_ <> nil) and (OLog_.S['COMPONENT_THUMBNAIL_ID'] = '') then
OLog_.S['COMPONENT_THUMBNAIL_ID'] := gMgSvc.SendPrintEmfFiles(sEmfDir, 'C:\ProgramData\HE\PrtThum\', PO.PrtCollThumLimit, crtDelete);
var bDoExtr: Boolean := true;
if PrtEnt_ <> nil then
begin
var ExtList: TStringList := gMgSvc.PrefModel.PrtOcrTxtExtList;
if ExtList.Count > 0 then
begin
if FileExists(PrtEnt_.sFPath) then
begin
var sExt: String := GetFileExt(PrtEnt_.sFPath).ToUpper;
if ExtList.IndexOf(sExt) = - 1 then
bDoExtr := false;
end else
if ExtList.IndexOf('*NF') = -1 then
bDoExtr := false;
end;
end;
if bDoExtr then
begin
if (OLog_ <> nil) and (OLog_.S['OCR_BODY'] = '') then
OLog_.S['OCR_BODY'] := ExtrTextFromPrintEmfFiles(sEmfDir);
end;
SendMessage(gMgSvc.RcvHwnd, WM_POPUP_PRTW_PROGRESS, 2, 0);
end;
SendMessage(gMgSvc.RcvHwnd, WM_POPUP_PRTW_PROGRESS, 2, 0); // 재출력일 경우 한단계 더 넘겨야 함..
end;
end else begin
if not FileExists(sDestPath_) and not FileExists(CutFileExt(sDestPath_) + '_0001.' + GetFileExt(sDestPath_)) then // ExtractImagesFromSpool()를 미리한 경우가 있다. 25_0728 13:13:04 kku
begin
ExtractImagesFromSpool(sExePath_, sParam_, sSrcPath_, 'prt_', sDestPath_, 300000, 0);
end;
if FileExists(sDestPath_) and (PrtEnt_ <> nil) and (PrtEnt_.sThumbIds = '') and (OLog_ <> nil) then
begin
// 썸네일 수집 25_0421 09:52:53 kku
if PO.IsPrtCollectThum then
begin
SendMessage(gMgSvc.RcvHwnd, WM_POPUP_PRTW_PROGRESS, 2, 0);
if (OLog_ <> nil) and (OLog_.S['COMPONENT_THUMBNAIL_ID'] = '') then
begin
OLog_.S['COMPONENT_THUMBNAIL_ID'] := gMgSvc.SendPrintImgFiles(sDestPath_, 'C:\ProgramData\HE\PrtThum\', PO.PrtCollThumLimit);
end;
if PO.Print.bCollectOutput and (OLog_.S['OCR_BODY'] = '') then
begin
var bDoExtr: Boolean := true;
if PrtEnt_ <> nil then
begin
var ExtList: TStringList := gMgSvc.PrefModel.PrtOcrTxtExtList;
if ExtList.Count > 0 then
begin
if FileExists(PrtEnt_.sFPath) then
begin
var sExt: String := GetFileExt(PrtEnt_.sFPath).ToUpper;
if ExtList.IndexOf(sExt) = - 1 then
bDoExtr := false;
end else
if ExtList.IndexOf('*NF') = -1 then
bDoExtr := false;
end;
end;
if bDoExtr then
begin
if (OLog_ <> nil) and (OLog_.S['OCR_BODY'] = '') then
OLog_.S['OCR_BODY'] := ExtrTextFromPrintImgFiles(sDestPath_);
end;
SendMessage(gMgSvc.RcvHwnd, WM_POPUP_PRTW_PROGRESS, 2, 0);
end;
SendMessage(gMgSvc.RcvHwnd, WM_POPUP_PRTW_PROGRESS, 2, 0); // 재출력일 경우 한단계 더 넘겨야 함..
end;
end;
end;
SendMessage(hRcvWnd_, WM_NOTIEXECUTE_END, 0, NativeUInt(Self));
SetWorkState(tsCompleted);
// finally
// CoUninitialize;
// end;
except
on E: Exception do
begin
ETgException.TraceException(Self, E, 'Fail .. Execute()');
SetWorkState(tsFail);
end;
end;
end;
end.