gpt4 book ai didi

c# - 网页浏览器站点 : how to call a private COM interface method in a derived class?

转载 作者:太空狗 更新时间:2023-10-29 17:43:24 26 4
gpt4 key购买 nike

这是挑战。我来自框架的 WebBrowserSite 类(class)。我的派生类的一个实例,ImprovedWebBrowserSite , 通过 WebBrowser.CreateWebBrowserSiteBase 返回,我在 WebBrowser 的派生版本中覆盖了它类 - 专门提供自定义站点对象。框架的 WebBrowser实现进一步将其向下传递到底层的非托管 WebBrowser ActiveX 控件。

到目前为止,我已经成功地覆盖了 IDocHostUIHandler在我的 ImprovedWebBrowserSite实现(如 this )。我现在正在寻找更多核心 COM 接口(interface),例如 IOleClientSite ,我想传递给 WebBrowserSite .所有这些都通过 ComImport 暴露给 COM , 但声明为 privateinternal通过框架的实现 WebBrowserSite/UnsafeNativeMethods .因此,我不能 explicitly re-implement它们在派生类中。我必须定义自己的版本,就像我对 IDocHostUIHandler 所做的那样.

所以,问题是,我如何调用 WebBrowserSite 中定义的私有(private)或内部 COM 接口(interface)的方法? , 来 self 的派生类? 例如,我想调用 IOleClientSite.GetContainer .我可以使用反射(如 this ),但那将是最后的手段,仅次于重新实现 WebBrowser从零开始。

我的想法是,因为框架的私有(private) UnsafeNativeMethods.IOleClientSite和我自己的 ImprovedWebBrowserSite.IOleClientSite都是 COM 接口(interface),用 ComImport 声明属性、相同的 GUID 和相同的方法签名。有 COM Type Equivalence在 .NET 4.0+ 中,因此必须有一种无需反射的方法。

[更新] 现在我有一个 solution ,我相信它在定制 WinForms version 方面开辟了一些新的有趣的可能性。的 WebBrowser控制。

此版本的问题是在 my initial attempt 之后创建的以更抽象的形式表述问题被评论员称为误导。该评论后来已被删除,但我决定保留两个版本。

为什么我不想使用反射来解决这个问题?有几个原因:

  • 依赖于内部或私有(private)方法的实际符号名称,由 WebBrowserSite 的实现者提供,与 COM 接口(interface)不同,COM 接口(interface)是关于二进制 v 表协定的。

  • 庞大的反射代码。例如,考虑调用基地的私有(private) TranslateAccelerator 通过Type.InvokeMember ,我有大约 20 种方法可以调用。

  • 效率虽然不太重要:通过反射进行后期绑定(bind)调用的效率总是低于通过 v 表直接调用 COM 接口(interface)方法的效率。

最佳答案

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

下面是可以自定义 WebBrowserSite OLE 接口(interface)的代码,以 IOleClientSite 为例,调用 WebBrowserSite 的私有(private) COM 可见实现.它可以扩展到其他接口(interface),例如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 = "<b>Hello from ImprovedWebBrowser!</b>";
}
}

// 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# - 网页浏览器站点 : how to call a private COM interface method in a derived class?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19717787/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com