gpt4 book ai didi

delphi - 如何获取从 GUI 应用程序启动的控制台窗口的句柄?

转载 作者:行者123 更新时间:2023-12-03 14:38:47 25 4
gpt4 key购买 nike

在我的 GUI 应用程序中,我运行控制台应用程序并需要其窗口的句柄。我尝试使用 EnumWindows(),请参阅下面的代码,但它不起作用。列表中没有我的控制台应用程序。

type
TEnumWindowsData = record
ProcessId: Cardinal;
WinHandle: THandle;
List: TStrings; // For test only
end;
PEnumWindowsData = ^TEnumWindowsData;

function FindWindow(hWnd: THandle; lParam: LPARAM): BOOL; stdcall;
var
ParamData: TEnumWindowsData;
ProcessId: Cardinal;
WinTitle: array[0..200] of Char; // For test only
begin
ParamData := PEnumWindowsData(lParam)^;
GetWindowThreadProcessId(hWnd, ProcessId);
if ProcessId <> ParamData.ProcessId then
Result := True
else begin
ParamData.WinHandle := hWnd;
Result := False;
end;
// For test only
GetWindowText(hWnd, WinTitle, Length(WinTitle) - 1);
ParamData.List.Add(IntToStr(ProcessId) + ' ' + IntToStr(hWnd) + ' ' + WinTitle);
end;

procedure TForm1.Button1Click(Sender: TObject);

function RunApp(const AProgram: string): Cardinal;
var
StartupInfo: TStartupInfo;
ProcessInformation: TProcessInformation;
begin
Result := 0;
...
if CreateProcess(nil, PChar(AProgram), nil, nil, False,
NORMAL_PRIORITY_CLASS, nil, nil, StartupInfo, ProcessInformation)
then
Result := ProcessInformation.dwProcessId;
...
end;

var
ParamData: TEnumWindowsData;
begin
ParamData.ProcessId := RunApp('cmd.exe /C D:\TMP\TEST.exe');
ParamData.WinHandle := 0;
ParamData.List := Memo1.Lines;
EnumWindows(@FindWindow, THandle(@ParamData));

FWindowHandle := ParamData.WinHandle;
end;

最佳答案

以下代码只是创建进程(控制台应用程序),通过AttachConsole将您的进程附加到新创建的控制台。函数并从附加的控制台使用 GetConsoleWindow 获取窗口句柄功能。

以下代码最大的弱点是 CreateProcess函数立即返回,当控制台尚未完全初始化时,当您尝试立即连接控制台时,您将失败。不幸的是,没有 WaitForInputIdle功能for console applications因此,作为一种可能的解决方法,我会选择尝试在某些有限的循环计数中附加控制台,一旦成功,获取句柄并分离控制台。

代码可能如下所示。那里的 RunApp 函数应该返回控制台窗口的句柄(假设您只从中运行控制台应用程序),并且应该等待大约。 1 秒用于您已开始可附加的控制台应用程序。您可以通过更改 Attempt 变量的初始值和/或更改 Sleep 间隔来修改此值。

function GetConsoleWindow: HWND; stdcall;
external kernel32 name 'GetConsoleWindow';
function AttachConsole(dwProcessId: DWORD): BOOL; stdcall;
external kernel32 name 'AttachConsole';

function RunApp(const ACmdLine: string): HWND;
var
CmdLine: string;
Attempt: Integer;
StartupInfo: TStartupInfo;
ProcessInfo: TProcessInformation;
begin
Result := 0;
FillChar(StartupInfo, SizeOf(TStartupInfo), 0);
FillChar(ProcessInfo, SizeOf(TProcessInformation), 0);
StartupInfo.cb := SizeOf(TStartupInfo);
StartupInfo.dwFlags := STARTF_USESHOWWINDOW;
StartupInfo.wShowWindow := SW_SHOWNORMAL;
CmdLine := ACmdLine;
UniqueString(CmdLine);
if CreateProcess(nil, PChar(CmdLine), nil, nil, False,
CREATE_NEW_CONSOLE, nil, nil, StartupInfo, ProcessInfo) then
begin
Attempt := 100;
while (Attempt > 0) do
begin
if AttachConsole(ProcessInfo.dwProcessId) then
begin
Result := GetConsoleWindow;
FreeConsole;
Break;
end;
Sleep(10);
Dec(Attempt);
end;
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
end;
end;

然后你可以例如通过这种方式更改启动的应用程序的控制台窗口的标题:

procedure TForm1.Button1Click(Sender: TObject);
var
S: string;
ConsoleHandle: HWND;
begin
ConsoleHandle := RunApp('cmd.exe');
if ConsoleHandle <> 0 then
begin
S := 'Hello! I''m your console, how can I serve ?';
SendTextMessage(ConsoleHandle, WM_SETTEXT, 0, S);
end;
end;

关于delphi - 如何获取从 GUI 应用程序启动的控制台窗口的句柄?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13796063/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com