我使用下面的代码启动一个应用程序,并将其移动到窗体的面板中。在本例中,我使用记事本,这只是一个示例。稍后我将使用不同的应用程序。
当另一个应用程序移到窗体前面时,我只能通过单击标题栏将窗体移到前台。如果我单击MDI子区域(即记事本移到的面板),则没有任何React。
是否有办法实现这一点?
Imports System.Runtime.InteropServices
Public Class Form1
Declare Auto Function SetParent Lib "user32.dll" (ByVal hWndChild As IntPtr, ByVal hWndNewParent As IntPtr) As Integer
Declare Auto Function SendMessage Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim proc As Process
proc = Process.Start("notepad.exe")
proc.WaitForInputIdle()
SetParent(proc.MainWindowHandle, Me.Panel1.Handle)
SendMessage(proc.MainWindowHandle, 274, 61488, 0)
End Sub
End Class
2条答案
按热度按时间tkclm6bt1#
问题是,宿主(重定父级)窗口在激活时不会导致宿主窗体也激活,因此它被带到前台。
宿主Window并不完全是子Window,宿主窗体不接收来自它的任何消息。
一种可能的方法,用于在此窗口获得焦点(单击或以其他方式激活它)时,将承载 foreign 窗口的窗体置于前台
它使用SetWinEventHook来安装一个Hook,该Hook监视窗口(
EVENT_SYSTEM_FOREGROUND
)的放置状态的变化。您可以指定兴趣窗口的句柄(此处为您的
proc.MainWindowHandle
)及其ProcessId
和ThreadId
。请注意,它们与您的应用不同,需要调用GetWindowThreadProcessId()才能获取此信息。当您激活 foreign 窗口时,挂钩调用指定的回调委托(此处为
ForegrundChangedEventDelegate
),该委托又执行它所指向的方法(ForegroundStateChangedCallback
)当调用此方法时,它会检查引起通知的对象是否为
OBJID_WINDOW
,以及事件是否实际为EVENT_SYSTEM_FOREGROUND
。如果是,它会调用SetWindowPos,将宿主窗体置于前台,但不激活它,这样宿主窗口就不会失去焦点备注:
SetWinEvetHook
委派会在父Form的建构函式(Sub New()
)中建立,沿着使用GC SafeHandle来防止委派在错误的时间遭到内存回收。它在
OnHandleDestroyed()
覆盖中释放,其中钩子proc也被解除钩子这意味着您必须指定应用程序的
namespace
,以便导入按预期工作。在VB .NET中,通常应用程序的名称与其主NameSpace
匹配;如果您的应用命名为WinFormsApp1
,则其Imports WinFormsApp1.NativeMethods
SetForegroundStateChangedHook()
方法。当窗体关闭时,挂钩被释放
我建议使用Unhook Window into its original State中的代码来设置Parent(并且,可能的话,在关闭宿主窗体之前将其设置回原始值)。如果需要,您可以将
WM_CLOSE
发送到Window。本机方法类
将此类添加到项目中,并按所述导入到窗体中
5tmbdcev2#
多亏了Jimi的大力帮助,我才能让它正常工作:
将
NativeMethods
类添加到项目中,使用上面Jimi's answer中的代码在表单中使用下列程式码: