Скопировать текст из DOS окна
От: axiv  
Дата: 28.10.09 13:44
Оценка:
Здравствуйте

Вопрос в следующем: как скопировать содержимое консольного окна как текст.
Делать это надо периодически, скажем раз в секунду-две. Windows позволяет выделять участки или всё консольное окно и копировать. Как это сделать на языке. Содержимое консольного окна сложное (a'la NortonCommander) и поэтому перехват стандартного вывода не катит.

Заранее благодарю за помощь
Re: Скопировать текст из DOS окна
От: DarkMaster Украина http://www.bdslib.at.ua
Дата: 30.10.09 16:25
Оценка:
Здравствуйте, axiv, Вы писали:

A>Здравствуйте

A>
A>Вопрос в следующем: как скопировать содержимое консольного окна как текст.
Делать это надо периодически, скажем раз в секунду-две. Windows позволяет выделять участки или всё консольное окно и копировать. Как это сделать на языке. Содержимое консольного окна сложное (a'la NortonCommander) и поэтому перехват стандартного вывода не катит.

Попробуй найти окно по классу ConsoleWindowClass и по заголовку через EnumWindows() и отослать окну WM_GETTEXT.
WBR, Dmitry Beloshistov AKA [-=BDS=-]
Re[2]: Скопировать текст из DOS окна
От: Leonid Troyanovsky  
Дата: 31.10.09 09:50
Оценка:
Здравствуйте, DarkMaster, Вы писали:

DM>Попробуй найти окно по классу ConsoleWindowClass и по заголовку через EnumWindows() и отослать окну WM_GETTEXT.


Заголовок, вроде, и так известен
--
С уважением, LVT
Re: Скопировать текст из DOS окна
От: NordSky Россия  
Дата: 31.10.09 10:03
Оценка:
Здравствуйте, axiv, Вы писали:

A>Здравствуйте

A>
A>Вопрос в следующем: как скопировать содержимое консольного окна как текст.
Делать это надо периодически, скажем раз в секунду-две. Windows позволяет выделять участки или всё консольное окно и копировать. Как это сделать на языке. Содержимое консольного окна сложное (a'la NortonCommander) и поэтому перехват стандартного вывода не катит.

A>Заранее благодарю за помощь


Редирект то не потянет?
Re[2]: Скопировать текст из DOS окна
От: axiv  
Дата: 02.11.09 12:31
Оценка:
Здравствуйте, NordSky, Вы писали:

NS>Редирект то не потянет?


Что есть "редирект" в вашем понимании?
Re[2]: Скопировать текст из DOS окна
От: Pavel Dvorkin Россия  
Дата: 02.11.09 13:33
Оценка:
Здравствуйте, NordSky, Вы писали:

NS>Редирект то не потянет?


Думаю, что в общем случае нет. Вывод в ДОС-окно — не всегда вывод в stdout. В те времена была еще и манера писать напрямую в видеобуфер.
With best regards
Pavel Dvorkin
Re: ReadConsoleOutput
От: Аноним  
Дата: 02.11.09 14:06
Оценка:
Здравствуйте, axiv!

A>...Windows позволяет выделять участки или всё консольное окно и копировать.


http://msdn.microsoft.com/en-us/library/ms684965(VS.85).aspx
Re[3]: Скопировать текст из DOS окна
От: DarkMaster Украина http://www.bdslib.at.ua
Дата: 02.11.09 14:14
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

NS>>Редирект то не потянет?


PD>Думаю, что в общем случае нет. Вывод в ДОС-окно — не всегда вывод в stdout. В те времена была еще и манера писать напрямую в видеобуфер.


А сейчас разве через WriteConsoleOutput() нельзя вывести сразу блок символов(+атрибутов), не занимаясь вызовом связки SetCosoleCursorPosition()/WriteConsole().
WBR, Dmitry Beloshistov AKA [-=BDS=-]
Re[2]: ReadConsoleOutput
От: axiv  
Дата: 02.11.09 15:01
Оценка:
Здравствуйте, Аноним, Вы писали:
А>http://msdn.microsoft.com/en-us/library/ms684965(VS.85).aspx

BOOL WINAPI ReadConsoleOutput(
__in HANDLE hConsoleOutput,
__out PCHAR_INFO lpBuffer,
__in COORD dwBufferSize,
__in COORD dwBufferCoord,
__inout PSMALL_RECT lpReadRegion
);

Замечательно, то что надо!! НО, чем получить требуемый HANDLE hConsoleOutput? GetStdHandle(STD_OUTPUT_HANDLE);?
Хочу еще раз заметить, что консольное приложение — DOS-приложение, а копировать содержимое его окна надо в свое приложение(в моём случае в Memo)

Гуру хэндлов, потоков и вин-апи, кто-нибудь может предложить рабочий код, который мог бы копировать содержимое окна, скажем с запущенным NortonCommander'ом в Memo?
Re[3]: ReadConsoleOutput
От: DarkMaster Украина http://www.bdslib.at.ua
Дата: 02.11.09 15:19
Оценка:
Здравствуйте, axiv, Вы писали:

A>BOOL WINAPI ReadConsoleOutput(

A> __in HANDLE hConsoleOutput,
A> __out PCHAR_INFO lpBuffer,
A> __in COORD dwBufferSize,
A> __in COORD dwBufferCoord,
A> __inout PSMALL_RECT lpReadRegion
A>);

A>Замечательно, то что надо!! НО, чем получить требуемый HANDLE hConsoleOutput? GetStdHandle(STD_OUTPUT_HANDLE);?


Задай себе сначала вопрос — какой консоли и сам ответишь на вопрос. Если у тебя Виста или ХП — попробуй через AttachConsole(ProcessID) где ProcessID — ИД искомого процесса.

Ну а дальше:

function ReadAttributesAt(x,y: smallint): Byte;
var
  WasRead: Longint;
  Coor: TCoord;
  Temp: Smallint;
begin
  Coor.x := x;
  Coor.y := y;
  ReadConsoleOutputAttribute(SysConOut, @Temp, 1, Coor, WasRead);
  Result := Temp;
end;

function ReadCharAt(x,y: Smallint): Char;
var
  WasRead: Longint;
  Coor: TCoord;
begin
  Coor.x := x;
  Coor.y := y;
  ReadConsoleOutputCharacter(SysConOut, @Result, 1, Coor, WasRead);
  if WasRead = 0 then
    Result := #0;
end;
WBR, Dmitry Beloshistov AKA [-=BDS=-]
Re[3]: ReadConsoleOutput
От: DarkMaster Украина http://www.bdslib.at.ua
Дата: 02.11.09 15:47
Оценка:
Здравствуйте, axiv, Вы писали:

A>Гуру хэндлов, потоков и вин-апи, кто-нибудь может предложить рабочий код, который мог бы копировать содержимое окна, скажем с запущенным NortonCommander'ом в Memo?



Uses jclSysInfo,Windows....;

procedure TForm1.Button2Click(Sender: TObject);

type
  TAttachConsole=function (ProcessID:DWORD):boolean; stdcall;

var L:TStringList;
    i:integer;
    ProcessID:DWORD;
    AC:TAttachConsole;
    AKernel:Cardinal;
    x,y:integer;
    S:String;
begin
  L:=TStringList.Create;
  try
     jclSysInfo.RunningProcessesList(L,True);               // получаем список процессов (из JCL)
     ProcessID:=0;
     for i:=0 to Pred(L.Count) do
        if L.Strings[i]='C:\Windows\system32\cmd.exe' then  // ищем CMD.EXE
           begin
             ProcessID:=DWORD(L.Objects[i]);
             Break;
           end;
  finally L.Free; end;

  AC:=nil;

  if ProcessID>0 then
     begin
       AKernel:=LoadLibrary('kernel32.dll');
       @AC:=GetProcAddress(AKernel,'AttachConsole');
       if @AC<>nil then AC(ProcessID);
          begin
           S:='';
           for Y:=0 to 24 do
             begin
               for X:=0 to 79 do S:=S+ReadCharAt(X,Y);
               Memo1.Lines.Add(S);
               S:='';
             end;
           FreeConsole;       // консоль нужно отпустить
         end;
     end;
end;


Кстати, консоли нонче юникодные пошли, так что на это стоит обратить внимание.
WBR, Dmitry Beloshistov AKA [-=BDS=-]
Re[4]: ReadConsoleOutput
От: DarkMaster Украина http://www.bdslib.at.ua
Дата: 02.11.09 15:52
Оценка:
Здравствуйте, DarkMaster, Вы писали:

DM>Здравствуйте, axiv, Вы писали:


A>>Гуру хэндлов, потоков и вин-апи, кто-нибудь может предложить рабочий код, который мог бы копировать содержимое окна, скажем с запущенным NortonCommander'ом в Memo?


Блин, поспешил... Функция чтения символа с консоли — ниже.


function ReadCharAt(x,y: Smallint): Char;
var
  WasRead: Cardinal;
  Coor: TCoord;
begin
  Coor.x := x;
  Coor.y := y;
  ReadConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), @Result, 1, Coor, WasRead);
  if WasRead = 0 then
    Result := #0;
end;


И основной код нужно поправить чтобы:


      if ( @AC<>nil ) and AC(ProcessID) then   // <--- мы можем обломится на атаче к консоли
          begin   
              for Y:=0 to 24 do
WBR, Dmitry Beloshistov AKA [-=BDS=-]
Re[4]: Скопировать текст из DOS окна
От: Pavel Dvorkin Россия  
Дата: 03.11.09 05:32
Оценка:
Здравствуйте, DarkMaster, Вы писали:

DM>А сейчас разве через WriteConsoleOutput() нельзя вывести сразу блок символов(+атрибутов), не занимаясь вызовом связки SetCosoleCursorPosition()/WriteConsole().


Я думаю, что внутри она все же вызовет WriteConsole и далее, WriteFile. Просто потому, что иных механизмов в Windows ИМХО нет.

А вот

mem[$8000:0] = 65;

в DOS не редиректится точно, так как никакого файлового вывода тут нет.
With best regards
Pavel Dvorkin
Re[5]: поправка
От: Pavel Dvorkin Россия  
Дата: 03.11.09 06:16
Оценка:
mem[$b800:0] = 65;
With best regards
Pavel Dvorkin
Re: Скопировать текст из DOS окна
От: axiv  
Дата: 03.11.09 08:12
Оценка:
Всем спасибо
Re[5]: Скопировать текст из DOS окна
От: DarkMaster Украина http://www.bdslib.at.ua
Дата: 03.11.09 08:33
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Я думаю, что внутри она все же вызовет WriteConsole и далее, WriteFile. Просто потому, что иных механизмов в Windows ИМХО нет.

PD>А вот
PD>mem[$8000:0] = 65;
PD>в DOS не редиректится точно, так как никакого файлового вывода тут нет.

Хм... А вот интересно, через ReadProcessMemory() к этому куску памяти можно добраться? По идее — ничего не мешает. Через AtachConsole() я пример уже приводил в этой же ветке.
WBR, Dmitry Beloshistov AKA [-=BDS=-]
Re[6]: Скопировать текст из DOS окна
От: Pavel Dvorkin Россия  
Дата: 03.11.09 08:49
Оценка:
Здравствуйте, DarkMaster, Вы писали:


DM>Хм... А вот интересно, через ReadProcessMemory() к этому куску памяти можно добраться? По идее — ничего не мешает.


Если только это буфер не лежит в системном адресном пространстве.
With best regards
Pavel Dvorkin
Re[4]: ReadConsoleOutput
От: Pavel Dvorkin Россия  
Дата: 03.11.09 09:30
Оценка:
Здравствуйте, DarkMaster, Вы писали:

DM> ProcessID:=0;

DM> for i:=0 to Pred(L.Count) do
DM> if L.Strings[i]='C:\Windows\system32\cmd.exe' then // ищем CMD.EXE
DM> begin
DM> ProcessID:=DWORD(L.Objects[i]);
DM> Break;
DM> end;
DM> finally L.Free; end;

OpenProcess
GetProcessId

DM> AC:=nil;


DM> for Y:=0 to 24 do

DM> begin
DM> for X:=0 to 79 do S:=S+ReadCharAt(X,Y);

Нет никакой гарантии, что 25*80. GetConsoleScreenBufferInfo.
И проще все же вместо цикла GetConsoleOutput, то есть весь буфер сразу.
With best regards
Pavel Dvorkin
Re[5]: ReadConsoleOutput
От: DarkMaster Украина http://www.bdslib.at.ua
Дата: 03.11.09 10:03
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

DM>> ProcessID:=DWORD(L.Objects[i]);

PD>OpenProcess
PD>GetProcessId

А зачем? В МСДН говорят нужен ProcessID, а не хэндл процесса, который мы через OpenProcess достаем.

DM>> for X:=0 to 79 do S:=S+ReadCharAt(X,Y);

PD>Нет никакой гарантии, что 25*80. GetConsoleScreenBufferInfo.

Конечно нет.

PD>И проще все же вместо цикла GetConsoleOutput, то есть весь буфер сразу.


Ну дык я просто привел рабочую болванку кода. Неоптимальную, не учитывающую кучку нюансов и т.п. Но допиливать напильником буду только в том случае, если это мне будет нужно или интересно.
WBR, Dmitry Beloshistov AKA [-=BDS=-]
Re[6]: ReadConsoleOutput
От: Pavel Dvorkin Россия  
Дата: 03.11.09 10:28
Оценка:
Здравствуйте, DarkMaster, Вы писали:

DM>Здравствуйте, Pavel Dvorkin, Вы писали:


DM>>> ProcessID:=DWORD(L.Objects[i]);

PD>>OpenProcess
PD>>GetProcessId

DM>А зачем? В МСДН говорят нужен ProcessID, а не хэндл процесса, который мы через OpenProcess достаем.


Проще открыть процесс, чем перебирать все. ИМХО.


DM>Ну дык я просто привел рабочую болванку кода. Неоптимальную, не учитывающую кучку нюансов и т.п. Но допиливать напильником буду только в том случае, если это мне будет нужно или интересно.


+1
With best regards
Pavel Dvorkin
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.