Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > [ "Начинающим" ]
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 05.04.2009, 13:23
8shar 8shar вне форума
Прохожий
 
Регистрация: 05.04.2009
Сообщения: 6
Репутация: 10
Злость Чтение с консоли

Доброго дня. Есть программа скрин которой здесь:
http://antsa.narod.ru/img.jpg
Вверху есть рамочка, в рамочке значения давления, температуры, расхода, мне нужно их забрать от туда. Программа старая (вроде как) MSDOS, использует процесс который называется NTVDM.EXE, он является вирт.машиной, исполняющей 16-разрядные ДОС-приложения.
Все это выводиться в консоль (CMD проще говоря).
Мне позарез нужно достать от туда эти данные:
Что я УЖЕ (за 3 дня) знаю что есть:

ReadConsoleOutput
http://winapi.freetechsecrets.com/wi...soleOutput.htm
В ReadConsoleOutput функция читает характер и цвет атрибут данных из прямоугольных блоков характера клеток в буфер экрана консоли, а также функция записывает данные в прямоугольных блоков на указанном месте в буфер назначения.

ReadConsoleOutputAttribute
http://winapi.freetechsecrets.com/wi...tAttribute.htm
В ReadConsoleOutputAttribute функция копии указанного количества плана и цвет фона атрибуты из последовательных ячеек консольный буфер экрана, начиная с указанного места.


ReadConsoleOutputCharacter
http://winapi.freetechsecrets.com/wi...tCharacter.htm
В ReadConsoleOutputCharacter функция копии ряда персонажей из последовательных ячеек консольный буфер экрана, начиная с указанного места.

Я делаю:
Код:
var
 pid: DWORD;
 hStdout: thandle;
 Buffer:array of integer;
 c:coord;
 wr:cardinal;
begin
 c.X:=1;
 c.Y:=1;
 GetWindowThreadProcessId(FindWindow('C:\WINDOWS\system32\cmd.exe',nil), @pid);
 hStdout := GetStdHandle(STD_OUTPUT_HANDLE);
 ReadConsoleOutputAttribute(hStdout,@Buffer[0],2,C,Wr);

 Memo1.Lines.Add(IntToStr(buffer[0]));
 Memo1.Lines.Add(IntToStr(wr));
end;
Но не работает. Помогите пожалуйста разобраться. Мне просто позарез нужны эти цифры...
Ответить с цитированием
  #2  
Старый 05.04.2009, 14:06
Аватар для Страдалецъ
Страдалецъ Страдалецъ вне форума
Гуру
 
Регистрация: 09.03.2009
Адрес: На курорте, из окна вижу теплое Баренцево море. Бррр.
Сообщения: 4,723
Репутация: 52347
По умолчанию

Не пользовался такими функциями, но могу предположить, что чтение аттрибута вам ненужно, если там консоль интерпретируется как экран 80х25, то имеем 4000 байт, где 2000 байт аттрибут цвета (нафик вам ненужные) и 2000 байт собственно знаки. Потому скорее всего надо использовать ReadConsoleOutputCharacter. Могу так-же предположить, что вместо Buffer:array of integer; надо сделать Buffer:array[1..2000] of byte;
Тогда по логиге из Buffer вас будет интересовать 2 и 3 строка т.е. 81-240 символы.
__________________
Жизнь такова какова она есть и больше никакова.
Помогаю за спасибо.
Ответить с цитированием
  #3  
Старый 05.04.2009, 14:18
8shar 8shar вне форума
Прохожий
 
Регистрация: 05.04.2009
Сообщения: 6
Репутация: 10
По умолчанию

Цитата:
Сообщение от Страдалецъ
Тогда по логиге из Buffer вас будет интересовать 2 и 3 строка т.е. 81-240 символы.
А там же есть C: coord мы задаем координаты точки откуда начинать чтение, и 2 значит сколько символов читать. Можно просто функцию написать потом ее 14 раз (по числу параметров) вызвать и записать в 14 переменных. а потом уже работать с ними.
Ответить с цитированием
  #4  
Старый 05.04.2009, 14:26
Аватар для Страдалецъ
Страдалецъ Страдалецъ вне форума
Гуру
 
Регистрация: 09.03.2009
Адрес: На курорте, из окна вижу теплое Баренцево море. Бррр.
Сообщения: 4,723
Репутация: 52347
По умолчанию

Можно и так конечно, хотя большой разницы нет, что 14 раз вызвать функцию с нужными координами, что прочитать один раз 160 байт и обращаться к нужному элементу по индексу.
__________________
Жизнь такова какова она есть и больше никакова.
Помогаю за спасибо.
Ответить с цитированием
  #5  
