Zatrzymanie polecenia cmd w Delphi

0

witam,

mam kod który odpala mi polecenie w cmd w aplikacji a wynik podaje w stringu:

 function GetDosOutput(CommandLine: string; Work: string = 'C:\'): string;
var
  SA: TSecurityAttributes;
  SI: TStartupInfo;
  PI: TProcessInformation;
  StdOutPipeRead, StdOutPipeWrite: THandle;
  WasOK: Boolean;
  Buffer: array[0..255] of AnsiChar;
  BytesRead: Cardinal;
  WorkDir: string;
  Handle: Boolean;
begin
  Result := '';
  with SA do begin
    nLength := SizeOf(SA);
    bInheritHandle := True;
    lpSecurityDescriptor := nil;
  end;
  CreatePipe(StdOutPipeRead, StdOutPipeWrite, @SA, 0);
  try
    with SI do
    begin
      FillChar(SI, SizeOf(SI), 0);
      cb := SizeOf(SI);
      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), SI, PI);
    CloseHandle(StdOutPipeWrite);
    if Handle then
      try
        repeat
          WasOK := ReadFile(StdOutPipeRead, Buffer, 255, BytesRead, nil);
          if BytesRead > 0 then
          begin
            Buffer[BytesRead] := #0;
            Result := Result + Buffer;
          end;
        until not WasOK or (BytesRead = 0);
        WaitForSingleObject(PI.hProcess, INFINITE);
      finally
        CloseHandle(PI.hThread);
        CloseHandle(PI.hProcess);
      end;
  finally
    CloseHandle(StdOutPipeRead);
  end;
end;

pytanie brzmi jak mogę zatrzymać przetwarzanie takiego polecenia, np: podaje GetDosOutput('polecenie') i te polecenie robi sie 30 sekund.
chciałbym to moc zatrzymac... (w sysemowym cmd na win7 to jest bodajże CTRL+C)

0

(w sysemowym cmd na win7 to jest bodajże CTRL+C)

Skrót Ctrl+C istniał już od pierwszych wersji DOSa (a może nawet był już w QDOSie);

Kod, który używasz, nie służy do kontrolowania konsoli, a do przekierowania jej wyjścia (czyli pobrania wyjścia jako łańcucha); Pokaż w jaki sposób próbujesz wysłać Ctrl+C do konsoli.

0

wszystk osie zgadza, pytanie brzmialo jak zatrzymac wykonywanie polecenia, a wlasciwie powinno brzmiec jak wyslac ctrl+c (lub cos innego) do konsoli aby to zastopowac.

2

Zamień ten: WaitForSingleObject(PI.hProcess, INFINITE);
na pętle która czeka nie w nieskończoność a powiedzmy 250 msec.
Po czym albo robisz kolejny nawrót pętli albo przechodzisz do sekcji finally.

0

Przenalizuj sobie kod dołączony do tego posta wraz z exekiem. Skompilowane pod Delphi7. A i pewnie są prostsze sposoby, ale ten też działa i daje według mnie daje większe możliwości, dzięki łatwej obsłudze zewnętrznej klasy - komponentu. Pisanego na bazie VCL TUnitemCMD, ale poprawionego przeze mnie do wykorzystania w czystym WinAPI, w innych moich projektach. Bo tak wolałem :)

Kod uruchamia batcha - u mnie na dysku, który poprzez wywołania rar.eze i zrobieniu wcześniej list plików do dpakowania w %TMP%. Backupuje do dwóch *.rar'ów dwa inne podkatalogi z konfiguracją od Opery. trwa przynajmniej kilkanaście sekund, także nadaje się idealnie do Twoich testów. Po zakonczeniu, naciśnięcie kombinacji Ctrl+C lub innego klawisza zamyka konsolę, kończąc pracę programu. Zmiana fontów na OEM przy wypisywaniu na konsole, jak widzisz również dodałem.

EDIT: załacznik dodany, sorry ale wcześniej z pośpiechu go nie dałem.

0

moze to wystarczy:

  if not GenerateConsoleCtrlEvent(CTRL_C_EVENT, PI.dwProcessId) then

albo jeszcze wyszukalem terminaterprocess...

gorzej ze teraz wdrozylem prawdziwe polecenie cmd ktore chce przetwarzac i ono zawiesza mi aplikację (chodzi o generowane wyjscie cmd),
wiec musze chyba zamienic funkcje na cos innego.

@olesio zapomniales dac chyba zalacznika.

2

Co zawiesza? Już @_13th_Dragon napisał taki kod zawsze będzie "zawieszał" aplikację bo tam masz odczyt w pętli a później czekanie na zakończenie nie pozwalając użytkownikowi na nic. wstaw ten kod w osobny wątek to nie będzie "zawieszało".

0

@czlowiekxxxx: sorry, załącznik już dodany do poprzedniego posta. Z pośpiechu nie zauważyłem, że się nie załączył. Oczywiście u mnie wszystko odbywa się wedle mnie jak należy, na bazie oryginalnego kodu w wersji VCL TUnitedCMD. I nic się nie "wiesza".

0

Tak jak napisał @kAzek, wstaw kod w osobny wątek bo zawiesisz sobie aplikację.
Pod jakiś Button wstaw kod

var h:HWND;
begin
  h:=FindWindow(PChar(ClassName),PChar(WindowText));
  if IsWindow(h) then SendMessage(h,WM_CLOSE,0,0);
end;

*ClassName *i *WindowText *możesz sprawdzić np programem WinInfo.

0

Zastosowalem oryginalny komponent UnitedCMD (natchniony postem Olesia :) ).

Podpialem go pod memo i mam na zywo wyniki z konsoli, nic nie zawiesza sie.

nadal pozostaje problem stopowania przetwarzania.

Link do TUnitedCMD: http://kupa.info/hackme/download/delphi/komponenty/TUnitedCMD.zip

proszę o propozycje do zaistnialej sytuacji.

0

Znajdź ID procesu konsoli i po prostu 'kill process'. (To tak na chama).

0

Po kiego szukać, ma go w PI.hProcess

0

porzucilem tamta funkcje, na rzecz tunitedCMD, nie wiem za bardzo jak tam dobrac sie do cmd zeby go zkillowac.

1

@czlowiekxxxx Zobacz, że u mnie w wersji WinAPI modułu jest takie coś i powinieneś mieć to konkretnie tam:

        if ComTWTime.BRead = 0 then
        begin
          ThreadTerminated := True;
          Break;
        end;

Po prostu w innym przypadku wątek będzie trwał dalej. I nie wykona się ubijanie procesu otwartej konsoli z CMD. O ile dobrze zrozumiałem co chcesz osiągnąć. Także w kodzie VCL, jeśli się przy nim upierasz wykonaj coś w stylu Terminate aby przerwać działanie wątku. Bo inaczej, to co jest po ostatnim until się nie wykonuje. A kod nie chce niestety inaczej wyktyć tego, że otrzymywanie danych od tego co działa tam pod cmd.exe się zakończyło.

1 użytkowników online, w tym zalogowanych: 0, gości: 1