将窗口嵌入另一个进程 [英] Embedding window into another process

查看:389
本文介绍了将窗口嵌入另一个进程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经在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而不是WS_POPUP)或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或SWP_FRAMECHANGED);

AttachThreadInput(GetCurrentThreadID(),CalcWindow,True);
结束
结束

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



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



感谢您的时间。

解决方案

尝试这段代码。我从一个旧的源代码中拿出来。您将失去玻璃框架,但主菜单是可见的,我没有注意到将焦点设置回嵌入式应用程序有任何问题。你应该可以使用SetForegroundWindow()API函数。每当您移动容器表单时,您的嵌入式应用程序将失去焦点,因此您需要再次调用SetForegroundWindow来恢复焦点:

 过程ShowAppEmbedded (WindowHandle:THandle; Container:TWinControl); 
var
WindowStyle:Integer;
FAppThreadID:红衣主教;
begin
///设置运行的应用程序窗口样式。
WindowStyle = = GetWindowLong(WindowHandle,GWL_STYLE);
WindowStyle:= WindowStyle
- WS_CAPTION
- WS_BORDER
- WS_OVERLAPPED
- WS_THICKFRAME;
SetWindowLong(WindowHandle,GWL_STYLE,WindowStyle);

///将容器应用程序输入线程附加到运行的应用程序输入线程,以便
///正在运行的应用程序接收用户输入。
FAppThreadID:= GetWindowThreadProcessId(WindowHandle,nil);
AttachThreadInput(GetCurrentThreadId,FAppThreadID,True);

///将正在运行的应用程序的父级更改为我们提供的容器控件
Windows.SetParent(WindowHandle,Container.Handle);
SendMessage(Container.Handle,WM_UPDATEUISTATE,UIS_INITIALIZE,0);
UpdateWindow(WindowHandle);

///这样可以防止父控件在其子窗口的区域重绘(正在运行的应用程序)
SetWindowLong(Container.Handle,GWL_STYLE,GetWindowLong(Container.Handle,GWL_STYLE)或WS_CLIPCHILDREN);
///使运行的应用程序填充容器的所有客户端区域
SetWindowPos(WindowHandle,0,0,0,Container.ClientWidth,Container.ClientHeight,SWP_NOZORDER);

SetForegroundWindow(WindowHandle);
结束

您可以这样调用:

  ShowAppEmbedded(FindWindow(nil,'Calculator'),Panel1); 


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.

解决方案

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

这篇关于将窗口嵌入另一个进程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