Запустить программу и состыковать с существующей программой Delphi 2010 - PullRequest
3 голосов
/ 07 марта 2011

Есть ли в Delphi 2010 способ запустить приложение, используя ShellExecute, а затем закрепить это приложение внутри другого?

Т.е. программа, написанная на Delphi, содержит 1 форму.Когда форма показывается, запускается программа B, написанная на C #, и клиент подключается к форме программы A?

Пол

Ответы [ 2 ]

6 голосов
/ 07 марта 2011

Да, вы можете сделать это.Вам нужно получить дескриптор окна главной формы в другом процессе (вызов EnumWindows).Затем вызовите SetParent, чтобы сделать это окно дочерним для вашего окна.

Возможно, вы захотите изменить стиль окна, положение и т. Д. Также вызовите WaitForInputIdle прежде чем пытаться найти дескриптор окна в новом процессе.Вы должны дать новому процессу шанс начать.

Теперь у вас есть довольно странный зверь.Внутри одного контейнера у вас есть два процесса.Каждый процесс имеет свой собственный поток пользовательского интерфейса.Вы можете показывать и взаимодействовать с двумя модальными диалогами одновременно.Там действительно нет конца веселья вы можете получить с этим!


РЕДАКТИРОВАТЬ

Просто для удовольствия я попытался написать простой Delphiприложение, чтобы сделать это.Он довольно хрупкий и работает только для самых простых приложений.Я думаю, что вы могли бы потратить много времени, пытаясь сделать эту работу хорошо, и все же в конечном итоге получить неудовлетворительный результат.На вашем месте я бы искал другие решения, особенно если у вас есть источник для этого приложения на C #.Конечно, вы могли бы представить его функциональность как ActiveX?

В любом случае, для вашего удовольствия я предлагаю следующий чрезвычайно неполированный код:

program AppHost;

uses
  Windows, Messages, SysUtils, Forms, Controls, ComCtrls;

{$R *.res}

procedure ResizePage(Page: TTabSheet);
var
  hwnd: Windows.HWND;
  Rect: TRect;
begin
  hwnd := Page.Tag;
  Rect := Page.ClientRect;
  MoveWindow(hwnd, Rect.Left, Rect.Top, Rect.Right-Rect.Left, Rect.Bottom-Rect.Top, True);
end;

type
  PEnumData = ^TEnumData;
  TEnumData = record
    ProcessID: DWORD;
    hwnd: HWND;
  end;

function EnumWindowsProc(hwnd: HWND; lParam: LPARAM): BOOL; stdcall;
var
  ProcessId: DWORD;
  EnumData: PEnumData;
begin
  EnumData := PEnumData(lParam);
  GetWindowThreadProcessId(hwnd, ProcessId);
  if EnumData.ProcessID=ProcessID then begin
    EnumData.hwnd := hwnd;
    Result := False;
    exit;
  end;
  Result := True;
end;

procedure Absorb(PageControl: TPageControl; const App: string; StartupInfo: TStartupInfo);
var
  Page: TTabSheet;
  ProcessInformation: TProcessInformation;
  EnumData: TEnumData;
begin
  Page := TTabSheet.Create(PageControl);
  Page.PageControl := PageControl;
  Page.Caption := ChangeFileExt(ExtractFileName(App), '');
  CreateProcess(PChar(App), nil, nil, nil, False, 0, nil, nil, StartupInfo, ProcessInformation);
  WaitForInputIdle(ProcessInformation.hProcess, INFINITE);
  EnumData.ProcessID := ProcessInformation.dwProcessId;
  EnumData.hwnd := 0;
  EnumWindows(@EnumWindowsProc, LPARAM(@EnumData));
  Page.Tag := Integer(EnumData.hwnd);
  SetParent(HWND(Page.Tag), Page.Handle);
  ResizePage(Page);
end;

type
  TEventProvider = class
  private
    FForm: TForm;
    FPageControl: TPageControl;
    procedure FormResize(Sender: TObject);
  public
    constructor Create(Form: TForm; PageControl: TPageControl);
  end;

{ TEventProvider }

constructor TEventProvider.Create(Form: TForm; PageControl: TPageControl);
begin
  inherited Create;
  FForm := Form;
  FPageControl := PageControl;
  FForm.OnResize := FormResize;
end;

procedure TEventProvider.FormResize(Sender: TObject);
var
  i: Integer;
begin
  for i := 0 to FPageControl.PageCount-1 do begin
    ResizePage(FPageControl.Pages[i]);
  end;
end;

procedure Main(Form: TForm);
var
  StartupInfo: TStartupInfo;
  PageControl: TPageControl;
begin
  Form.ClientHeight := 600;
  Form.ClientWidth := 800;
  Form.Caption := 'All your processes are belong to us';
  PageControl := TPageControl.Create(Form);
  PageControl.Parent := Form;
  PageControl.Align := alClient;
  StartupInfo.cb := SizeOf(StartupInfo);
  GetStartupInfo(StartupInfo);
  Absorb(PageControl, 'C:\Windows\Notepad.exe', StartupInfo);
  Absorb(PageControl, 'C:\Program Files\CommandLine\depends.exe', StartupInfo);
  TEventProvider.Create(Form, PageControl);
end;

var
  Form: TForm;

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm, Form);
  Main(Form);
  Application.Run;
  Form.Free;
end.
1 голос
/ 07 марта 2011

Да, у меня есть доступ к программе на C #

Мне нужно решение, которое работает независимо от языка, но любая программа, загружаемая таким образом, будет той, которую мы напишем

GetProcessIDвозвращает 0?

Все, что я сейчас сделал, - это создание 2 программ на Delphi, 1 вызывает другую

Затем я хочу получить dockapp2 для стыковки внутри dockapp1 и чтобы пользователь не знал, чтоэто отдельная программа.

Если GetProcessID возвращает 0, это не идеально!

procedure TForm2.BitBtn1Click(Sender: TObject);
var 
n: Integer;
n2: Integer;
begin
  n := ShellExecute(0, 'open', PChar('c:\temp\dockapp2\dockapp2.exe'), nil, nil,     SW_SHOWNORMAL); 
  n2:= GetProcessId(n);
 Caption := IntToStr(n2);
end;
...