Встраивание окна в другой процесс - PullRequest
4 голосов
/ 30 сентября 2011

Я прочитал несколько постов здесь, на StackOverflow, но ни один не работал для меня. Вот код, который я использую для отображения окна стандартного Калькулятора в моей форме:

procedure TForm1.Button1Click(Sender: TObject);
var
  Tmp: Cardinal;
  R: TRect;
begin
  CalcWindow := FindWindow(nil, 'Calculator');
  if (CalcWindow <> 0) then
  begin
    GetWindowThreadProcessID(CalcWindow, CalcProcessID);

    Tmp := GetWindowLong(CalcWindow, GWL_STYLE);
    Tmp := (Tmp and not WS_POPUP) or WS_CHILD;
    SetWindowLong(CalcWindow, GWL_STYLE, Tmp);
    GetWindowRect(CalcWindow, R);

    SetForegroundWindow(CalcWindow);
    Windows.SetParent(CalcWindow, Panel1.Handle);
    SetWindowPos(CalcWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE or SWP_FRAMECHANGED);

    AttachThreadInput(GetCurrentThreadID(), CalcWindow, True);
  end;
end;

Оно отображает окно в моей форме, но стеклянная рамка теряется, и иногда (особенно когда я перемещаю форму) трудно восстановить фокус на встроенном окне (мне нужно нажать несколько раз).

Что может быть причиной этого? Кроме того, вы видите какие-либо потенциальные проблемы, с которыми я могу столкнуться при использовании этого метода?

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

Ответы [ 2 ]

6 голосов
/ 30 сентября 2011

Попробуйте этот код. Я взял это из одного из моих старых исходников. Вы потеряете стеклянную рамку, но главное меню видно, и я не заметил никаких проблем при настройке фокуса на встроенное приложение. Вы должны быть в состоянии сделать это, используя функцию API SetForegroundWindow (). Всякий раз, когда вы перемещаете форму контейнера, ваше встроенное приложение теряет фокус, поэтому вам нужно снова вызвать SetForegroundWindow, чтобы восстановить фокус:

procedure ShowAppEmbedded(WindowHandle: THandle; Container: TWinControl);
var
  WindowStyle : Integer;
  FAppThreadID: Cardinal;
begin
  /// Set running app window styles.
  WindowStyle := GetWindowLong(WindowHandle, GWL_STYLE);
  WindowStyle := WindowStyle
                 - WS_CAPTION
                 - WS_BORDER
                 - WS_OVERLAPPED
                 - WS_THICKFRAME;
  SetWindowLong(WindowHandle,GWL_STYLE,WindowStyle);

  /// Attach container app input thread to the running app input thread, so that
  ///  the running app receives user input.
  FAppThreadID := GetWindowThreadProcessId(WindowHandle, nil);
  AttachThreadInput(GetCurrentThreadId, FAppThreadID, True);

  /// Changing parent of the running app to our provided container control
  Windows.SetParent(WindowHandle,Container.Handle);
  SendMessage(Container.Handle, WM_UPDATEUISTATE, UIS_INITIALIZE, 0);
  UpdateWindow(WindowHandle);

  /// This prevents the parent control to redraw on the area of its child windows (the running app)
  SetWindowLong(Container.Handle, GWL_STYLE, GetWindowLong(Container.Handle,GWL_STYLE) or WS_CLIPCHILDREN);
  /// Make the running app to fill all the client area of the container
  SetWindowPos(WindowHandle,0,0,0,Container.ClientWidth,Container.ClientHeight,SWP_NOZORDER);

  SetForegroundWindow(WindowHandle);
end;

Вы можете назвать это так:

  ShowAppEmbedded(FindWindow(nil, 'Calculator'), Panel1);
2 голосов
/ 03 октября 2011

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

Я пытался сделать именно это с моим собственным программным обеспечением (окно из 32-разрядного приложения, встроенного в 64-разрядную оболочку), и оно никогда не работало на 100%, даже используя приемы из других ответов, которые вы получили здесь .

  1. Очень трудно заставить его работать надежно, есть множество мелких тонких проблем, которые вы никогда не исправите. Если вы возитесь с окнами других приложений, которые не знают о ваших манипуляциях, обычно вы напрашиваетесь на неприятности.

  2. Вы меняете способ, которым пользователи ожидают, что Windows будет вести себя. Это будет сбивать с толку и неожиданно для них.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...