unit ExifTool;
interface
uses
Classes, SysUtils, Vcl.Forms, Util, Windows;
function ExecuteExifTool(const Command: WideString; Output, Errors: TStrings): TFunctionResult;
implementation
uses
MainForm, StatusForm;
function ExecuteExifTool(const Command: WideString; Output, Errors: TStrings): TFunctionResult;
var
Buffer: array[0..255] of Byte;
CreationFlags: DWORD;
NumberOfBytesRead: DWORD;
PipeErrorsRead: THandle;
PipeErrorsWrite: THandle;
PipeOutputRead: THandle;
PipeOutputWrite: THandle;
ProcessInfo: TProcessInformation;
SecurityAttr: TSecurityAttributes;
StartupInfo: TStartupInfo;
WaitResult: DWORD;
FileCounter: integer;
Line: String;
OutStream, ErrStream: TMemoryStream;
Success: BOOL;
begin
FileCounter := 0;
FillChar(ProcessInfo, SizeOf(TProcessInformation), 0);
FillChar(SecurityAttr, SizeOf(TSecurityAttributes), 0);
SecurityAttr.nLength := SizeOf(TSecurityAttributes);
SecurityAttr.bInheritHandle := True;
SecurityAttr.lpSecurityDescriptor := nil;
CreatePipe(PipeOutputRead, PipeOutputWrite, @SecurityAttr, 0);
CreatePipe(PipeErrorsRead, PipeErrorsWrite, @SecurityAttr, 0);
FillChar(StartupInfo, SizeOf(TStartupInfo), 0);
StartupInfo.cb := SizeOf(TStartupInfo);
StartupInfo.hStdInput := 0;
StartupInfo.hStdOutput := PipeOutputWrite;
StartupInfo.hStdError := PipeErrorsWrite;
StartupInfo.wShowWindow := SW_HIDE;
StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
CreationFlags := CREATE_DEFAULT_ERROR_MODE or CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS;
Success := CreateProcessW(
nil, PWideChar(Command), nil, nil, True,
CreationFlags, nil, nil, StartupInfo, ProcessInfo
);
if Success then
begin
Result := frOk;
CloseHandle(PipeOutputWrite);
CloseHandle(PipeErrorsWrite);
OutStream := TMemoryStream.Create;
ErrStream := TMemoryStream.Create;
try
repeat
WaitResult := WaitForSingleObject(ProcessInfo.hProcess, 100);
NumberOfBytesRead := 0;
if PeekNamedPipe(PipeOutputRead, nil, 0, nil, @NumberOfBytesRead, nil) and (NumberOfBytesRead > 0) then
begin
while ReadFile(PipeOutputRead, Buffer, Length(Buffer) - 1, NumberOfBytesRead, nil) and not frmStatus.Cancel do
begin
OutStream.Write(Buffer, NumberOfBytesRead);
for var i := 0 to NumberOfBytesRead - 1 do
begin
Line := Line + Char(Buffer[i]);
if Char(Buffer[i]) = #$0A then
begin
if Line.Contains('SourceFile') then
begin
Inc(FileCounter);
Line := UTF8ToString(RawByteString(Line));
frmStatus.FilesProcessed := FileCounter;
Line := Line.Remove(Line.Length - 4, 4).Remove(0, 17);
frmStatus.ProcessingFile := Line.Replace('/', '\');
frmMain.StatusBar.Panels[3].Text := FileCounter.ToString;
frmMain.StatusBar.Panels[9].Text := TruncateFileName(frmStatus.ProcessingFile, (frmMain.StatusBar.Panels[9].Width - 10) div 9);
Application.ProcessMessages;
end;
Line := '';
end;
end;
end;
end;
NumberOfBytesRead := 0;
if PeekNamedPipe(PipeErrorsRead, nil, 0, nil, @NumberOfBytesRead, nil) and (NumberOfBytesRead > 0) then
begin
while ReadFile(PipeErrorsRead, Buffer, Length(Buffer) - 1, NumberOfBytesRead, nil) do
begin
ErrStream.Write(Buffer, NumberOfBytesRead);
end;
end;
Application.ProcessMessages;
until (WaitResult <> WAIT_TIMEOUT) or frmStatus.Cancel;
if frmStatus.Cancel then
Result := frCancel
else
begin
frmStatus.FilesProcessed := FileCounter;
frmStatus.ProcessingFile := Line;
frmMain.StatusBar.Panels[3].Text := FileCounter.ToString;
frmMain.StatusBar.Panels[9].Text := TruncateFileName(Line, (frmMain.StatusBar.Panels[9].Width - 10) div 9);
end;
OutStream.Position := 0;
Output.LoadFromStream(OutStream);
ErrStream.Position := 0;
Errors.LoadFromStream(ErrStream);
finally
OutStream.Free;
ErrStream.Free;
end;
CloseHandle(ProcessInfo.hProcess);
CloseHandle(ProcessInfo.hThread);
CloseHandle(PipeOutputRead);
CloseHandle(PipeErrorsRead);
end
else
begin
CloseHandle(PipeOutputRead);
CloseHandle(PipeOutputWrite);
CloseHandle(PipeErrorsRead);
CloseHandle(PipeErrorsWrite);
Result := frError;
end;
end;
initialization
finalization
end.