私は別のプロセスからコンソールのバッファにアクセスするには? AttachConsole ERROR_INVALID_PARAMETER
は、DOSの16ビットアプリケーションであるReadConsoleOutputを呼び出すなど、(AttachConsoleを経由して)別のプロセスコンソールのバッファへのアクセスを取得したいです。私はパイプを使用することはできません。なぜなら、それは出力をsecuentiallyに書き出していないからです(私が何を意味するか知っていれば、FAR commanderのように "windows"をエミュレートします)。
だから私がすべき:
1)アプリ 2を起動するには)プロセスID 3を得る)AttachConsole(PROCID) 4を呼び出す)サイズ 5を取得するためにGetConsoleScreenBufferInfoを呼び出す)ReadConsoleOutput
を呼び出します問題は3です:AttachConsole irが0を返し、GetLastErrorを呼び出した後にERROR_INVALID_PARAMETER 87(0x57)が返されます。
AttachConsoleの唯一のパラメータはProcessIdであり、ProcessExplorerで正しくチェックされています(実際にはアプリケーションをエミュレートするntvdm.exeのPIDです)。
Delphiコード:フォームで
function AttachConsole(dwProcessId: DWORD): Cardinal; external kernel32 name 'AttachConsole';
var
Handle: HWND;
function EnumWindowsProc(hwnd: HWND; lParam: LPARAM): BOOL; stdcall;
var
s: string;
IsVisible, IsOwned, IsAppWindow: Boolean;
begin
Result := True;//carry on enumerating
IsVisible := IsWindowVisible(hwnd);
if not IsVisible then
exit;
IsOwned := GetWindow(hwnd, GW_OWNER)<>0;
if IsOwned then
exit;
IsAppWindow := GetWindowLongPtr(hwnd, GWL_STYLE) and WS_EX_APPWINDOW<>0;
if not IsAppWindow then
exit;
SetLength(s, GetWindowTextLength(hwnd));
GetWindowText(hwnd, PChar(s), Length(s)+1);
if AnsiContainsText(s, '????.EXE') then // set windows name to search
Handle := hwnd;
end;
procedure Test(Strings: TStrings);
var
ProcessID: Cardinal;
begin
Handle := 0;
EnumWindows(@EnumWindowsProc, 0);
Strings.Add('Handle: ' + IntToStr(Handle));
if Handle <> 0 then
SetForegroundWindow(Handle);
Sleep(100);
GetWindowThreadProcessId(Handle, @ProcessID);
Strings.Add('ProcessId: ' + IntToStr(ProcessID));
if AttachConsole(ProcessId) <> 0 then
Strings.Add('Ok Attached')
else
Strings.Add('Error: ' + IntToStr(GetLastError));
end;
ドロップメモとボタン。 OnClickコールテスト(Memo1.Lines)。
===== EDIT完全なソリューション=====
function AttachAndGetConsoleHandle(ProcessId: Cardinal): Cardinal;
begin
if not AttachConsole(ProcessId) then
raise Exception.Create('AttachConsole error: ' + IntToStr(GetLastError));
Result := GetStdHandle(STD_OUTPUT_HANDLE);
if Result = INVALID_HANDLE_VALUE then
raise Exception.Create('GetStdHandle(STD_OUTPUT_HANDLE) error: ' + IntToStr(GetLastError));
end;
procedure DettachConsole;
begin
if not FreeConsole then
raise Exception.Create('FreeConsole error: ' + IntToStr(GetLastError));
end;
function ReadConsole(ConsoleHandle: Cardinal): TStringList;
var
BufferInfo: _CONSOLE_SCREEN_BUFFER_INFO;
BufferSize, BufferCoord: _COORD;
ReadRegion: _SMALL_RECT;
Buffer: Array of _CHAR_INFO;
I, J: Integer;
Line: AnsiString;
begin
Result := TStringList.Create;
ZeroMemory(@BufferInfo, SizeOf(BufferInfo));
if not GetConsoleScreenBufferInfo(ConsoleHandle, BufferInfo) then
raise Exception.Create('GetConsoleScreenBufferInfo error: ' + IntToStr(GetLastError));
SetLength(Buffer, BufferInfo.dwSize.X * BufferInfo.dwSize.Y);
BufferSize.X := BufferInfo.dwSize.X;
BufferSize.Y := BufferInfo.dwSize.Y;
BufferCoord.X := 0;
BufferCoord.Y := 0;
ReadRegion.Left := 0;
ReadRegion.Top := 0;
ReadRegion.Right := BufferInfo.dwSize.X;
ReadRegion.Bottom := BufferInfo.dwSize.Y;
if ReadConsoleOutput(ConsoleHandle, Pointer(Buffer), BufferSize, BufferCoord, ReadRegion) then
begin
for I := 0 to BufferInfo.dwSize.Y - 1 do
begin
Line := '';
for J := 0 to BufferInfo.dwSize.X - 1 do
Line := Line + Buffer[I * BufferInfo.dwSize.X + J].AsciiChar;
Result.Add(Line)
end
end
else
raise Exception.Create('ReadConsoleOutput error: ' + IntToStr(GetLastError));
end;
AttachConsole関数に 'stdcall'呼び出し規約を追加してみてください。 – RRUZ