Hi Rafal,
the `cmd` is a horrible shell, so I would try to avoid it at all.
Here are the options I see:
1. Keep using the cmd, and prepare a property file with the L2 text (and possibly other properties). Use the classic \n for new lines. Then use -lpf JSignPdf argument to load the property file.
Sample property file content (l2.properties):
visibleSignature.l2text=line 1\nline 2\netc
Sample call:
JSignPdfC.exe -lpf l2.properties -V ...
2. Use PowerShell and its newline support by `n (backtick+n)
.\JSignPdfC.exe -ksf C:\client.p12 -ksp 123456 -d C:\Data C:\test.pdf -V --l2-text "Hello`nBye"
3. launch the JSignPdf directly from the Delphi and use line-feed directly (#10):
var
R: TProcessResult;
begin
R := RunProcess('"C:\Program Files\JSignPdf\JSignPdfC.exe" -ksf "C:\Users\Lenovo\AppData\client.p12" -ksp 123456 -d C:\Users\Lenovo\AppData "C:\Program Files\JSignPdf\docs\JSignPdf.pdf" -V --l2-text "line 1'+ #10 +'line 2'+ #10 +'etc"');
Memo1.Lines.Text := R.Output;
if R.ExitCode <> 0 then
ShowMessage('Exit code: ' + R.ExitCode.ToString);
end;---------------------------
{helper unit:}
uses
Winapi.Windows,
System.SysUtils,
System.Classes;
type
TProcessResult = record
Output: string;
ExitCode: Cardinal;
end;
function RunProcess(const CommandLine: string;
const WorkingDir: string = '';
const Encoding: TEncoding = nil): TProcessResult;
const
BUFFER_SIZE = 8192;
var
SA: TSecurityAttributes;
ReadPipe, WritePipe: THandle;
SI: TStartupInfo;
PI: TProcessInformation;
Buffer: array[0..BUFFER_SIZE - 1] of Byte;
BytesRead, TotalAvail: DWORD;
OutputStream: TBytesStream;
WaitRes: DWORD;
WorkingDirPtr: PChar;
CmdLineBuffer: PChar;
begin
Result.Output := '';
Result.ExitCode := Cardinal(-1);
if WorkingDir<>'' then
workingdirptr := PChar(WorkingDir)
else
WorkingDirPtr := nil;
// Security attributes for inheritable pipe
SA.nLength := SizeOf(SA);
SA.lpSecurityDescriptor := nil;
SA.bInheritHandle := True;
if not CreatePipe(ReadPipe, WritePipe, @SA, 0) then
RaiseLastOSError;
try
// Prevent parent from inheriting read handle
SetHandleInformation(ReadPipe, HANDLE_FLAG_INHERIT, 0);
ZeroMemory(@SI, SizeOf(SI));
SI.cb := SizeOf(SI);
SI.dwFlags := STARTF_USESTDHANDLES;
SI.hStdOutput := WritePipe;
SI.hStdError := WritePipe;
SI.hStdInput := GetStdHandle(STD_INPUT_HANDLE);
ZeroMemory(@PI, SizeOf(PI));
CmdLineBuffer := StrAlloc(Length(CommandLine) + 1);
StrPCopy(CmdLineBuffer, CommandLine);
if not CreateProcess(
nil,
CmdLineBuffer,
nil,
nil,
True, // inherit handles
CREATE_NO_WINDOW,
nil,
WorkingDirPtr,
SI,
PI) then
RaiseLastOSError;
// Parent must close write end
CloseHandle(WritePipe);
WritePipe := 0;
OutputStream := TBytesStream.Create;
try
repeat
WaitRes := WaitForSingleObject(PI.hProcess, 50);
while PeekNamedPipe(ReadPipe, nil, 0, nil, @TotalAvail, nil) and
(TotalAvail > 0) do
begin
if not ReadFile(ReadPipe, Buffer, BUFFER_SIZE, BytesRead, nil) then
Break;
if BytesRead > 0 then
OutputStream.WriteBuffer(Buffer, BytesRead);
end;
until WaitRes = WAIT_OBJECT_0;
// Final drain
while ReadFile(ReadPipe, Buffer, BUFFER_SIZE, BytesRead, nil) and
(BytesRead > 0) do
begin
OutputStream.WriteBuffer(Buffer, BytesRead);
end;
if not GetExitCodeProcess(PI.hProcess, Result.ExitCode) then
RaiseLastOSError;
try
Result.Output := TEncoding.UTF8.GetString(
OutputStream.Bytes, 0, OutputStream.Size);
except
on EEncodingError do
Result.Output := TEncoding.GetEncoding(GetOEMCP).GetString(
OutputStream.Bytes, 0, OutputStream.Size);
end;
finally
OutputStream.Free;
end;
CloseHandle(PI.hProcess);
CloseHandle(PI.hThread);
finally
if WritePipe <> 0 then
CloseHandle(WritePipe);
CloseHandle(ReadPipe);
end;
end;
Regards,
Josef