Старый 05.04.2009, 14:58
8shar 8shar вне форума
Прохожий
 
Регистрация: 05.04.2009
Сообщения: 6
Репутация: 10
По умолчанию

Только вопрос как получить это??!?!?!?
Ответить с цитированием
  #6  
Старый 05.04.2009, 16:50
Аватар для Страдалецъ
Страдалецъ Страдалецъ вне форума
Гуру
 
Регистрация: 09.03.2009
Адрес: На курорте, из окна вижу теплое Баренцево море. Бррр.
Сообщения: 4,723
Репутация: 52347
По умолчанию

У меня появилось сильное сомнение, что
Код:
 
hStdout := GetStdHandle(STD_OUTPUT_HANDLE)
правильно отрабатывает, чему равен у вас hStdout
__________________
Жизнь такова какова она есть и больше никакова.
Помогаю за спасибо.
Ответить с цитированием
  #7  
Старый 06.04.2009, 06:38
8shar 8shar вне форума
Прохожий
 
Регистрация: 05.04.2009
Сообщения: 6
Репутация: 10
По умолчанию

Цитата:
Сообщение от Страдалецъ
У меня появилось сильное сомнение, что
Код:
 
hStdout := GetStdHandle(STD_OUTPUT_HANDLE)
правильно отрабатывает, чему равен у вас hStdout
а как правильно?
Ответить с цитированием
  #8  
Старый 06.04.2009, 08:45
Аватар для Страдалецъ
Страдалецъ Страдалецъ вне форума
Гуру
 
Регистрация: 09.03.2009
Адрес: На курорте, из окна вижу теплое Баренцево море. Бррр.
Сообщения: 4,723
Репутация: 52347
По умолчанию

Я ведь тоже неиспользовал ранее этих функций, так-что тоже пионер в данном вопросе, но может у вас и правильно, а у меня он возвращает 0 и в Buffer у меня ничего невозвращается.
__________________
Жизнь такова какова она есть и больше никакова.
Помогаю за спасибо.
Ответить с цитированием
  #9  
Старый 06.04.2009, 21:45
Аватар для Karsh
Karsh Karsh вне форума
Активный
 
Регистрация: 22.09.2007
Адрес: SPb
Сообщения: 228
Версия Delphi: 7, 2009, XE2
Репутация: 70
По умолчанию

Можно использовать AttachConsole, но эта функция есть только в Windows XP и выше.
Вот готовая программа на WinAPI, котороя ловит окно по его названию и создает текстовый файл с содержимым этого окна.
Код:
program uAttachConsole;

uses                   
  Windows;

const
   _WIN32_WINNT = $0501;

type
   TAttachConsole = function (dwProcessId: DWORD): LongBOOL stdcall;

var
  AttachConsole: TAttachConsole;
  mProcessID, Wnd, Hcwnd, chRead: Cardinal;
  BufInfo: _CONSOLE_SCREEN_BUFFER_INFO;
  lpCh: PChar;
  Coord: _COORD;
  i: Integer;

function FileExists(const FileName: string): Boolean;
var
  FindData: TWin32FindData;
  F: THandle;
begin
  F:= FindFirstFile(PChar(FileName), FindData);
  Result:= (F <> INVALID_HANDLE_VALUE);
  if Result then FindClose(F);
end;

function ChangeFileExt(const FName, newExt: string): string;
var
  i, x, e: integer;
begin
  e:= Length(FName); x:= e;
  for i:= e downto 1 do
    if FName[i] = '.' then
    begin
      x:= i - 1;
      break;
    end;
  Result:= Copy(FName, 1, x) + newExt;
end;

function OpenFile(var fLog: TextFile; const LogFileName: String;
   const IsErase: Boolean = False): Boolean;
{var
   TmpStr: String; }
begin
{$I-}
   AssignFile(fLog, LogFileName);
   Result := IOResult = 0;
   if Result then begin
      if IsErase or (not FileExists (LogFileName)) then
         Rewrite(fLog)
      else
         Append(fLog);
      Result := IOResult = 0;
   end;
{$I+}
end;

function WriteLnStr(var fLog: TextFile; const fStr: string): boolean;
begin
{$I-}
   Writeln (fLog, fStr);
   Result := IOResult = 0;
   if Result then begin
      Flush (fLog);
      Result := IOResult = 0;
   end;
{$I+}
end;

procedure CloseFile(var fLog: TextFile);
begin
{$I-}
  Flush(fLog);
  System.CloseFile(fLog);
{$I+}
end;


