问题在于,托管(重新设置父级)窗口在激活时不会导致托管窗体也激活,因此它会被带到前台。
托管窗口并不完全是子窗口,托管窗体不会从它接收任何消息。
将承载窗体的窗体带到前台的可能方法foreign窗口,当此窗口接收焦点时(您单击或以其他方式激活它)
它用设置WinEventHook安装一个 Hook 来监视窗口放置状态的变化(EVENT_SYSTEM_FOREGROUND
).
您指定感兴趣的窗口的句柄,(您的proc.MainWindowHandle
在这里),加上它的ProcessId
and ThreadId
。请注意,这些与您的应用程序的调用不同获取窗口线程进程ID()需要获取此信息。
当您激活foreign窗口中,Hook 调用指定的回调委托(这里,ForegroundChangedEventDelegate
),依次执行它指向的方法(ForegroundStateChangedCallback
)
当调用此方法时,它会检查引起通知的对象是否是OBJID_WINDOW
该事件实际上是EVENT_SYSTEM_FOREGROUND
。如果是这种情况,它会调用设置窗口位置将托管窗体带到前台,但不激活它,因此托管窗口不会失去焦点
Notes:
这意味着您必须指定应用程序的命名空间才能使导入按预期工作。在 VB.NET 中,通常是应用程序的名称及其主目录Namespace
匹配;如果您的应用程序被命名,WinFormsApp1
,那么就是Imports WinFormsApp1.NativeMethods
- 要激活 Hook,一旦更改了该窗口的父级,就可以使用其句柄来调用
SetForegroundStateChangedHook()
方法。就这样。
当窗体关闭时,钩子被释放
我建议使用中的代码将窗口脱钩至其原始状态设置父级(并且可能在关闭托管表单之前将其设置回原始值)。你可以发送WM_CLOSE
如果需要的话到窗口。
Imports [Your App Namespace].NativeMethods
Public Class SomeForm
Private hForegrundChangedEventHook As IntPtr
Private ReadOnly ForegrundChangedEventDelegate As WinEventDelegate
Private Shared GCForegroundStateSafetyHandle As GCHandle
Public Sub New()
InitializeComponent()
ForegrundChangedEventDelegate = New WinEventDelegate(AddressOf ForegroundStateChangedCallback)
GCForegroundStateSafetyHandle = GCHandle.Alloc(ForegrundChangedEventDelegate)
End Sub
Protected Overrides Sub OnHandleDestroyed(e As EventArgs)
GCForegroundStateSafetyHandle.Free()
UnhookWinEvent(hForegrundChangedEventHook)
MyBase.OnHandleDestroyed(e)
End Sub
Private Sub SetForegroundStateChangedHook(hWnd As IntPtr)
Dim processId As UInteger
Dim targetThreadId = GetWindowThread(hWnd, processId)
hForegrundChangedEventHook = WinEventHookOne(SWEH_Events.EVENT_SYSTEM_FOREGROUND, ForegrundChangedEventDelegate, processId, targetThreadId)
End Sub
Friend Sub ForegroundStateChangedCallback(hWinEventHook As IntPtr, eventType As SWEH_Events, hWnd As IntPtr, idObject As SWEH_ObjectId, idChild As Long, dwEventThread As UInteger, dwmsEventTime As UInteger)
If idObject = SWEH_ObjectId.OBJID_WINDOW AndAlso eventType = SWEH_Events.EVENT_SYSTEM_FOREGROUND Then
Dim flags = SWP_Flags.SWP_ASYNCWINDOWPOS Or SWP_Flags.SWP_NOACTIVATE Or SWP_Flags.SWP_NOSIZE Or SWP_Flags.SWP_NOMOVE
SetWindowPos(Handle, IntPtr.Zero, 0, 0, 0, 0, flags)
End If
End Sub
End Class
NativeMethods类
将此类添加到项目中并按照所述导入到您的表单中
Imports System.Runtime.InteropServices
Public Class NativeMethods
<DllImport("user32.dll", SetLastError:=True)>
Friend Shared Function GetWindowThreadProcessId(hWnd As IntPtr, ByRef lpdwProcessId As UInteger) As UInteger
End Function
<DllImport("user32.dll", SetLastError:=True)>
Friend Shared Function SetWindowPos(hWnd As IntPtr, hWndInsertAfter As IntPtr, x As Integer, y As Integer, cx As Integer, cy As Integer, uFlags As SWP_Flags) As Boolean
End Function
Friend Delegate Sub WinEventDelegate(
hWinEventHook As IntPtr,
eventType As SWEH_Events,
hwnd As IntPtr, idObject As SWEH_ObjectId,
idChild As Long,
dwEventThread As UInteger,
dwmsEventTime As UInteger)
<DllImport("user32.dll", SetLastError:=False)>
Friend Shared Function SetWinEventHook(
eventMin As SWEH_Events,
eventMax As SWEH_Events,
hmodWinEventProc As IntPtr,
lpfnWinEventProc As WinEventDelegate,
idProcess As UInteger,
idThread As UInteger,
dwFlags As SWEH_dwFlags) As IntPtr
End Function
<DllImport("user32.dll", SetLastError:=False)>
Friend Shared Function UnhookWinEvent(hWinEventHook As IntPtr) As Boolean
End Function
Friend Shared WinEventHookInternalFlags As SWEH_dwFlags =
SWEH_dwFlags.WINEVENT_OUTOFCONTEXT Or SWEH_dwFlags.WINEVENT_SKIPOWNPROCESS
Friend Shared Function WinEventHookOne(evt As SWEH_Events, weDelegate As WinEventDelegate, idProcess As UInteger, idThread As UInteger) As IntPtr
Return SetWinEventHook(evt, evt, IntPtr.Zero, weDelegate, idProcess, idThread, WinEventHookInternalFlags)
End Function
Friend Shared Function GetWindowThread(hWnd As IntPtr, ByRef processID As UInteger) As UInteger
processID = 0
Return GetWindowThreadProcessId(hWnd, processID)
End Function
' SetWinEventHook Events
Friend Enum SWEH_Events As UInteger
EVENT_MIN = &H1
EVENT_MAX = &H7FFFFFFF
EVENT_SYSTEM_SOUND = &H1
EVENT_SYSTEM_ALERT = &H2
EVENT_SYSTEM_FOREGROUND = &H3
EVENT_SYSTEM_MENUSTART = &H4
EVENT_SYSTEM_MENUEND = &H5
EVENT_SYSTEM_MENUPOPUPSTART = &H6
EVENT_SYSTEM_MENUPOPUPEND = &H7
EVENT_SYSTEM_CAPTURESTART = &H8
EVENT_SYSTEM_CAPTUREEND = &H9
EVENT_SYSTEM_MOVESIZESTART = &HA
EVENT_SYSTEM_MOVESIZEEND = &HB
EVENT_SYSTEM_CONTEXTHELPSTART = &HC
EVENT_SYSTEM_CONTEXTHELPEND = &HD
EVENT_SYSTEM_DRAGDROPSTART = &HE
EVENT_SYSTEM_DRAGDROPEND = &HF
EVENT_SYSTEM_DIALOGSTART = &H10
EVENT_SYSTEM_DIALOGEND = &H11
EVENT_SYSTEM_SCROLLINGSTART = &H12
EVENT_SYSTEM_SCROLLINGEND = &H13
EVENT_SYSTEM_SWITCHSTART = &H14
EVENT_SYSTEM_SWITCHEND = &H15
EVENT_SYSTEM_MINIMIZESTART = &H16
EVENT_SYSTEM_MINIMIZEEND = &H17
EVENT_SYSTEM_DESKTOPSWITCH = &H20
EVENT_SYSTEM_END = &HFF
EVENT_OEM_DEFINED_START = &H101
EVENT_OEM_DEFINED_END = &H1FF
EVENT_UIA_EVENTID_START = &H4E00
EVENT_UIA_EVENTID_END = &H4EFF
EVENT_UIA_PROPID_START = &H7500
EVENT_UIA_PROPID_END = &H75FF
EVENT_CONSOLE_CARET = &H4001
EVENT_CONSOLE_UPDATE_REGION = &H4002
EVENT_CONSOLE_UPDATE_SIMPLE = &H4003
EVENT_CONSOLE_UPDATE_SCROLL = &H4004
EVENT_CONSOLE_LAYOUT = &H4005
EVENT_CONSOLE_START_APPLICATION = &H4006
EVENT_CONSOLE_END_APPLICATION = &H4007
EVENT_CONSOLE_END = &H40FF
EVENT_OBJECT_CREATE = &H8000
EVENT_OBJECT_DESTROY = &H8001
EVENT_OBJECT_SHOW = &H8002
EVENT_OBJECT_HIDE = &H8003
EVENT_OBJECT_REORDER = &H8004
EVENT_OBJECT_FOCUS = &H8005
EVENT_OBJECT_SELECTION = &H8006
EVENT_OBJECT_SELECTIONADD = &H8007
EVENT_OBJECT_SELECTIONREMOVE = &H8008
EVENT_OBJECT_SELECTIONWITHIN = &H8009
EVENT_OBJECT_STATECHANGE = &H800A
EVENT_OBJECT_LOCATIONCHANGE = &H800B
EVENT_OBJECT_NAMECHANGE = &H800C
EVENT_OBJECT_DESCRIPTIONCHANGE = &H800D
EVENT_OBJECT_VALUECHANGE = &H800E
EVENT_OBJECT_PARENTCHANGE = &H800F
EVENT_OBJECT_HELPCHANGE = &H8010
EVENT_OBJECT_DEFACTIONCHANGE = &H8011
EVENT_OBJECT_ACCELERATORCHANGE = &H8012
EVENT_OBJECT_INVOKED = &H8013
EVENT_OBJECT_TEXTSELECTIONCHANGED = &H8014
EVENT_OBJECT_CONTENTSCROLLED = &H8015
EVENT_SYSTEM_ARRANGMENTPREVIEW = &H8016
EVENT_OBJECT_END = &H80FF
EVENT_AIA_START = &HA000
EVENT_AIA_END = &HAFFF
End Enum
' SetWinEventHook Window Objects
Friend Enum SWEH_ObjectId As Long
OBJID_WINDOW = &H0
OBJID_SYSMENU = &HFFFFFFFFUI
OBJID_TITLEBAR = &HFFFFFFFEUI
OBJID_MENU = &HFFFFFFFDUI
OBJID_CLIENT = &HFFFFFFFCUI
OBJID_VSCROLL = &HFFFFFFFBUI
OBJID_HSCROLL = &HFFFFFFFAUI
OBJID_SIZEGRIP = &HFFFFFFF9UI
OBJID_CARET = &HFFFFFFF8UI
OBJID_CURSOR = &HFFFFFFF7UI
OBJID_ALERT = &HFFFFFFF6UI
OBJID_SOUND = &HFFFFFFF5UI
OBJID_QUERYCLASSNAMEIDX = &HFFFFFFF4UI
OBJID_NATIVEOM = &HFFFFFFF0UI
End Enum
' WinEventDelegate flags
Friend Enum SWEH_dwFlags As UInteger
WINEVENT_OUTOFCONTEXT = &H0 ' Events are ASYNC - No dll needed
WINEVENT_SKIPOWNTHREAD = &H1 ' Don't call back for events on installer's thread
WINEVENT_SKIPOWNPROCESS = &H2 ' Don't call back for events on installer's process
WINEVENT_INCONTEXT = &H4 ' Events are SYNC, this causes your dll to be injected into every process
End Enum
' SetWindowPos flags
<Flags>
Public Enum SWP_Flags As UInteger
SWP_NOSIZE = &H1
SWP_NOMOVE = &H2
SWP_NOZORDER = &H4
SWP_NOREDRAW = &H8
SWP_NOACTIVATE = &H10
SWP_DRAWFRAME = &H20
SWP_FRAMECHANGED = &H20
SWP_SHOWWINDOW = &H40
SWP_HIDEWINDOW = &H80
SWP_NOCOPYBITS = &H100
SWP_NOOWNERZORDER = &H200
SWP_NOREPOSITION = &H200
SWP_NOSENDCHANGING = &H400
SWP_NOCLIENTSIZE = &H800
SWP_NOCLIENTMOVE = &H1000
SWP_DEFERERASE = &H2000
SWP_ASYNCWINDOWPOS = &H4000
End Enum
End Class