J'ai besoin d'exécuter une commande "find" de Windows à partir d'un logiciel Delphi. J'ai essayé d'utiliser la commande ShellExecute
, mais cela ne semble pas fonctionner. En C, j'utiliserais la procédure system
, mais ici ... je ne sais pas. Je voudrais faire quelque chose comme ça:
System('find "320" in.txt > out.txt');
Edit: Merci pour la réponse :) J'essayais d'exécuter 'Find' comme un exécutable, pas comme argument pour cmd.exe.
Un exemple utilisant ShellExecute()
:
procedure TForm1.Button1Click(Sender: TObject);
begin
ShellExecute(0, nil, 'cmd.exe', '/C find "320" in.txt > out.txt', nil, SW_HIDE);
Sleep(1000);
Memo1.Lines.LoadFromFile('out.txt');
end;
Notez que l'utilisation de CreateProcess()
au lieu de ShellExecute()
permet un bien meilleur contrôle du processus.
Idéalement, vous devriez également appeler cela dans un thread secondaire et appeler WaitForSingleObject()
sur le descripteur de processus pour attendre la fin du processus. La Sleep()
dans l'exemple est juste un hack pour attendre un certain temps pour que le programme démarré par ShellExecute()
se termine - ShellExecute()
ne fera pas cela. Si c'était le cas, vous ne pourriez pas, par exemple, simplement ouvrir une instance notepad
pour éditer un fichier, ShellExecute()
bloquerait votre application parent jusqu'à la fermeture de l'éditeur.
Variante 1 (en utilisant le CreateProcess "avancé"):
Cela exécutera un programme "DOS" et récupérera sa sortie:
function GetDosOutput(CommandLine: string; Work: string = 'C:\'): string; { Run a DOS program and retrieve its output dynamically while it is running. }
var
SecAtrrs: TSecurityAttributes;
StartupInfo: TStartupInfo;
ProcessInfo: TProcessInformation;
StdOutPipeRead, StdOutPipeWrite: THandle;
WasOK: Boolean;
pCommandLine: array[0..255] of AnsiChar;
BytesRead: Cardinal;
WorkDir: string;
Handle: Boolean;
begin
Result := '';
with SecAtrrs do begin
nLength := SizeOf(SecAtrrs);
bInheritHandle := True;
lpSecurityDescriptor := nil;
end;
CreatePipe(StdOutPipeRead, StdOutPipeWrite, @SecAtrrs, 0);
try
with StartupInfo do
begin
FillChar(StartupInfo, SizeOf(StartupInfo), 0);
cb := SizeOf(StartupInfo);
dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
wShowWindow := SW_HIDE;
hStdInput := GetStdHandle(STD_INPUT_HANDLE); // don't redirect stdin
hStdOutput := StdOutPipeWrite;
hStdError := StdOutPipeWrite;
end;
WorkDir := Work;
Handle := CreateProcess(nil, PChar('cmd.exe /C ' + CommandLine),
nil, nil, True, 0, nil,
PChar(WorkDir), StartupInfo, ProcessInfo);
CloseHandle(StdOutPipeWrite);
if Handle then
try
repeat
WasOK := windows.ReadFile(StdOutPipeRead, pCommandLine, 255, BytesRead, nil);
if BytesRead > 0 then
begin
pCommandLine[BytesRead] := #0;
Result := Result + pCommandLine;
end;
until not WasOK or (BytesRead = 0);
WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
finally
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
end;
finally
CloseHandle(StdOutPipeRead);
end;
end;
Variante 2:
Capturez la sortie de la console en [temps réel] et comment elle dans un TMemo:
procedure CaptureConsoleOutput(const ACommand, AParameters: String; AMemo: TMemo);
const
CReadBuffer = 2400;
var
saSecurity: TSecurityAttributes;
hRead: THandle;
hWrite: THandle;
suiStartup: TStartupInfo;
piProcess: TProcessInformation;
pBuffer: array[0..CReadBuffer] of AnsiChar; <----- update
dRead: DWord;
dRunning: DWord;
begin
saSecurity.nLength := SizeOf(TSecurityAttributes);
saSecurity.bInheritHandle := True;
saSecurity.lpSecurityDescriptor := nil;
if CreatePipe(hRead, hWrite, @saSecurity, 0) then
begin
FillChar(suiStartup, SizeOf(TStartupInfo), #0);
suiStartup.cb := SizeOf(TStartupInfo);
suiStartup.hStdInput := hRead;
suiStartup.hStdOutput := hWrite;
suiStartup.hStdError := hWrite;
suiStartup.dwFlags := STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW;
suiStartup.wShowWindow := SW_HIDE;
if CreateProcess(nil, PChar(ACommand + ' ' + AParameters), @saSecurity,
@saSecurity, True, NORMAL_PRIORITY_CLASS, nil, nil, suiStartup, piProcess)
then
begin
repeat
dRunning := WaitForSingleObject(piProcess.hProcess, 100);
Application.ProcessMessages();
repeat
dRead := 0;
ReadFile(hRead, pBuffer[0], CReadBuffer, dRead, nil);
pBuffer[dRead] := #0;
OemToAnsi(pBuffer, pBuffer);
AMemo.Lines.Add(String(pBuffer));
until (dRead < CReadBuffer);
until (dRunning <> WAIT_TIMEOUT);
CloseHandle(piProcess.hProcess);
CloseHandle(piProcess.hThread);
end;
CloseHandle(hRead);
CloseHandle(hWrite);
end;
end;
Source: delphi.wikia.com