function StrFile(const fStr, fFileName: String;
   const IsErase: Boolean = False): Boolean;
var
   fLog: TextFile;
begin
   Result := OpenFile(fLog, fFileName, IsErase);
   if Result then begin
      try
         Result := WriteLnStr(fLog, fStr);
      finally
         CloseFile(fLog);
      end;
   end;
end;

begin
  @AttachConsole:= GetProcAddress(GetModuleHandle('kernel32.dll'), 'AttachConsole');

  if @AttachConsole = nil then
  begin
    MessageBox(0, 'Программа работает только под Windows XP и выше!', 'Error', 16);
    Halt(1);
  end;

//  Wnd:= FindWindow(nil, 'Командная строка');
  Wnd:= FindWindow(nil, 'C:\WINDOWS\system32\cmd.exe');

  GetWindowThreadProcessId(Wnd, @mProcessID);

  if AttachConsole(mProcessID) then begin
    Hcwnd:= GetStdHandle(STD_OUTPUT_HANDLE);
    GetConsoleScreenBufferInfo(Hcwnd, BufInfo);
    GetMem(lpCh, BufInfo.dwMaximumWindowSize.X+1);
    try
      for i:=0 to BufInfo.dwSize.Y-1 do begin
         Coord.X := 0;
         Coord.Y := i;
         ReadConsoleOutputCharacter(Hcwnd, lpCh, BufInfo.dwMaximumWindowSize.X, Coord, chRead);
         StrFile(lpCh, ChangeFileExt(ParamStr(0), '.log'), False);
      end;
    finally
      FreeMem(lpCh, BufInfo.dwMaximumWindowSize.X+1);
    end;
  end;
  Halt(0);
end.
__________________
Начинающий программист уверен, что в 1 килобайте 1000 байт.
Законченный программист уверен, что в 1 километре 1024 метра.
Ответить с цитированием
  #10  
Старый 07.04.2009, 17:02
8shar 8shar вне форума
Прохожий
 
Регистрация: 05.04.2009
Сообщения: 6
Репутация: 10
По умолчанию

Цитата:
Сообщение от Karsh
Можно использовать AttachConsole, но эта функция есть только в Windows XP и выше.
Вот готовая программа на WinAPI, котороя ловит окно по его названию и создает текстовый файл с содержимым этого окна.
Код:
program uAttachConsole;

uses                   
  Windows;

const
   _WIN32_WINNT = $0501;

type
   TAttachConsole = function (dwProcessId: DWORD): LongBOOL stdcall;

var
  AttachConsole: TAttachConsole;
  mProcessID, Wnd, Hcwnd, chRead: Cardinal;
  BufInfo: _CONSOLE_SCREEN_BUFFER_INFO;
  lpCh: PChar;
  Coord: _COORD;
  i: Integer;

function FileExists(const FileName: string): Boolean;
var
  FindData: TWin32FindData;
  F: THandle;
begin
  F:= FindFirstFile(PChar(FileName), FindData);
  Result:= (F <> INVALID_HANDLE_VALUE);
  if Result then FindClose(F);
end;

function ChangeFileExt(const FName, newExt: string): string;
var
  i, x, e: integer;
begin
  e:= Length(FName); x:= e;
  for i:= e downto 1 do
    if FName[i] = '.' then
    begin
      x:= i - 1;
      break;
    end;
  Result:= Copy(FName, 1, x) + newExt;
end;

function OpenFile(var fLog: TextFile; const LogFileName: String;
   const IsErase: Boolean = False): Boolean;
{var
   TmpStr: String; }
begin
{$I-}
   AssignFile(fLog, LogFileName);
   Result := IOResult = 0;
   if Result then begin
      if IsErase or (not FileExists (LogFileName)) then
         Rewrite(fLog)
      else
         Append(fLog);
      Result := IOResult = 0;
   end;
{$I+}
end;

function WriteLnStr(var fLog: TextFile; const fStr: string): boolean;
begin
{$I-}
   Writeln (fLog, fStr);
   Result := IOResult = 0;
   if Result then begin
      Flush (fLog);
      Result := IOResult = 0;
   end;
{$I+}
end;

procedure CloseFile(var fLog: TextFile);
begin
{$I-}
  Flush(fLog);
  System.CloseFile(fLog);
{$I+}
end;


function StrFile(const fStr, fFileName: String;
   const IsErase: Boolean = False): Boolean;
var
   fLog: TextFile;
begin
   Result := OpenFile(fLog, fFileName, IsErase);
   if Result then begin
      try
         Result := WriteLnStr(fLog, fStr);
      finally
         CloseFile(fLog);
      end;
   end;
