Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Сделать на форме окно для консольного приложения?


Автор: Nicholas 30.11.2008, 13:03
В общем у меня в цикле много раз запускается консольное приложение (конвертор), но не много окон, а прога ждет пока оно завершится потом продолжает цыкл, мне надо чтоб его окно запускалось внутри моей формы!
Иначе по рабочему столу начинают прыгать окшки консольного приложения, то там то тут  smile))

Нашел пример http://forum.vingrad.ru/topic-32298.html. Исходник примера http://forum.vingrad.ru/act-Attach/type/post/id-239269.html.

Код

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    GroupBox1: TGroupBox;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  ProcessInfo:TProcessInformation;
  CMD:Cardinal;
  OldParent:HWND; //если захочет вернуть :)

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var StartUpInfo:TStartupInfo;
    PrConsole:String;
    pID:Cardinal;
begin
 FillChar(StartUpInfo,SizeOf(TStartUpInfo),0);
 StartUpInfo.cb:=SizeOf(TStartUpInfo);
 StartUpInfo.dwFlags:=STARTF_USESHOWWINDOW;
 StartUpInfo.wShowWindow:=SW_SHOW;
 PrConsole:=ExtractFilePath(ParamStr(0))+'Console\PrConsole.exe';
 if CreateProcess(nil,{'cmd.exe'}PChar(PrConsole),nil,nil,false,NORMAL_PRIORITY_CLASS,nil,nil,StartUpInfo,ProcessInfo) then
  begin
   repeat
    CMD:=findwindow('ConsoleWindowClass', nil);
    pID:=0;
    if CMD<>0 then
     begin
      GetWindowThreadProcessId(CMD,@pID);
      if pID<>ProcessInfo.dwProcessId then CMD:=0; //Ждем пока именно наша консоль не окажется на самом верху
     end;
   until (CMD<>0);
   OldParent:=Windows.SetParent(CMD,GroupBox1.Handle);
   SetWindowPos(CMD,0,5,20,GroupBox1.ClientWidth-15,GroupBox1.ClientHeight-20,0);
  end else
  begin
   ShowMessage({'cmd.exe - не найден!'}'PrConsole.exe - не найден!');
   Application.Terminate;
  end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
 TerminateProcess(ProcessInfo.hProcess,0);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 Close;
end;

end.


