как получить содержимое консольного окна в виде текста если известен его handle? А решение этой задачи точно есть ( Ведь винда это как-то делает (Правка -> Выделить -> Копировать... и т.п.) Заранее сэнкс
Функции в помощь: AttachConsole ReadConsole ReadConsoleOutput GetConsoleSelectionInfo Многие функции есть только в NT-системах. В других лучше использовать свое консольное приложение как редиректор, запускающий чужое (см. CreateProcess). По этой ссылке, можно загрузить пример редиректора консоли, на Дельфийском наречии.
The ReadConsoleOutput function reads character and color attribute data from a rectangular block of character cells in a console screen buffer, and the function writes the data to a rectangular block at a specified location in the destination buffer. BOOL ReadConsoleOutput( HANDLE hConsoleOutput, // handle of a console screen buffer PCHAR_INFO lpBuffer, // address of buffer that receives data COORD dwBufferSize, // column-row size of destination buffer COORD dwBufferCoord, // upper-left cell to write to PSMALL_RECT lpReadRegion // address of rectangle to read from );
_DEN_ И в чем же сложность тогда? Если предполагается подключаться к уже запущенному процессу, не имея на руках описателей консоли, можно просто внедрить DLL.
Для тех, кто, как и я, долго ...лся в поисках решения проблемы: Чтение текста из чужого консольного окна (на Delphi 5). К сожалению, пока только для XP: Код (Text): 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; begin @AttachConsole := GetProcAddress(GetModuleHandle('kernel32.dll'), 'AttachConsole'); GetWindowThreadProcessId(FindWindow(nil, '[1/2] {D:\MyFolder\zDown\Тексты} - Far'), // Текст заголовка должен быть записан сюда полностью @mProcessID); if AttachConsole(mProcessID) then begin Hcwnd:=GetStdHandle(STD_OUTPUT_HANDLE); GetConsoleScreenBufferInfo (Hcwnd, BufInfo); GetMem(lpCh, BufInfo.dwMaximumWindowSize.Y*BufInfo.dwMaximumWindowSize.X); try for i:=0 to BufInfo.dwMaximumWindowSize.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.Y*BufInfo.dwMaximumWindowSize.X); end; end; end. архив с исходником приложен. 1972767194__ConsoleScreenBuffer.rar
>можно просто внедрить DLL. А вот это оказалось не так просто. Что с помощью хука WH_GETMESSAGE, что с помощью CreateRemoteThread, один фиг - в консольное окно, может, и внедряется, но вот проверить это никак - не могу оттуда даже имя модуля посмотреть - в случае WH_GETMESSAGE не вызывается функция обработки сообщений (проверял на гуишном окне - на нем вызывается нормально), а в случае CreateRemoteThread полная тишина и отсутствие любых ошибок и исключений. Подскажите в таком случае, как внедрить dll в процесс с консольным окном, чтобы потом можно было получить у него STD_OUTPUT_HANDLE?
поправка: в случае CreateRemoteThread, DLLEntryPoint при инжекте не вызывается, а если смотреть имя модуля в другой процедуре, вызываемой из внедряющей проги, получим имя модуля этой самой проги, а не того модуля, в чей процесс внедряли. Возможно ли в принципе внедрить dll в процесс консольного окна и как?
Консольное - не GUI, там нет цикла сообщений и прочих GUI-премудростей. Следовательно, и хуки не работают.
delpher Можно внедрится посредством Toolhelp32 и потоковых (SetThreadContext) функций, в любой процесс - главное чтобы хватало привелегий.
Доброго времени суток! эта тема для меня стала актуальна. Хочу прикрутить WinAVR к RadASM 3.0. Но утилитка Make, будь она не ладна, не хочет работать на прямую. Переназначение стандартного вывода (cmd /K "make -B -C default" > 1.txt) тоже не дает требуемого результата. Может кто-то уже сделал что-то похожее? Ато я тут нагородил. Код (Text): GetConsoleTxt proc lpTitle:DWORD LOCAL mProcessID :DWORD LOCAL Hcwnd :DWORD LOCAL chRead :DWORD LOCAL BufInfo :CONSOLE_SCREEN_BUFFER_INFO; LOCAL lpCh :DWORD LOCAL Coord :COORD; LOCAL hWndC :DWORD; mov [hWndC], rv(FindWindow, NULL,[lpTitle]) invoke GetWindowThreadProcessId,[hWndC],ADDR[mProcessID]; .if rv(AttachConsole,[mProcessID]) mov [Hcwnd],rv(GetStdHandle,STD_OUTPUT_HANDLE); fn GetConsoleScreenBufferInfo,[Hcwnd],ADDR[BufInfo]; PrintHex BufInfo.dwMaximumWindowSize.x movzx edx, [BufInfo.dwMaximumWindowSize.x] PrintDec edx PrintHex BufInfo.dwMaximumWindowSize.y movzx ecx, [BufInfo.dwMaximumWindowSize.y] movzx edx, [BufInfo.dwMaximumWindowSize.y] mov [lpCh], rv(LocalAlloc,LMEM_FIXED,rv(MulDiv,ecx,edx,1)) movzx edx, [BufInfo.dwMaximumWindowSize.x] mov BYTE ptr[eax+edx],0 xor eax,eax .while ax<[BufInfo.dwMaximumWindowSize.y] mov [Coord.x],0 mov [Coord.y],ax push eax movzx edx, [BufInfo.dwMaximumWindowSize.x] fn ReadConsoleOutputCharacter,[Hcwnd],[lpCh], edx, DWORD ptr[Coord],ADDR[chRead]; PrintStringByAddr lpCh movzx edx, [BufInfo.dwMaximumWindowSize.x] mov BYTE ptr[eax+edx],0 invoke OutputString,[lpCh] invoke OutputString,addr szCR pop eax inc eax PrintDec eax .endw invoke FreeConsole invoke LocalFree,[lpCh] .endif; ret GetConsoleTxt endp Всё хорошо. Инфу с окна снимаю. Но есть пару НО. 1. invoke FreeConsole - если эта строчка есть приложение вылетает. Приложение вкурсе что произошла ошибка и предлагает сохраниться. 2. invoke FreeConsole - если этой строчки нет, то всё ОК пока не закроешь новую консоль приложение опять вылетает безо всякого сообщения.