end;

begin
  @AttachConsole:= GetProcAddress(GetModuleHandle('kernel32.dll'), 'AttachConsole');

  if @AttachConsole = nil then
  begin
    MessageBox(0, 'Программа работает только под Windows XP и выше!', 'Error', 16);
    Halt(1);
  end;

//  Wnd:= FindWindow(nil, 'Командная строка');
  Wnd:= FindWindow(nil, 'C:\WINDOWS\system32\cmd.exe');

  GetWindowThreadProcessId(Wnd, @mProcessID);

  if AttachConsole(mProcessID) then begin
    Hcwnd:= GetStdHandle(STD_OUTPUT_HANDLE);
    GetConsoleScreenBufferInfo(Hcwnd, BufInfo);
    GetMem(lpCh, BufInfo.dwMaximumWindowSize.X+1);
    try
      for i:=0 to BufInfo.dwSize.Y-1 do begin
         Coord.X := 0;
         Coord.Y := i;
         ReadConsoleOutputCharacter(Hcwnd, lpCh, BufInfo.dwMaximumWindowSize.X, Coord, chRead);
         StrFile(lpCh, ChangeFileExt(ParamStr(0), '.log'), False);
      end;
    finally
      FreeMem(lpCh, BufInfo.dwMaximumWindowSize.X+1);
    end;
  end;
  Halt(0);
end.

Да!!!
Лед тронулся:
Код:
procedure TForm1.Button9Click(Sender: TObject);
type
   TAttachConsole = function (dwProcessId: DWORD): LongBOOL stdcall;
var
  AttachConsole: TAttachConsole;
  mProcessID, Hcwnd, chRead: Cardinal;
  BufInfo: _CONSOLE_SCREEN_BUFFER_INFO;
  lpCh : PChar;
  Coord: _COORD;
  i: Integer;

  Phwnd:HWND;
  ii:bool;
begin
  Phwnd:=FindWindow(nil,'C:\WINDOWS\system32\cmd.exe');

  @AttachConsole := GetProcAddress(GetModuleHandle('kernel32.dll'), 'AttachConsole');
  GetWindowThreadProcessId(Phwnd,@mProcessID);

  if AttachConsole(mProcessID) then begin
    Hcwnd:=GetStdHandle(STD_OUTPUT_HANDLE);
    GetConsoleScreenBufferInfo (Hcwnd, BufInfo);
    GetMem(lpCh, BufInfo.dwMaximumWindowSize.Y*BufInfo.dwMaximumWindowSize.X);
    Coord.X:=0;
    Coord.Y:=0;
   ii := ReadConsoleOutputCharacter(Hcwnd,lpCh,BufInfo.dwMaximumWindowSize.X,Coord,chRead);

    If ii then Memo1.Lines.Add('yes'); //успешон забрали с консоли
    If not ii then Memo1.Lines.Add('no'); //не забрали с консоли
     Memo1.Lines.Add(lpCh);  //выводим то что забрали

        Memo1.Lines.Add('Phwnd '+IntToStr(Phwnd));
        Memo1.Lines.Add('Hcwnd '+IntToStr(Hcwnd));
  end else Memo1.Lines.Add('Nea');

end;
Ответить с цитированием
  #11  
Старый 07.04.2009, 18:15
8shar 8shar вне форума
Прохожий
 
Регистрация: 05.04.2009
Сообщения: 6
Репутация: 10
По умолчанию

Цитата:
Сообщение от Karsh
Можно использовать AttachConsole, но эта функция есть только в Windows XP и выше.
Вот готовая программа на WinAPI, котороя ловит окно по его названию и создает текстовый файл с содержимым этого окна.
Код:
program uAttachConsole;

uses                   
  Windows;

const
   _WIN32_WINNT = $0501;

type
   TAttachConsole = function (dwProcessId: DWORD): LongBOOL stdcall;

var
  AttachConsole: TAttachConsole;
  mProcessID, Wnd, Hcwnd, chRead: Cardinal;
  BufInfo: _CONSOLE_SCREEN_BUFFER_INFO;
  lpCh: PChar;
  Coord: _COORD;
  i: Integer;

function FileExists(const FileName: string): Boolean;
var
  FindData: TWin32FindData;
  F: THandle;
begin
  F:= FindFirstFile(PChar(FileName), FindData);
  Result:= (F <> INVALID_HANDLE_VALUE);
  if Result then FindClose(F);
end;

function ChangeFileExt(const FName, newExt: string): string;
var
  i, x, e: integer;
