Csharp/C#教程:WebBrowserSite:如何在派生类中调用私有COM接口方法?分享


WebBrowserSite:如何在派生类中调用私有COM接口方法?

这是挑战。 我是从Framework的WebBrowserSite类派生出来的。 我的派生类ImprovedWebBrowserSite一个实例是通过WebBrowser.CreateWebBrowserSiteBase返回的,我在WebBrowser类的派生版本中覆盖了它 – 专门用于提供自定义站点对象。 Framework的WebBrowser实现进一步将其传递给底层的非托管WebBrowser ActiveX控件。

到目前为止,我已经设法在我的ImprovedWebBrowserSite实现中覆盖IDocHostUIHandler (像这样 )。 我现在正在寻找更多的核心COM接口,比如IOleClientSite ,我想将它传递给WebBrowserSite 。 所有这些都通过ComImport暴露给COM,但是通过Framework的WebBrowserSite / UnsafeNativeMethods实现声明为privateinternal 。 因此,我无法在派生类中明确地重新实现它们。 我必须定义自己的版本,就像我使用IDocHostUIHandler

所以,问题是,如何从我的派生类中调用WebBrowserSite定义的私有或内部COM接口的方法? 例如,我想调用IOleClientSite.GetContainer 。 我可以使用reflection(像这样 ),但这将是最后的手段,其次是从头开始重新实现WebBrowser

我的想法是,因为Framework的私有UnsafeNativeMethods.IOleClientSite和我自己的ImprovedWebBrowserSite.IOleClientSite都是COM接口,使用ComImport属性声明,相同的GUID和相同的方法签名。 .NET 4.0+中有COM类型等价 ,因此必须有一种方法可以在没有reflection的情况下完成。

[更新]现在我已经有了解决方案 ,我相信它为自定义WebBrowser控件的WinForms版本打开了一些新的和有趣的可能性。

这个版本的问题是在我最初尝试以更抽象的forms提出问题之后创建的,被评论员称为误导。 评论已被删除,但我决定保留这两个版本。

为什么我不想用reflection来解决这个问题? 原因如下:

最后,我相信我已经使用Marshal.CreateAggregatedObject解决了这个问题,在@EricBrown的帮助下。

