将窗口嵌入到另一个进程中

发布于 2024-12-07 07:06:51 字数 887 浏览 1 评论 0原文

我在 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;

它确实在我的表单上显示了窗口,但玻璃边框丢失了,有时(特别是当我移动表单时),很难恢复将焦点转移到嵌入窗口(我需要单击几次)。

可能是什么原因造成的?另外,您是否发现使用此方法可能会遇到任何潜在问题?

感谢您抽出时间。

I have read some posts here on StackOverflow, but none has worked for me. Here is the code I am using to display the window of the standard Calculator on my form:

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;

It does display the window on my form, but the glass border is lost and sometimes (especially when I move my form), it is hard to restore the focus to the embedded window (I need to click several times).

What may be causing this? Also, do you see any potential issues I may get into with using this method?

Thank you for your time.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

尽揽少女心 2024-12-14 07:06:52

为了你的理智,以及你的程序用户的理智,我认为你最好放弃这个想法:

我尝试用我自己的软件来做这件事(一个从 32 位应用程序嵌入到 64 位包装器中的窗口) ),而且它从来没有 100% 有效,即使使用你在这里得到的其他答案中的技巧也是如此。

  1. 让它可靠地工作是非常困难的,有无数的小微妙问题你永远无法解决。如果你弄乱了其他应用程序的窗口,而这些应用程序不知道你的操作,通常你是在自找麻烦。

  2. 您正在改变用户期望 Windows 的行为方式。这会让他们感到困惑和意外。

For the sake of your sanity, and the sanity of your program's users, I think you'd better abandon this idea:

I tried to do exactly this thing with my own software (a window from 32-bit app embedded into 64-bit wrapper), and it never worked 100%, even using the tricks from the other answers you've got here.

  1. It is very hard to make it work reliably, there are zillion little subtle issues that you'll never get right. If you're messing with windows of other applications, which are not aware of your manipulation, generally you're asking for trouble.

  2. You're changing the way users expect Windows to behave. This will be confusing and unexpected for them.

山有枢 2024-12-14 07:06:51

试试这个代码。我从我的一份旧源代码中获取了它。您将失去玻璃框架,但主菜单是可见的,并且我没有注意到将焦点设置回嵌入式应用程序有任何问题。您应该能够使用 SetForegroundWindow() API 函数来执行此操作。每当您移动容器表单时,您的嵌入式应用程序都会失去焦点,因此您需要再次调用 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);

Try this code. I took it from one of my older source codes. You will lose glass frame, but main menu is visible, and I didn't notice any problem in setting focus back to the embedded app. You should be able to do so using SetForegroundWindow() API function. Whenever you move your container form, your embedded app loses focus, so you need to call SetForegroundWindow again to restore focus :

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;

You can call it this way:

  ShowAppEmbedded(FindWindow(nil, 'Calculator'), Panel1);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文