|
#1
|
|||
|
|||
Чтение с консоли
Доброго дня. Есть программа скрин которой здесь:
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
|
||||
|
||||
Не пользовался такими функциями, но могу предположить, что чтение аттрибута вам ненужно, если там консоль интерпретируется как экран 80х25, то имеем 4000 байт, где 2000 байт аттрибут цвета (нафик вам ненужные) и 2000 байт собственно знаки. Потому скорее всего надо использовать ReadConsoleOutputCharacter. Могу так-же предположить, что вместо Buffer:array of integer; надо сделать Buffer:array[1..2000] of byte;
Тогда по логиге из Buffer вас будет интересовать 2 и 3 строка т.е. 81-240 символы. Жизнь такова какова она есть и больше никакова. Помогаю за спасибо. |
#3
|
|||
|
|||
Цитата:
|
#4
|
||||
|
||||
Можно и так конечно, хотя большой разницы нет, что 14 раз вызвать функцию с нужными координами, что прочитать один раз 160 байт и обращаться к нужному элементу по индексу.
Жизнь такова какова она есть и больше никакова. Помогаю за спасибо. |
#5
|
|||
|
|||
Только вопрос как получить это??!?!?!?
|
#6
|
||||
|
||||
У меня появилось сильное сомнение, что
Код:
hStdout := GetStdHandle(STD_OUTPUT_HANDLE) Жизнь такова какова она есть и больше никакова. Помогаю за спасибо. |
#7
|
|||
|
|||
Цитата:
|
#8
|
||||
|
||||
Я ведь тоже неиспользовал ранее этих функций, так-что тоже пионер в данном вопросе, но может у вас и правильно, а у меня он возвращает 0 и в Buffer у меня ничего невозвращается.
Жизнь такова какова она есть и больше никакова. Помогаю за спасибо. |
#9
|
||||
|
||||
Можно использовать 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
|
|||
|
|||
Цитата:
Да!!! Лед тронулся: Код:
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
|
|||
|
|||
Цитата:
Это было то, что нужно пошарив про функцию аттачконсоль, я нашел много интересного и написал: Код:
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; Спасибо огромное!!! |