下面是使用IOleClientSite作为示例自定义WebBrowserSite OLE接口的代码,调用WebBrowserSite的私有COM可见实现。 它可以扩展到其他接口,例如IDocHostUIHandler

 using System; using System.Diagnostics; using System.Linq; using System.Runtime.InteropServices; using System.Windows.Forms; namespace CustomWebBrowser { public partial class MainForm : Form { public MainForm() { InitializeComponent(); } private void MainForm_Load(object sender, EventArgs e) { var wb = new ImprovedWebBrowser(); wb.Dock = DockStyle.Fill; this.Controls.Add(wb); wb.Visible = true; wb.DocumentText = "Hello from ImprovedWebBrowser!"; } } // ImprovedWebBrowser with custom pass-through IOleClientSite public class ImprovedWebBrowser: WebBrowser { // provide custom WebBrowserSite, // where we override IOleClientSite and call the base implementation protected override WebBrowserSiteBase CreateWebBrowserSiteBase() { return new ImprovedWebBrowserSite(this); } // IOleClientSite [ComImport(), Guid("00000118-0000-0000-C000-000000000046")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IOleClientSite { void SaveObject(); [return: MarshalAs(UnmanagedType.Interface)] object GetMoniker( [In, MarshalAs(UnmanagedType.U4)] int dwAssign, [In, MarshalAs(UnmanagedType.U4)] int dwWhichMoniker); [PreserveSig] int GetContainer([Out] out IntPtr ppContainer); void ShowObject(); void OnShowWindow([In, MarshalAs(UnmanagedType.I4)] int fShow); void RequestNewObjectLayout(); } // ImprovedWebBrowserSite protected class ImprovedWebBrowserSite : WebBrowserSite, IOleClientSite, ICustomQueryInterface, IDisposable { IOleClientSite _baseIOleClientSite; IntPtr _unkOuter; IntPtr _unkInnerAggregated; Inner _inner; #region Inner // Inner as aggregated object class Inner : ICustomQueryInterface, IDisposable { object _outer; Type[] _interfaces; public Inner(object outer) { _outer = outer; // the base's private COM interfaces are here _interfaces = _outer.GetType().BaseType.GetInterfaces(); } public CustomQueryInterfaceResult GetInterface(ref Guid iid, out IntPtr ppv) { if (_outer != null) { var ifaceGuid = iid; var iface = _interfaces.FirstOrDefault((t) => t.GUID == ifaceGuid); if (iface != null) { var unk = Marshal.GetComInterfaceForObject(_outer, iface, CustomQueryInterfaceMode.Ignore); if (unk != IntPtr.Zero) { ppv = unk; return CustomQueryInterfaceResult.Handled; } } } ppv = IntPtr.Zero; return CustomQueryInterfaceResult.Failed; } ~Inner() { // need to work out the reference counting for GC to work correctly Debug.Print("Inner object finalized."); } public void Dispose() { _outer = null; _interfaces = null; } } #endregion // constructor public ImprovedWebBrowserSite(WebBrowser host): base(host) { // get the CCW object for this _unkOuter = Marshal.GetIUnknownForObject(this); Marshal.AddRef(_unkOuter); try { // aggregate the CCW object with the helper Inner object _inner = new Inner(this); _unkInnerAggregated = Marshal.CreateAggregatedObject(_unkOuter, _inner); // turn private WebBrowserSiteBase.IOleClientSite into our own IOleClientSite _baseIOleClientSite = (IOleClientSite)Marshal.GetTypedObjectForIUnknown(_unkInnerAggregated, typeof(IOleClientSite)); } finally { Marshal.Release(_unkOuter); } } ~ImprovedWebBrowserSite() { // need to work out the reference counting for GC to work correctly Debug.Print("ImprovedClass finalized."); } public CustomQueryInterfaceResult GetInterface(ref Guid iid, out IntPtr ppv) { if (iid == typeof(IOleClientSite).GUID) { // CustomQueryInterfaceMode.Ignore is to avoid infinite loop during QI. ppv = Marshal.GetComInterfaceForObject(this, typeof(IOleClientSite), CustomQueryInterfaceMode.Ignore); return CustomQueryInterfaceResult.Handled; } ppv = IntPtr.Zero; return CustomQueryInterfaceResult.NotHandled; } void IDisposable.Dispose() { base.Dispose(); // we may have recicular references to itself _baseIOleClientSite = null; if (_inner != null) { _inner.Dispose(); _inner = null; } if (_unkInnerAggregated != IntPtr.Zero) { Marshal.Release(_unkInnerAggregated); _unkInnerAggregated = IntPtr.Zero; } if (_unkOuter != IntPtr.Zero) { Marshal.Release(_unkOuter); _unkOuter = IntPtr.Zero; } } #region IOleClientSite // IOleClientSite public void SaveObject() { Debug.Print("IOleClientSite.SaveObject"); _baseIOleClientSite.SaveObject(); } public object GetMoniker(int dwAssign, int dwWhichMoniker) { Debug.Print("IOleClientSite.GetMoniker"); return _baseIOleClientSite.GetMoniker(dwAssign, dwWhichMoniker); } public int GetContainer(out IntPtr ppContainer) { Debug.Print("IOleClientSite.GetContainer"); return _baseIOleClientSite.GetContainer(out ppContainer); } public void ShowObject() { Debug.Print("IOleClientSite.ShowObject"); _baseIOleClientSite.ShowObject(); } public void OnShowWindow(int fShow) { Debug.Print("IOleClientSite.OnShowWindow"); _baseIOleClientSite.OnShowWindow(fShow); } public void RequestNewObjectLayout() { Debug.Print("IOleClientSite.RequestNewObjectLayout"); _baseIOleClientSite.RequestNewObjectLayout(); } #endregion } } } 

只是一个想法,但也许你可以使用这里的一些源代码。 你会重新实现,但它可能会给你你想要的东西。

上述就是C#学习教程:WebBrowserSite:如何在派生类中调用私有COM接口方法?分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请点击右边联系管理员删除。

如若转载,请注明出处:https://www.ctvol.com/cdevelopment/996784.html

(0)
上一篇 2021年12月25日
下一篇 2021年12月25日

精彩推荐