在 C# 或 VB.NET 中,在 Windows 表單下,我想知道如何將外部命令列界面 (CLI) 視窗嵌入到可以呈現外部 CLI 內容的面板或其他型別的主機視窗中我的表單內的視窗。
請注意,我不會假裝自己重定向和列印StdOut流。我只是想將視窗嵌入到我的表單中并讓它成為現實。
我已經按照建議嘗試了SetParent函式,但它似乎不適用于非圖形用戶界面視窗,因為在設定父視窗時,CLI 視窗會從螢屏上消失,并且不會在父級(面板)中呈現窗戶。
似乎可以按照此處的建議在 WPF 中完成此操作,但我不知道如何在 Windows 表單下執行此操作。
我正在尋找一些可以像這樣使用的解決方法:
using (var p = new Process()) {
p.StartInfo.FileName = @".\cli-process.exe";
p.StartInfo.Arguments = @"...";
p.StartInfo.CreateNoWindow = false;
p.StartInfo.UseShellExecute = false;
p.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
p.Start();
Thread.Sleep(2000);
EmbedToWindow(p.MainWindowHandle, this.Panel1.Handle);
p.WaitForExit(TimeOut.Infinite);
}
}
uj5u.com熱心網友回復:
我剛剛在 VB.NET 中撰寫了一個簡單的幫助程式類,它可以幫助我輕松設定和釋放父視窗。
至少就我在所需場景中對其進行的測驗而言,它似乎可以按預期作業。
感謝@Jimi、@RbMm 和@Remy Lebeau 的幫助和我需要知道的提示,以便弄清楚如何做到這一點。
但是,由于缺少型別,我在這里分享的內容不起作用,但您可以理解。抱歉,這需要超過這篇文章的最大字符數限制,如果我是唯一一個有興趣完成這項任務的人,那么復制和粘貼并調整內容以在此處顯示它們可能會花費太多精力......
但是如果你想知道如何使這個類正常作業,那么只需添加我在缺少的NativeMethods類定義中使用的缺少的 P/Invoke 成員,并替換缺少的WindowInfo型別以呼叫GetWindowInfo(和WINDOWINFO結構)或GetClientRect GetWindowLongPtr函式,并替換從SafeHandleZeroOrMinusOneIsInvalid派生的自定義類的缺失SafeWindowHandle型別。IntPtr
使用示例:
Dim process As Process = Process.GetProcessesByName("name").Single()
Dim windowParenting As New WindowParenting(process.MainWindowHandle)
windowParenting.SetParent(Me.Panel1,
fitToParentBounds:=True,
removeBorder:=True,
removeCaption:=True,
resizable:=False)
Thread.Sleep(5000)
windowParenting.ReleaseParent(throwOnInvalidSourceWindowHandle:=True)
' Or...
' windowParenting.Dispose() ' It calls ReleaseParent.
WindowParenting 類:
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Implements a mechanism to set and release the parent window for a specific source window.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
Public Class WindowParenting : Implements IDisposable
#Region " Properties"
''' <summary>
''' A safe handle to the source window.
''' </summary>
Public ReadOnly Property WindowHandle As SafeWindowHandle
''' <summary>
''' Gets a <see cref="DevCase.Core.IPC.WindowInfo"/> object for the source window.
''' </summary>
Public ReadOnly Property WindowInfo As WindowInfo
Get
Return Me.GetWindowInfo()
End Get
End Property
''' <summary>
''' Gets a value that determine whether the source window has a parent window.
''' </summary>
Public ReadOnly Property HasParent As Boolean
Get
Try
Return Me.WindowInfo.ParentWindow IsNot Nothing
Catch ex As Exception
Return False
End Try
End Get
End Property
#End Region
#Region " Private Fields"
''' <summary>
''' Keeps track of the current source window bounds when making a call to <see cref="WindowParenting.SetParent"/> method.
''' </summary>
Private lastBounds As Rectangle = Rectangle.Empty
''' <summary>
''' Keeps track of the current source <see cref="WindowStyles"/> when making a call to <see cref="WindowParenting.SetParent"/> method.
''' </summary>
Private lastWindowStyle As WindowStyles = WindowStyles.None
#End Region
#Region " Constructors "
''' <summary>
''' Initializes a new instance of the <see cref="WindowParenting"/> class.
''' </summary>
''' <param name="hwnd">
''' A handle to the source window.
''' </param>
<DebuggerStepThrough>
Public Sub New(hwnd As IntPtr)
Me.New(New SafeWindowHandle(hwnd))
End Sub
''' <summary>
''' Initializes a new instance of the <see cref="WindowParenting"/> class.
''' </summary>
''' <param name="hwnd">
''' A handle to the source window.
''' </param>
<DebuggerStepThrough>
Public Sub New(hwnd As SafeHandle)
Me.WindowHandle = hwnd
If Me.WindowHandle.IsInvalid Then
Throw New Exception("Invalid window handle.")
End If
End Sub
''' <summary>
''' Initializes a new instance of the <see cref="WindowParenting"/> class.
''' </summary>
''' <param name="window">
''' AThe source window.
''' </param>
<DebuggerStepThrough>
Public Sub New(window As NativeWindow)
Me.New(New SafeWindowHandle(window.Handle))
End Sub
''' <summary>
''' Initializes a new instance of the <see cref="WindowParenting"/> class.
''' </summary>
''' <param name="window">
''' The source window.
''' </param>
<DebuggerStepThrough>
Public Sub New(window As IWin32Window)
Me.New(New SafeWindowHandle(window.Handle))
End Sub
#End Region
#Region " Public Methods "
''' <summary>
''' Sets a new parent window for the source window.
''' </summary>
''' <param name="parentWindow">
''' The parent window.
''' </param>
'''
''' <param name="fitToParentBounds">
''' If set to <see langword="True"/>, fits to size of the source window to the parent window bounds.
''' </param>
'''
''' <param name="removeBorder">
''' If set to <see langword="True"/>, removes the border from the source window.
''' </param>
'''
''' <param name="removeCaption">
''' If set to <see langword="True"/>, removes the caption from the source window.
''' </param>
'''
''' <param name="resizable">
''' If set to <see langword="False"/>, remove sthe size frame from the source window.
''' </param>
''' <exception cref="InvalidOperationException">
''' Source window already has a parent window.
''' </exception>
<DebuggerStepThrough>
Public Overridable Sub SetParent(parentWindow As IWin32Window, fitToParentBounds As Boolean,
removeBorder As Boolean, removeCaption As Boolean,
resizable As Boolean)
Dim curentWindowInfo As WindowInfo = Me.GetWindowInfo()
If Me.lastBounds = Rectangle.Empty Then
Me.lastBounds = curentWindowInfo.Bounds
End If
If Me.lastWindowStyle = WindowStyles.None Then
Me.lastWindowStyle = curentWindowInfo.WindowStyle
End If
Dim newStyle As WindowStyles = (Me.lastWindowStyle And Not WindowStyles.SysMenu)
If removeBorder Then
newStyle = (newStyle And Not WindowStyles.Border)
End If
If removeCaption Then
newStyle = (newStyle And Not WindowStyles.Caption)
End If
If Not resizable Then
newStyle = (newStyle And Not WindowStyles.SizeFrame)
End If
Dim parentWindowHandle As New SafeWindowHandle(parentWindow.Handle)
NativeMethods.SetParent(Me.WindowHandle, parentWindowHandle)
Me.SetSourceWindowStyle(newStyle)
Dim parentClientRect As Rectangle
If fitToParentBounds Then
NativeMethods.GetClientRect(parentWindowHandle, parentClientRect)
End If
NativeMethods.SetWindowPos(Me.WindowHandle, IntPtr.Zero, 0, 0,
If(fitToParentBounds, parentClientRect.Width, 0),
If(fitToParentBounds, parentClientRect.Height, 0),
SetWindowPosFlags.AsyncWindowPos Or
SetWindowPosFlags.ShowWindow Or
If(fitToParentBounds, SetWindowPosFlags.None, SetWindowPosFlags.IgnoreResize))
End Sub
Public Overridable Sub SetParent(parentWindow As NativeWindow, fitToParentBounds As Boolean,
removeBorder As Boolean, removeCaption As Boolean,
resizable As Boolean)
Me.SetParent(DirectCast(parentWindow, IWin32Window), fitToParentBounds, removeBorder, removeCaption, resizable)
End Sub
Public Overridable Sub SetParent(parentWindow As Control, fitToParentBounds As Boolean,
removeBorder As Boolean, removeCaption As Boolean,
resizable As Boolean)
Me.SetParent(DirectCast(parentWindow, IWin32Window), fitToParentBounds, removeBorder, removeCaption, resizable)
End Sub
''' <summary>
''' Release the source window from its current parent window.
''' </summary>
''' <param name="throwOnInvalidSourceWindowHandle">
''' If set to <see langword="True"/>, throws an <see cref="NullReferenceException"/>
''' if the source window handle specified in <see cref="WindowParenting.WindowHandle"/> is invalid.
''' <para></para>
''' This can be useful if you need to detect whether the source window has been destroyed.
''' </param>
<DebuggerStepThrough>
Public Overridable Sub ReleaseParent(Optional throwOnInvalidSourceWindowHandle As Boolean = False)
Dim isInvalid As Boolean = Me.WindowHandle.IsInvalid OrElse
Me.WindowHandle.IsClosed OrElse
Not NativeMethods.IsWindow(Me.WindowHandle)
If isInvalid AndAlso throwOnInvalidSourceWindowHandle Then
Throw New NullReferenceException("Invalid source window handle.")
ElseIf Not isInvalid Then
If Not Me.HasParent Then
Throw New InvalidOperationException("Source window has not a parent window.")
End If
NativeMethods.SetParent(Me.WindowHandle, IntPtr.Zero)
If Me.lastWindowStyle <> WindowStyles.None Then
Me.SetSourceWindowStyle(Me.lastWindowStyle)
Me.lastWindowStyle = WindowStyles.None
End If
If Me.lastBounds <> Rectangle.Empty Then
NativeMethods.SetWindowPos(Me.WindowHandle, IntPtr.Zero,
Me.lastBounds.X, Me.lastBounds.Y,
Me.lastBounds.Width, Me.lastBounds.Height,
SetWindowPosFlags.AsyncWindowPos)
Me.lastBounds = Rectangle.Empty
End If
End If
End Sub
#End Region
#Region " Private Methods "
''' <summary>
''' Returns a <see cref="DevCase.Core.IPC.WindowInfo"/> object for the source window.
''' </summary>
<DebuggerStepThrough>
Private Function GetWindowInfo() As WindowInfo
Return New WindowInfo(Me.WindowHandle)
End Function
''' <summary>
''' Sets the <see cref="WindowStyles"/> for the source window.
''' </summary>
<DebuggerStepThrough>
Private Sub SetSourceWindowStyle(style As WindowStyles)
If Environment.Is64BitProcess Then
NativeMethods.SetWindowLongPtr(Me.WindowHandle, WindowLongValues.WindowStyle, style)
Else
NativeMethods.SetWindowLong(Me.WindowHandle, WindowLongValues.WindowStyle, style)
End If
End Sub
#End Region
#Region " IDisposable Implementation "
''' <summary>
''' Flag to detect redundant calls.
''' </summary>
Private disposedValue As Boolean
''' <summary>
''' Releases all the resources used by this instance.
''' </summary>
''' <param name="disposing">
''' <see langword="True"/> to release both managed and unmanaged resources;
''' <see langword="False"/> to release only unmanaged resources.
''' </param>
Protected Overridable Sub Dispose(disposing As Boolean)
If Not Me.disposedValue AndAlso disposing Then
Try
Me.ReleaseParent()
Catch ex As Exception
End Try
Me.WindowHandle?.Close()
End If
Me.disposedValue = True
End Sub
''' <summary>
''' Releases all the resources used by this instance.
''' </summary>
Public Sub Dispose() Implements IDisposable.Dispose
Me.Dispose(True)
End Sub
#End Region
End Class
它缺少一點對 P/invokes 的 win32 錯誤處理。也許其他事情可以改進。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/473615.html
上一篇:從不同的表單更新XamDataGrid的源的最佳方法是什么?
下一篇:在VisualStudio更新(?)之后,FTD2XX函式在VB.NET中不起作用的原因是什么,是否有可能修復?
