加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

delphi – 如何从我的GUI应用程序启动控制台窗口的处理?

发布时间:2020-12-15 03:34:10 所属栏目:大数据 来源:网络整理
导读:在我的GUI应用程序中,我运行控制台应用程序,需要其窗口的处理.我尝试使用Enum Windows(),看下面的代码,但它不起作用.在列表中没有我的控制台应用程序 type TEnumWindowsData = record ProcessId: Cardinal; WinHandle: THandle; List: TStrings; // For test
在我的GUI应用程序中,我运行控制台应用程序,需要其窗口的处理.我尝试使用Enum Windows(),看下面的代码,但它不起作用.在列表中没有我的控制台应用程序
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,False,NORMAL_PRIORITY_CLASS,StartupInfo,ProcessInformation)
    then
      Result := ProcessInformation.dwProcessId;
    ...
  end;

var
  ParamData: TEnumWindowsData;
begin
  ParamData.ProcessId := RunApp('cmd.exe /C D:TMPTEST.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秒钟的控制台应用程序你开始可以附加.您可以通过更改尝试变量的初始值和/或更改睡眠间隔来修改此值.

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),CREATE_NEW_CONSOLE,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;

那么你可以以这种方式更改您的lauched应??用程序的控制台窗口的标题:

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,S);
  end;
end;

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读