AProcess.Output кирилицей

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Re: AProcess.Output кирилицей

Сообщение xchgeaxeax » 25.09.2024 13:27:02

Снег Север писал(а):Странно. У меня начиная с семерки всегда UTF8.

ЗЫ. Правда честно говоря консолью я пользуюсь в среднем один раз в году.

Во первых, там не UTF8, а UTF16BE. Намеки на использование в системе UTF8 появляются только в Win11.
Во вторых, проверять надо именно в консоли. Речь изначально идет о ней. Сначала тему прочитайте внимательнее, а потом говорите.
xchgeaxeax
постоялец
 
Сообщения: 125
Зарегистрирован: 11.05.2023 03:51:40

Re: AProcess.Output кирилицей

Сообщение xchgeaxeax » 25.09.2024 13:27:02

удвоение
xchgeaxeax
постоялец
 
Сообщения: 125
Зарегистрирован: 11.05.2023 03:51:40

Re: AProcess.Output кирилицей

Сообщение sts » 25.09.2024 14:35:41

Снег Север писал(а):Странно. У меня начиная с семерки всегда UTF8.

смотрел так (на всех стоит русский интерфейс)
в консоли xcopy > 1.txt, открыл 1.txt нотепадом++ и в какой кодировке читается текст, в файле - "Скопировано файлов: 0."
sts
постоялец
 
Сообщения: 431
Зарегистрирован: 04.04.2008 12:15:44
Откуда: Тольятти

Re: AProcess.Output кирилицей

Сообщение xchgeaxeax » 25.09.2024 15:48:33

можно тоже самое с ping localhost сделать или любой другой консольной командой, выдающий русский текст
xchgeaxeax
постоялец
 
Сообщения: 125
Зарегистрирован: 11.05.2023 03:51:40

Re: AProcess.Output кирилицей

Сообщение Alex2013 » 28.09.2024 15:05:54

ИМХО Для заметной части вариантов использования консоли вполне хватит "виртуальной консоли".
(А в ней особых проблем с кириллицей быть недолжно . "Memo и в африке Memo" )
Код: Выделить всё
// Выполнить команду в виртуальной консоли
Procedure RunDosInMemo(CmdLine: String; AMemo: TMemo);
Const
    ReadBuffer = 1023;
Var
    Security: TSecurityAttributes;
    OutReadPipe, OutWritePipe: tHandle; // труба для output'a консольной проги.
    InReadPipe, InWritePipe: tHandle; // труба для input'a консольной проги.
    ErrReadPipe, ErrWritePipe: tHandle; // труба для error's консольной проги.
    // InReadPipe, ErrReadPipe и объявлены для полноты картины,но не создаются
    //и не используются.
    start: TStartUpInfo;
    Buffer: Pchar;
    BytesRead: DWord;
    Apprunning: DWord;
    avail : dword;
    notread:dword;
    I,CL:Longint;
    CS:String;
     Int:TIniFile;

