我有一个第三方程序集,其中包含一个实现某个COM接口的公共抽象类。
的影响[ComVisible(true)]
public abstract class SomeClass: ISomeInterface
{
....
public void Method1() {...}
}
实际对象是扩展SomeClass的内部对象,由第三方代码
实例化如果我拥有的是ISomeInterface的CCW,是否有办法访问此类的公共方法?
澄清我的问题:
我正在构建一个扩展F#项目系统的风味Visual Studio项目。我的代码和F#项目系统都是托管的,但我们之间有很多非托管代码。在我的项目经理中,我得到一个指针(IntPtr)给F#项目经理,我可以将它转换为F#项目经理实现的许多接口,但我需要在项目经理本身上调用(公共)方法,到目前为止我找不到办法做到这一点
答案 0 :(得分:0)
一般来说,没有。您只能获取此COM接口中的方法以及同一对象上的其他COM接口。
答案 1 :(得分:0)
这取决于您尝试调用的未发布方法是否具有您无法看到的内部COM(或C ++)实现。 COM接口要求实现对象提供固定位置vtables
,通常可以从托管代码访问和解释它,即使它们不是公开使用的。
对于本机COM库,COM vtable方案通常对应于内部运行时内部设置方式的二进制映像。由于这些表是不可移动的并且与众所周知的COM要求相关联,因此不安全的托管代码可以浏览并找出如何获取任何内容。为了说明,您可以在代码中定义一个接口IFoo
,它与COM库的一个秘密接口相似 - 可能包含如下所示的单个方法:
[ComImport, SuppressUnmanagedCodeSecurity, Guid("00000000-0000-0000-0000-123456789ABC")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IFoo
{
int FooFunc(uint x);
}
请注意,如果要为COM启用IUnknown
和其他CLR支持,则此处应使用[ComImport]
,即使这是您自己的“导入”的唯一接口声明任何地方。现在假设此接口匹配某些外部COM对象的运行时vtable,或者甚至是非COM本机C ++对象(给定适当的调整),您可以执行以下操作:
var vtbl = *(IntPtr**)pObj; // ptr to a C++ style object, perhaps from ICustomMarshaller
// ...or...
var vtbl = *(IntPtr**)((IntPtr*)pUnk - 1); // or an IUnknown ptr instead
// since IUnknown methods are 0, 1, 2, vtable slot for FooFunc is likely '3'
// but to fetch it in a more "official way"...
var mi = typeof(IFoo).GetMethod(nameof(IFoo.FooFunc));
int slot_ix = Marshal.GetComSlotForMethodInfo(mi);
// fetch unmanaged function pointer to 'FooFunc'
IntPtr pfn = vtbl[slot_ix];
此时,您需要声明一个托管委托,以便通过此函数指针进行调用。由于FooFunc
是instance call,因此委托需要与相关的this
实例绑定,在这种情况下为pObj
,以便将该值插入每当调用FooFunc
时,'invisible'第一个参数,就像函数所期望的那样。请注意,您无法利用将相关实例存储在my_delegate.Target
属性中的常规CLR机制,因为这仅适用于托管对象,此处所讨论的目标不是。因此,额外的论证变得比“不可见”小:
// important... note this crucial attribute and its argument ---v
[ComVisible(true), UnmanagedFunctionPointer(CallingConvention.ThisCall)]
public delegate int __this_FooFunc([In] IntPtr _this, [In] uint x);
// create managed delegate for unmanaged function pointer from above
var __FooFunc = Marshal.GetDelegateForFunctionPointer<__this_FooFunc>(pfn);
// call it... v--- but don't forget the 'this'
int i = __FooFunc(pObj, 1234U); // call vtable-based function from managed code
无论如何,这一切都有效,甚至不是粗略或有争议的;我们基本上只是在COM规范中建立良好的步行结构,就像CLR的默认封送代码一样。
现在说了所有这些,如果您感兴趣的COM功能来自托管环境,例如您指定的F#,则上述内容很少或根本不适用。托管运行时环境有机会在更复杂的基础上提供COM vtable,例如:
虽然我不确定这些要点中哪些适用于您所描述的情况,但似乎其中的部分或全部可能会因CLR主机的实施细节而异。不幸的是,主机部署这些优化中的任何一个都足以掩盖上述vtable snooping的类型。