Cześć.
Mam taki interesujący problem.
Poprzez mój program chcę odczytywać dane z programu cmd.exe.
Czy istnieje możliwość skopiowania danych, np. do kontrolki TMemo z programu cmd.exe?
W jaki sposób wywołać z poziomu mojej aplikacji(shellexecute?) program cmd.exe z parametrem np. net share(zasoby udostepnione) kopiując rezultat do TMemo, czy jest to w ogóle możliwe?
Ogólnie, chodzi o wydobycie ciekawych informacji z programów Windows, poprzez konsolę cmd.
Pozdrawiam
Pepe
Tak, dzieki, skorzystalem z kodu programu "guipex"
http://www.blueorbsoft.com/guipex/
Wykorzystałem następującą funkcję:
function TForm1.DosExecAndWait32(const FileName: string; var Output: string): DWORD;
{ func to execute a DOS app and pipe output to a string variable }
var
zAppName: array[0..512] of char;
StartupInfo: TStartupInfo;
SecurityAttrib: TSecurityAttributes;
ProcessInfo: TProcessInformation;
StdOutPipeWrite, StdOutPipeRead: THandle;
bResult: boolean;
Buffer: array[0..255] of Char;
BytesRead: Cardinal;
procedure WaitFor(processHandle: THandle);
var
msg: TMsg;
ret: DWORD;
begin
repeat
ret := MsgWaitForMultipleObjects(
1, { 1 handle to wait on }
processHandle, { the handle }
False, { wake on any event }
INFINITE, { wait without timeout }
QS_PAINT or { wake on paint messages }
QS_SENDMESSAGE { or messages from other threads }
);
if ret = WAIT_FAILED then Exit; { can do little here }
if ret = (WAIT_OBJECT_0 + 1) then
begin
{ Woke on a message, process paint messages only. Calling
PeekMessage gets messages send from other threads processed. }
while PeekMessage(msg, 0, WM_PAINT, WM_PAINT, PM_REMOVE) do
DispatchMessage(msg);
end;
until ret = WAIT_OBJECT_0;
end;
begin
with SecurityAttrib do
begin
nLength := SizeOf(SecurityAttrib);
bInheritHandle := True;
lpSecurityDescriptor := nil;
end;
// create pipe for standard output redirection
CreatePipe(StdOutPipeRead, // read handle
StdOutPipeWrite, // write handle
@SecurityAttrib, // security attributes
0 // number of bytes reserved for pipe - 0default
);
FillChar(zAppName, Sizeof(zAppName), #0);
StrPCopy(zAppName, FileName);
FillChar(StartupInfo, Sizeof(StartupInfo), #0);
with StartupInfo do
begin
cb := Sizeof(StartupInfo);
dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
wShowWindow := SW_HIDE;
hStdInput := GetStdHandle(STD_INPUT_HANDLE); // don't redirect stdinput
hStdOutput := StdOutPipeWrite;
hStdError := StdOutPipeWrite;
end;
if not CreateProcess(nil,
zAppName, { pointer to command line string }
nil, { pointer to process security attributes }
nil, { pointer to thread security attributes }
True, { handle inheritance flag }
CREATE_NEW_CONSOLE or { creation flags }
HIGH_PRIORITY_CLASS,
nil, { pointer to new environment block }
nil, { pointer to current directory name }
StartupInfo, { pointer to STARTUPINFO }
ProcessInfo) { pointer to PROCESS_INF } then
Result := DWORD(-1) { failed, GetLastError has error code }
else
begin
CloseHandle(StdOutPipeWrite);
// get all output until dos app finishes
repeat
// read block of characters (might contain carriage returns and line feeds)
bResult := ReadFile(StdOutPipeRead, Buffer, 255, BytesRead, nil);
// has anything been read?
if BytesRead > 0 then
begin
// finish buffer to PChar
Buffer[BytesRead] := #0;
// combine the buffer with the rest of the last run
Output := Output + Buffer;
end;
until not(bResult) or (BytesRead = 0);
Waitfor(ProcessInfo.hProcess);
GetExitCodeProcess(ProcessInfo.hProcess, Result);
CloseHandle(ProcessInfo.hProcess);
CloseHandle(ProcessInfo.hThread);
CloseHandle(StdOutPipeRead);
end;
end;
Niestety, w TMemo, do którego dane wczytuje nie mam polskich znaków!!! Dlaczego? Jak je uzyskać?
Wywołuje dane w ten sposób:
procedure TForm1.SpeedButton2Click(Sender: TObject);
var
Output: string;
CommandParams:string;
podprogram : string;
begin
CommandParams:=parametry.text;
podprogram:=programwyw.Text;
memo1.Clear;
DosExecAndWait32(podprogram + ' ' + CommandParams , Output);
memo1.Lines.Add('********************************************************************************');
memo1.Lines.Add(podprogram);
memo1.Lines.Add('Time: ' + timetostr(now) + ', Date: ' + Datetostr(now));
memo1.Lines.Add('');
memo1.Lines.Add('');
memo1.Lines.Add(output);
memo1.Lines.Add('********************************************************************************');
end;
Pozdr, pepe
Witam!
Sorry wielkie za odkopywanie tak starego tematu, ale przydał mi się właśnie bardzo z tym że potrzebuję się nieco dopytać.
Mianowicie wykorzystałem sobie kodzik z postu wyżej do odpalania pewnej aplikacji która działa tylko z wiersza poleceń. Wszystko działa miodnie, program się odpala, robi co mu kazałem i uzyskuję od niego odpowiedź. Problem w tym że po uzyskaniu odpowiedzi potrzebuję wysłać do niego kolejne polecenie i znów uzyskać odpowiedź, tak kilka razy. Przy czym program nie może zostać zamykany i uruchamiany ponownie pomiędzy komendami, są one ze sobą powiązane i dają wspólny efekt.
Dodam że bawiłem się komponentem TUnitedCMD oraz TDosCommand, nie pasują mi one bardzo ze względu na mechanizm działania (timer). Próbowałem wygrzebać coś z ich kodu, ale wychodzi na to że jestem zbyt zielony, nie potrafię tego zmusić do działania.
Proszę o pomoc!
Pozdrawiam!
musisz wgryźć się trochę w ten kod, jak widzisz komunikacja odbywa się poprzez ReadFile(StdOutPipeRead,...)
, oraz, czego nie widać, WriteFile(StdOutPipeWrite,...)
.
Poczytaj o "named pipes".
Opisany wyżej problem z polskimi literami wynika z różnej strony kodowej w oknie konsoli (CP852) i w reszcie systemu (CP1250).
Sęk w tym że próbowałem i za cholerę mi to nie działa :/
Robiłem takie coś:
// do buffera jest wrzucana komenda
// bwrite dalem typu dword - ale nawet nie wiem po co mi ta zmienna :/
WriteFile(StdOutPipeWrite, Buffer, Length(command), BWrite, nil);