In my answer to this question, where the asker needed a fast way to get a directory listing of a folder on a network drive, I suggested using the DOS "dir" command. Unfortunately, it's a command, not a program, so you can't execute it with CreateProcess and so I had to put it in a batch file. I don't really like that solution. It feels like a hack to me. Does anyone know a way to run dir from Delphi instead of from an external batch file?
+3
A:
You don't need a batch file, you can just execute:
cmd.exe /c dir
You can check the option to command with cmd /?
:
c:> cmd /?
CMD [/A | /U] [/Q] [/D] [/E:ON | /E:OFF] [/F:ON | /F:OFF] [/V:ON | /V:OFF]
[[/S] [/C | /K] string]
/C Carries out the command specified by string and then terminates
: : : : :
paxdiablo
2010-03-23 13:52:44
Is there any way to do it invisibly? Calling cmd.exe will open up a DOS window in the middle of your app.
Mason Wheeler
2010-03-23 13:54:20
@Mason: See Mef's answer. The trick is to set wShowWIndow to SW_HIDE and include STARTF_USESHOWWINDOW in dwFlags.
gabr
2010-03-23 14:59:38
+17
A:
Invisible Solution (Create a pipe, execute the command, redirect stdout to the pipe, read out the pipe):
function Console(const Command: String): String;
var
StartupInfo: TStartupInfo;
ProcessInfo: TProcessInformation;
SecurityAttr: TSecurityAttributes;
OutputPipeRead, OutputPipeWrite: THandle;
Res: Boolean;
BufSize: Cardinal;
Buffer: String;
BytesRead: Cardinal;
begin
FillChar(ProcessInfo, SizeOf(TProcessInformation), 0);
FillChar(SecurityAttr, SizeOf(TSecurityAttributes), 0);
SecurityAttr.nLength := SizeOf(SecurityAttr);
SecurityAttr.bInheritHandle := true;
SecurityAttr.lpSecurityDescriptor := nil;
CreatePipe(OutputPipeRead, OutputPipeWrite, @SecurityAttr, 0);
FillChar(StartupInfo, SizeOf(TStartupInfo), 0);
StartupInfo.cb:=SizeOf(StartupInfo);
StartupInfo.hStdInput := 0;
StartupInfo.hStdOutput := OutputPipeWrite;
StartupInfo.hStdError := OutputPipeWrite;
StartupInfo.wShowWindow := SW_HIDE;
StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
Res := CreateProcess(nil, PChar(command), nil, nil, true,
CREATE_DEFAULT_ERROR_MODE or CREATE_NEW_CONSOLE or
NORMAL_PRIORITY_CLASS, nil, nil, StartupInfo, ProcessInfo);
CloseHandle(OutputPipeWrite);
Result := '';
if Res then
begin
SetLength(Buffer, 5000);
BufSize := Length(Buffer);
repeat
Res := ReadFile(OutputPipeRead, Buffer[1], BufSize, BytesRead, nil);
Result := Result + Copy(Buffer, 1, BytesRead);
until not Res;
WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
CloseHandle(ProcessInfo.hProcess);
end;
CloseHandle(OutputPipeRead);
end;
Sample Usage:
ShowMessage(Console('cmd /c dir C:\'));
Mef
2010-03-23 14:00:12
+1
A:
Why not FindFirstFile? It returns an attribute for each item that you can compare with FILE_ATTRIBUTE_DIRECTORY to check for a directory. I highly suspect that dir doesn't do anything else. Using the dir command is like using a bar to type on the keyboard.
ChristianWimmer
2010-03-23 16:14:08
Having followed the other thread, I think the OP was more interested in the invocation of the command shell interpreter, rather than "dir" specifically.
Conor Boyd
2010-03-23 19:26:23