begin
  e:= Length(FName); x:= e;
  for i:= e downto 1 do
    if FName[i] = '.' then
    begin
      x:= i - 1;
      break;
    end;
  Result:= Copy(FName, 1, x) + newExt;
end;

function OpenFile(var fLog: TextFile; const LogFileName: String;
   const IsErase: Boolean = False): Boolean;
{var
   TmpStr: String; }
begin
{$I-}
   AssignFile(fLog, LogFileName);
   Result := IOResult = 0;
   if Result then begin
      if IsErase or (not FileExists (LogFileName)) then
         Rewrite(fLog)
      else
         Append(fLog);
      Result := IOResult = 0;
   end;
{$I+}
end;

function WriteLnStr(var fLog: TextFile; const fStr: string): boolean;
begin
{$I-}
   Writeln (fLog, fStr);
   Result := IOResult = 0;
   if Result then begin
      Flush (fLog);
      Result := IOResult = 0;
   end;
{$I+}
end;

procedure CloseFile(var fLog: TextFile);
begin
{$I-}
  Flush(fLog);
  System.CloseFile(fLog);
{$I+}
end;


function StrFile(const fStr, fFileName: String;
   const IsErase: Boolean = False): Boolean;
var
   fLog: TextFile;
begin
   Result := OpenFile(fLog, fFileName, IsErase);
   if Result then begin
      try
         Result := WriteLnStr(fLog, fStr);
      finally
         CloseFile(fLog);
      end;
   end;
end;

begin
  @AttachConsole:= GetProcAddress(GetModuleHandle('kernel32.dll'), 'AttachConsole');

  if @AttachConsole = nil then
  begin
    MessageBox(0, 'Программа работает только под Windows XP и выше!', 'Error', 16);
    Halt(1);
  end;

//  Wnd:= FindWindow(nil, 'Командная строка');
  Wnd:= FindWindow(nil, 'C:\WINDOWS\system32\cmd.exe');

  GetWindowThreadProcessId(Wnd, @mProcessID);

  if AttachConsole(mProcessID) then begin
    Hcwnd:= GetStdHandle(STD_OUTPUT_HANDLE);
    GetConsoleScreenBufferInfo(Hcwnd, BufInfo);
    GetMem(lpCh, BufInfo.dwMaximumWindowSize.X+1);
    try
      for i:=0 to BufInfo.dwSize.Y-1 do begin
         Coord.X := 0;
         Coord.Y := i;
         ReadConsoleOutputCharacter(Hcwnd, lpCh, BufInfo.dwMaximumWindowSize.X, Coord, chRead);
         StrFile(lpCh, ChangeFileExt(ParamStr(0), '.log'), False);
      end;
    finally
      FreeMem(lpCh, BufInfo.dwMaximumWindowSize.X+1);
    end;
  end;
  Halt(0);
end.

Это было то, что нужно пошарив про функцию аттачконсоль,
я нашел много интересного и написал:
Код:
type
 TAttachConsole = function (dwProcessId: DWORD): LongBOOL stdcall;

var
 AttachConsole: TAttachConsole;
 mProcessID, Hcwnd: Cardinal;

procedure TForm1.FormCreate(Sender: TObject);
begin
 @AttachConsole := GetProcAddress(GetModuleHandle('kernel32.dll'), 'AttachConsole');
 GetWindowThreadProcessId(FindWindow(nil,'C:\WINDOWS\system32\cmd.exe'),@mProcess ID);
 AttachConsole(mProcessID);
end;

function TForm1.ReadCMD(x, y: byte): string;
const
 SMB = 4;
var
 chRead: Cardinal;
 BufInfo: _CONSOLE_SCREEN_BUFFER_INFO;
 lpCh : PChar;
 Coord: _COORD;
begin
   Hcwnd:=GetStdHandle(STD_OUTPUT_HANDLE);
   GetConsoleScreenBufferInfo (Hcwnd, BufInfo);
   GetMem(lpCh,SMB);
   Coord.X:=x;
   Coord.Y:=y;
   ReadConsoleOutputCharacter(Hcwnd,lpCh,SMB,Coord,chRead);
   Result:=copy(lpCh,1,SMB);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 Memo1.Lines.Add(ReadCMD(22,1));
end;
А вот это уже рабочий код, мы получаем 4 символа из CMD стоящие начиная с позиции x y передаваемой аргументами функции.
Спасибо огромное!!!
Ответить с цитированием
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 08:39.


 

Сайт

Форум

FAQ

RSS лента

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2023

ВКонтакте   Facebook   Twitter