//   stop:boolean;
Begin
//flPBar:=F_M3U8toMP4.ProgressBar1;
//flPBar.Position:=0;
//flPBar.Min:=0;
fsDuration:='';
fsProgress:='';
fsVideo:='';
vsSpeed:='';
Process_stop := false;
    With Security Do Begin // инициализация структуры
        nlength := SizeOf(TSecurityAttributes);
        binherithandle := true;
        lpsecuritydescriptor := Nil;
    End;
    Createpipe(InReadPipe, InWritePipe, @Security, 0);
    Createpipe(ErrReadPipe, ErrWritePipe, @Security, 0);
    If Createpipe(OutReadPipe, OutWritePipe, @Security, 0) Then Begin
        // создали трубу для выхлопа бэкграунд-приложения
        Buffer := AllocMem(ReadBuffer + 1);
        // создали буфер для чтения
        FillChar(Start, Sizeof(Start), #0);
        // заполнили содержимое стартовой структуры #0
        start.cb := SizeOf(start);
        start.hStdOutput := OutWritePipe;
        start.hStdError := OutWritePipe;
        start.hStdInput := InReadPipe;
        (*************************************************************
            такой себе опширненьний комментарий...
            Оказывается, мать их так, если сделать перенаправление
            вывода в трубы, но не читать его, то если он(вывод)
            будет достаточно длинный и сможет переполнить буфер,
            который изначально отводится под трубу, то пишущий поток
            остановится и будет ждать пока не освободится место в
            буфере трубы. Как только оно освободилось, он сможет
            продолжать работу и писать дальше.

            start.hStdOutput := OutWritePipe;
            start.hStdError := OutWritePipe;

            почему собственно такой странный код: два потока
            перенаправлены в одну трубу?
            Потому что некоторые замечательные проги типа 7zip свой
            вывод направляют не в StdOut, а почему то в StdErr...
            и если для этих двух потоков назначить две разных трубы,
            а читать только одну, то произойдет то, что описано выше.
            РРРРРРРРРРРРРРРРРРРРРРРРР!!!!!!!!! сопли, слюни, ярость и
            буйное помешательство на почве программирования под винду.

            Может стоит сделать две трубы и читать каждую в отдельное
            мемо???
        **************************************************************)
        start.dwFlags := STARTF_USESTDHANDLES + STARTF_USESHOWWINDOW;
        start.wShowWindow := SW_HIDE;
        // окно прячем

        If CreateProcess(Nil, PChar(CmdLine), @Security, @Security, true, NORMAL_PRIORITY_CLASS,
            Nil, Nil, start, ProcessInfo) Then Begin
            // создали процесс
            Repeat

                Apprunning := WaitForSingleObject(ProcessInfo.hProcess, 100);
                PeekNamedPipe(OutReadPipe, @Buffer[0], ReadBuffer, @BytesRead, @avail, @notread);
                // PeekNamedPipe копирует из буфера трубы и оставляет его в первоначальном состоянии
                // в то время как ReadFile читая из трубы - опустошает ее.
                // PeekNamedPipe можно использовать для того чтобы узнать сколько данных есть в трубе
                // и если в PeekNamedPipe передать 2 и 3 параметры пустыми, то она просто скажет
                // сколько данных есть в трубе
                if avail > 0 then begin
                    ReadFile(OutReadPipe, Buffer[0], BytesRead, BytesRead, Nil); // *******
                    // ReadFile при чтении из трубы опустошает ее(трубы) буфер.
                end
                else begin
                    if Apprunning <> 258 then
                        Process_stop := true;
                end;
                // читаем через читающий конец трубы из вывода консоли
                Buffer[BytesRead] := #0;
                // последний символ #0 - конец буфера
                OemToAnsi(Buffer, Buffer);
                // перевели из кодировки DOS в кодировку WIN
                CL:=AMemo.Lines.Count;
                CS:=String(Buffer)+#0;

                if fsDuration<>'' then begin
                if fsProgress <>'' then begin
               If vsSpeed<>'' then
               { F_M3U8toMP4.Caption:=
                'M3U8 to MP4 ( Progress : ' + fsProgress+' )'+
                 // F_M3U8toMP4.Caption:= F_M3U8toMP4.Caption+
                                    ' Speed= '+vsSpeed+' kb/s';
                }
                // SendMessage(AMemo.Handle,EM_REPLACESEL,0,integer(@CS[1]));
                end
                else
                  With AMemo do
                if Lines[Lines.Count-1] <>'' then begin
                Lines.Add('');
                Lines.Add('Duration ='+fsDuration);
                Lines.Add('');Lines.Add('');
                end;

                end else  begin
                SendMessage(AMemo.Handle,EM_REPLACESEL,0,integer(@CS[1]));
                 AMemo.SelStart:=Length(AMemo.Lines.Text);
                //ReadInputStream(CS);
                //AMemo.Refresh;
             {  if WMainForm <> Nil then
               wnmainform.WMainForm.CmdBox
               .Write(WinCPToUTF8(String(Buffer)));
              }
               end;

             {   if WMainForm <> Nil then
               wnmainform.WMainForm.CmdBox
               .Write(WinCPToUTF8(String(Buffer)));
              }

                //GetDuration(CS);
               // GetFFTime(CS);
                //GetFFVideo(CS);

               {F_M3U8toMP4.CmdBox
                //Add( WinCPToUTF8(String(Buffer));
                .Write(WinCPToUTF8(String(Buffer)));}


               { if AMemo.VertScrollBar<> nil then
                 if CL<>AMemo.Lines.Count then //AMemo.VertScrollBar.Position:=
                 begin

                     AMemo.SelStart:=Length(AMemo.Lines.Text);
                  //  if  AMemo.Lines.Count >200 then AMemo.Lines.Delete(0);
                  //   AMemo.SelStart:=Length(AMemo.Lines.Text);
                    // AMemo.Refresh;
                 end; }
                // то что прочитали приписали к тексту в мемо
                Application.ProcessMessages;
                // обработали очередь сообщений
//            Until ((Apprunning <> WAIT_TIMEOUT) or (avail < 0));
            Until Process_stop;
            // прервемся когда процесс завершится
        // F_M3U8toMP4.Caption :='M3U8 to MP4';
        End;
        FreeMem(Buffer); // освободили буфер
         {WAIT_TIMEOUT
     WAIT_OBJECT_0 = 0;
     WAIT_ABANDONED_0 = $80;
     WAIT_TIMEOUT = $102;
     WAIT_IO_COMPLETION = $c0;
     WAIT_ABANDONED = $80;
     WAIT_FAILED = $ffffffff;
     MAXIMUM_WAIT_OBJECTS = $40;
     MAXIMUM_SUSPEND_COUNT = $7f;

         }
        //PostMessage(Handle, WM_QUIT, 0, 0);
       // GetExitCodeProcess(processInfo.dwProcessId
        //GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,processInfo.dwProcessId);
        //TerminateProcess(processInfo.hProcess, 0);

        {    if FindWindow(nil,PChar(Slots[i-1].GUID))<>0 then
       SendMessage(FindWindow(nil,PChar(Slots[i-1].GUID)),WM_CLOSE,0,0)
else
TerminateProcess(hProcess, NO_ERROR);
//.kill }
      // KillTask('ffmpeg.exe');
       Application.ProcessMessages;
       AMemo.Lines.Add('');

       If fsVideo<>'' Then begin
       AMemo.Lines.Add(fsVideo) ;
       {
       Int:=TIniFile.Create(ExtractFilePath(paramstr(0))+ ListMFName);
         Int.WriteString(F_M3U8toMP4.FF_NS,'FFMPEG_LocalFile',F_M3U8toMP4.FF_NF);
        Int.Free;
        }
        end
         Else
         begin
          KillProcessTree( ProcessInfo.dwProcessId);
          {
          Int:=TIniFile.Create(ExtractFilePath(paramstr(0))+ ListMFName);
          Int.DeleteKey(F_M3U8toMP4.FF_NS,'FFMPEG_LocalFile');
          Int.Free;
           }
         end;

          { then
         Amemo.Lines.add('Дерево процессов успешно завершено ')
       else
           Amemo.Lines.add('Ошибка завершеня ');
       }
        Application.ProcessMessages;
        CloseHandle(ProcessInfo.hProcess); // закрыли все хендлы
        CloseHandle(ProcessInfo.hThread);
        CloseHandle(OutReadPipe);
        CloseHandle(OutWritePipe);
        CloseHandle(InReadPipe);
        CloseHandle(InWritePipe);
        CloseHandle(ErrReadPipe);
        CloseHandle(ErrWritePipe);
    End;

    Amemo.Lines.Add('');
    Amemo.Lines.Add('==== процесс завершён ====');
    //' + FormatDateTime('dd.mm.yyyy h:mm:ss:zzz am/pm',dt) + '} ====');

    // конец.
End;

Изображение
Alex2013
долгожитель
 
Сообщения: 3048
Зарегистрирован: 03.04.2013 11:59:44

Re: AProcess.Output кирилицей

Сообщение sts » 29.09.2024 16:54:21

Alex2013 писал(а):OemToAnsi(Buffer, Buffer);
// перевели из кодировки DOS в кодировку WIN


т.е. работать будет тока при установленной 866

Добавлено спустя 21 минуту 40 секунд:
по хорошему в винде в STARTUPINFO должно быть поле в какой кодировке ты хочешь получать данные в каналах и если запускаемая прога меняет кодировку консоли, то перекодировать в заданную

Добавлено спустя 37 секунд:
при этом виндовая консоль это делает
sts
постоялец
 
Сообщения: 431
Зарегистрирован: 04.04.2008 12:15:44
Откуда: Тольятти

Re: AProcess.Output кирилицей

Сообщение xchgeaxeax » 29.09.2024 19:33:26

sts писал(а):при этом виндовая консоль это делает

Судя по тестам с cp 65001 это не так. Она просто использует предустановленные файлы локалей, а не перекодировку текстов от программы. Во всяком случае так делают стандартные её утилиты.
xchgeaxeax
постоялец
 
Сообщения: 125
Зарегистрирован: 11.05.2023 03:51:40

Re: AProcess.Output кирилицей

Сообщение Ustas » 30.09.2024 10:49:51

Доброго дня!

После долгих экспериментов получается:
1. батник в формате ANSI
Код: Выделить всё
@chcp 1251 > nul

2. строки перекодируются функцией
Код: Выделить всё
LazUTF8.WinCPToUTF8()


И тогда все выводиться кириллицей.
Всем спасибо за помощь, за мысли для размышлений.
Ustas
постоялец
 
Сообщения: 153
Зарегистрирован: 19.10.2009 14:58:10
Откуда: г.Муром

Пред.

Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 15

Рейтинг@Mail.ru