非常感谢@γηράσκω δ' αεί πολλά διδασκόμε我最终实现的建议是使用SharpDx.
下面的代码包含一些对外部库的调用,但是我认为这个想法会非常清晰。
As @γηράσκω δ' αεί πολλά διδασκόμε说,要使用WindowRenderTarget
看来我需要以我自己的形式使用它,并且我的形式必须满足这些条件:
- 背景颜色为黑色。
- 成为无边界表格。
- 成为最顶层的窗口(显而易见)。
- 窗口框架必须扩展到客户区,通过调用DwmExtendFrameIntoClientArea https://msdn.microsoft.com/en-us/library/windows/desktop/aa969512%28v=vs.85%29.aspx功能。
然后我可以调用该方法WindowRenderTarget.Clear(Color.Transparent)
使表格透明。请注意,Clear()
在上述条件下,该方法不适用于我们自己的窗体之外的任何其他窗口,这意味着如果我们尝试直接在目标窗口上绘制透明表面而不是使用我们的窗体来执行此操作,我们将生成纯色表面不能透明(我真的不明白为什么不能。)
因此,在完成提到的所有基本步骤之后,现在只需进行一些润色工作,例如将源窗口重叠在目标窗口顶部(以产生 HUD 效果),处理目标窗口大小调整,以及你想要什么。下面的代码只是示范性的,我目前还不能很好地处理这些事情。
这是代码:
Imports D2D1 = SharpDX.Direct2D1
Imports D3D = SharpDX.Direct3D
Imports DXGI = SharpDX.DXGI
Imports DxColor = SharpDX.Color
Imports DxPoint = SharpDX.Point
Imports DxRectangle = SharpDX.Rectangle
Imports DxSize = SharpDX.Size2
Imports Device = SharpDX.Direct3D11.Device
Imports MapFlags = SharpDX.Direct3D11.MapFlags
Imports Elektro.Imaging.Tools
Imports Elektro.Interop.Win32
Imports Elektro.Interop.Win32.Enums
Imports Elektro.Interop.Win32.Types
Public NotInheritable Class Form1 : Inherits Form
<DllImport("dwmapi.dll")>
Private Shared Function DwmExtendFrameIntoClientArea(ByVal hwnd As IntPtr, ByRef margins As Margins) As Integer
End Function
Private factory As New D2D1.Factory(D2D1.FactoryType.SingleThreaded)
Private render As D2D1.WindowRenderTarget
Private renderProps As D2D1.HwndRenderTargetProperties
Private renderThread As Thread = Nothing
Private srcHwnd As IntPtr
Private dstHwnd As IntPtr
Private Sub Form1_Load() Handles MyBase.Shown
' Window handles of source and target window.
Me.srcHwnd = Me.Handle
Me.dstHwnd = Process.GetProcessesByName("notepad").Single().MainWindowHandle
' Form settings.
Me.BackColor = Color.Black
Me.FormBorderStyle = FormBorderStyle.None
Me.TopMost = True
' DWM stuff for later to be able make transparent the source window.
Dim rc As NativeRectangle ' a win32 RECT
NativeMethods.GetClientRect(srcHwnd, rc)
Dim margins As Margins
margins.TopHeight = rc.Width
margins.BottomHeight = rc.Height
DwmExtendFrameIntoClientArea(srcHwnd, margins)
' ------------------------------------------------
Me.renderProps = New D2D1.HwndRenderTargetProperties()
Me.renderProps.Hwnd = srcHwnd
Me.renderProps.PixelSize = New DxSize(rc.Width, rc.Height)
Me.renderProps.PresentOptions = D2D1.PresentOptions.None
Me.render = New D2D1.WindowRenderTarget(Me.factory, New D2D1.RenderTargetProperties(New D2D1.PixelFormat(DXGI.Format.B8G8R8A8_UNorm, D2D1.AlphaMode.Premultiplied)), Me.renderProps)
Me.renderThread = New Thread(New ParameterizedThreadStart(AddressOf Me.DoRender))
Me.renderThread.Priority = ThreadPriority.Normal
Me.renderThread.IsBackground = True
Me.renderThread.Start()
End Sub
Private Sub DoRender(ByVal sender As Object)
While True
Me.OverlapToWindow(Me.srcHwnd, Me.dstHwnd)
Me.render.BeginDraw()
Me.render.Clear(DxColor.Transparent)
Me.render.Flush()
Me.render.EndDraw()
End While
End Sub
Private Sub OverlapToWindow(ByVal srcHwnd As IntPtr, ByVal dstHwnd As IntPtr)
' Gets the (non-client) Rectangle of the windows, taking into account a borderless window of Windows 10.
Dim srcRect As Rectangle = ImageUtil.GetRealWindowRect(srcHwnd)
Dim dstRect As Rectangle = ImageUtil.GetRealWindowRect(dstHwnd)
NativeMethods.SetWindowPos(srcHwnd, dstHwnd,
dstRect.X, dstRect.Y, dstRect.Top, dstRect.Left,
SetWindowPosFlags.IgnoreZOrder Or SetWindowPosFlags.IgnoreResize)
End Sub
End Class