Что я пока не понял в примере, это то как окно появляется на форме и как оно таскается мышью... :(
Вообще мне нажна процедура которая будет в своих параметрах иметь еще и GroupBox в котором будет работать окно консольного приложения.

Сейчас я пользуюсь функцией которая запускает и ждет выполнения приложения:
Код


function SwitchToProg(const Path: string): Boolean;
var
  SI: TStartupInfo;
  PI: TProcessInformation;
  ExitCode: Cardinal;
begin
  FillChar(SI, SizeOf(SI), 0);
  SI.cb := SizeOf(SI);

  Result := CreateProcess(nil, PChar(Path), nil, nil, False, 0, nil, nil,
    SI, PI);

  if Result then
  begin
    Application.MainForm.Hide;
    while GetExitCodeProcess(PI.hProcess, ExitCode) and
      (ExitCode = STILL_ACTIVE) do
      ; // ждем завершения, пустой цикл
    Application.MainForm.Show;
  end;
end;


Подскажите как ее переделать что было примерно так
Код

function SwitchToProg(const Path: string,GroupBox1:TGroupBox): Boolean;


Может ктонибудь предложит вариант проще??? 

Автор: Letov 30.11.2008, 15:11
Интересная задача. Я, например, тяжело представляю себе как запускать приложение внутри своей формы (как я понял - консоль должна появляться в GroupBox1).
Есть другой интересный метод.
Например, запускать скрытый консольный процесс, и, если надо, перехватывать вывод консоль, например, с помощью пайпов (Pipe) и выводить ее в Memo.
В общем случает - смотри http://drkb.ru/. Там это есть.

Код

function SwitchToProg(const Path: string): Boolean;
var
  SI: TStartupInfo;
  PI: TProcessInformation;
  ExitCode: Cardinal;
begin
  FillChar(SI, SizeOf(SI), 0);
  SI.cb := SizeOf(SI);

  Result := CreateProcess(nil, PChar(Path), nil, nil, False, 0, nil, nil,
    SI, PI);

  if Result then
  begin
    Application.MainForm.Hide;
    while GetExitCodeProcess(PI.hProcess, ExitCode) and
      (ExitCode = STILL_ACTIVE) do
         Application.ProcessMessages
      ; // ждем завершения
    Application.MainForm.Show;
  end;
end;

Так лучше^^.

Автор: bems 30.11.2008, 18:23
Думаю, лучше так: сначала вызываешь AllocConsole. Новый процесс создаешь не указывая флажки DETACHED_PROCESS, CREATE_NEW_CONSOLE, CREATE_NEW_PROCESS_GROUP. Новый процесс унаследует твою консоль, и вместо привязки каждой новой консоли к твоему окну, достаточно это сделать один раз для своей консоли. Для этого сначала получаешь хэндл консольного окна (это GetConsoleWindow в новых виндах и куча сомнительных трюков в старых - ищи по форуму), а потоми делаешь SetParent этому окну

Автор: Nicholas 3.12.2008, 15:29
Цитата(bems @ 30.11.2008,  18:23)
Думаю, лучше так: сначала вызываешь AllocConsole. Новый процесс создаешь не указывая флажки DETACHED_PROCESS, CREATE_NEW_CONSOLE, CREATE_NEW_PROCESS_GROUP. Новый процесс унаследует твою консоль, и вместо привязки каждой новой консоли к твоему окну, достаточно это сделать один раз для своей консоли. Для этого сначала получаешь хэндл консольного окна (это GetConsoleWindow в новых виндах и куча сомнительных трюков в старых - ищи по форуму), а потоми делаешь SetParent этому окну

 smile 

Я без собранного во едино кода нифига не пойму :(

Автор: bems 3.12.2008, 20:25
ну вот тебе пример: 
Код

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls;

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

function GetConsoleWindow:HWND;external 'kernel32.dll';

procedure TForm1.Button1Click(Sender: TObject);
var wnd:HWND;
    pi:TProcessInformation;
    si:TStartupInfo;
begin
AllocConsole;
wnd:=GetConsoleWindow;
Windows.SetParent(wnd,Panel1.Handle);
SetWindowPos(wnd,0,0,0,Panel1.Width,Panel1.Height,0); 
ZeroMemory(@si,SizeOf(si));
si.cb:=SizeOf(si);
if CreateProcess(nil,'cmd.exe',nil,nil,False,0,nil,nil,si,pi)
   then begin
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread)
        end;
end;

end.


Автор: Nicholas 4.12.2008, 04:56
Нее, я все забыл... :(

п.с. Спасибо за пример.

Автор: Nicholas 4.6.2011, 19:08
Подскажите, как сделать, что бы консольное окно никак не реагировало ни на мышь, ни на клавиатуру? Т.е. надо, что оно просто выводило результаты работы, а главное никто эту работу не мог прервать.

п.с.
Убрал заголовок и запретил изменение размеров так:
Код

// скрываем заголовок окна
SetWindowLong(wnd, GWL_STYLE, GetWindowLong(wnd, GWL_STYLE) xor WS_BORDER);
// запрещаем изменение размера окна
SetWindowLong(wnd, GWL_STYLE, GetWindowLong(wnd, GWL_STYLE) And Not WS_THICKFRAME);



Автор: Nicholas 20.6.2011, 07:26
Модераторы, можете тему перенести в ветку "Delphi: WinAPI и системное программирование" ?
а то здесь она заглохнет судя по всему...

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)