Среда, 26.07.2017, 01:48 Приветствую вас Гость | Группа "Гости" 


[ Новые сообщения · Участники · Правила форума · Поиск · RSS ]
Страница 1 из 11
Модератор форума: xXxSh@dowxXx, Anton93, Волк-1024 
delfcode » Delphi » Вопросы по Delphi » Отлов ответа из cmd (Нагуглил функцию, но явно косяк с кодировкой)
Отлов ответа из cmd
tatsuДата: Воскресенье, 24.01.2016, 18:04 | Сообщение # 1
Частый гость
Зарегистрирован: 17.05.2009
Группа: Пользователи
Сообщений: 27
Статус: Offline
Всем доброго времени суток. Собственно задача: Выполнять досовую команду, но ответ писать не в консоль приложения, а в переменную. Нагуглил функцию. Работает. Однако есть 1 нюанс. Функция возвращает байты точь в точь, поскольку использует именованный канал. Кирилическая винда в командную строку выплёвывает как правило ответ в кодировке 866. Однако на деле имеем вместо текста кучу знаков вопросов и всё. Для отладки выплюнул ответ в файл. Вооружлся notepad++ и hex-редактором. Сравнил байты, оказалось - инглишный текст соответствует ASCII, а вот там где должный быть кирилические символы - байты не известной кодировки. Подскажите, как привести это в читабельный вид. Функция:
Код
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 Char;
  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); // не переадресовывать stdinput
      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;


Ибо маст дай!
 
dolphinДата: Воскресенье, 24.01.2016, 22:14 | Сообщение # 2
Администратор
Сообщений: 902
Статус: Offline
Код
procedure TCmdThread.Execute;
var
  ExecInform   : TShellExecuteInfo;
  MemoryStream : TMemoryStream;
begin
ZeroMemory(@ExecInform,sizeOf(ExecInform));
  with ExecInform do
  begin
    cbSize := SizeOf(ExecInform);
    lpVerb := 'open';
    lpFile := 'cmd.exe';
    lpParameters := PChar('cmd /u /c '+ComandLine+'cmd.txt');
    nShow := SW_HIDE;
    fMask := $00000040;
  end;
  if not ShellExecuteEx(@ExecInform) then
  case ExecInform.hInstApp of
    2  : EndString:= 'Ôàéë íå íàéäåí';
    3  : EndString:= 'Ïóòü íå íàéäåí';
    5  : EndString:= 'Äîñòóï ê ôàéëó çàïðåùåí';
    8  : EndString:= 'He õâàòàåò ïàìÿòè';
    32 : EndString:= 'Íå íàéäåíà íåîáõîäèìàÿ DLL';
    26 : EndString:= 'Ôàéë çàõâà÷åí äðóãèì ïîëüçîâàòåëåì';
    27 : EndString:= 'Íå ïîëíàÿ èíôîðìàöèÿ î ñâÿçàííîì ñ ôàéëîì ïðèëîæåíèè';
    28 : EndString:= 'Èñòåêëî âðåìÿ íà âûïîëíåíèå îïåðàöèè DDE';
    29 : EndString:= 'Îøèáî÷íàÿ îïåðàöèÿ DDE';
    30 : EndString:= 'Îïåðàöèÿ DDE çàíÿòà';
    31 : EndString:= 'Íåò ïðèëîæåíèÿ, ñâÿçàííîãî ñ ôàéëîì';
  end
  else
  begin
    WaitForSingleObject(ExecInform.hProcess,INFINITE);
    CloseHandle(ExecInform.hProcess);
    MemoryStream := TMemoryStream.Create;
    MemoryStream.LoadFromFile('cmd.txt');
    OemToCharBuffA(MemoryStream.Memory,MemoryStream.Memory,MemoryStream.Size);
    SetString(EndString,PAnsiChar(MemoryStream.Memory),MemoryStream.Size);
    MemoryStream.Free;
  end;
  Synchronize(EndWork);
end;

procedure TCmdThread.EndWork;
begin
SendMessage(EndString);
end;


Надеюсь поможет


Система: Windows 10 x64, Windows XP
Среды программирования: Delphi 7, Delphi 10 Seattle

Я не профессионал, я всего лишь любитель
Я не вредитель, я всего лишь теоретик
 
tatsuДата: Воскресенье, 24.01.2016, 22:27 | Сообщение # 3
Частый гость
Зарегистрирован: 17.05.2009
Группа: Пользователи
Сообщений: 27
Статус: Offline
dolphin, В принципе суть ясна, но тебе не кажется, что использовать текстовики при такой задаче это малось костыльно. Собственно эту же задачу я уже реализовывал на питоне и думаю, что как раз таки копать надо в сторону перенаправления вывода, ранешь об этом не думал как-то, покопаю пайпы глубже.

Ибо маст дай!
 
NeoДата: Понедельник, 25.01.2016, 15:19 | Сообщение # 4
Модератор
Зарегистрирован: 04.05.2010
Группа: Модераторы
Сообщений: 316
Статус: Offline
Ч что, если тебе в cmd добавить chcp cp1251 или chcp utf8
???
 
delfcode » Delphi » Вопросы по Delphi » Отлов ответа из cmd (Нагуглил функцию, но явно косяк с кодировкой)
Страница 1 из 11
Поиск:

delfcode.ru © 2008 - 2017 Хостинг от uCoz