我正在尝试使用以下代码聚合COM对象(外部未知)中的.NET对象:
Object obj = ... // some ComVisible .NET object
var comObj = (IMyComInterface)Activator.CreateInstance(Type.GetTypeFromProgID("some.progid"));
var unknown = Marshal.GetIUnknownForObject(comObj);
var innerUnknown = Marshal.CreateAggregatedObject(unknown, obj);
// This is where the ExecutionEngineException is thrown.
var aggObj = Marshal.GetObjectForIUnknown(innerUnknown);
// Make outer object aware of our dotnet object, say.
comObj.DotNetObj = aggObj;
Marshal.Release(unknown);
...
此代码有“明显”错误吗?这个例外让我很少继续下去。同样令人讨厌的是,异常并不总是发生,尽管它经常发生。 还有另一种方法来实现这一目标吗? (即将innerUnknown IntPtr封送到我的COM对象)
注意:我必须定位框架的第2版并且没有尝试过版本4,据我所知,我完全是最新的。
答案 0 :(得分:3)
回答这个问题,它失败的原因是innerUnknown是错误的未知。该方法旨在获取COM IUnknown的活动RCW,但此IUnknown是Managed对象的Com-callable包装器。
在任何情况下,外部对象都需要innerUnknown
指针。如果你给它一个你想要的那个,你会在QueryInterface中得到一个堆栈溢出。
在上面的示例中,.Net对象认为它已由COM对象聚合,但COM对象无法识别。假设它是你的COM对象,你需要给它innerUnknown,然后实现委托IUnknown(如果你还没有)。您无需调用GetObjectForIUnknown。
然而,你却有点倒退。通常的方法是COM对象调用CoCreateInstance将自身作为外部未知来传递。然后运行时为您调用CreateAggregatedObject。
如果希望.Net对象聚合COM对象,则应该从RCW继承。这将创建COM对象作为聚合对象,将.Net内部未知传递给CoCreateInstance。但它必须是支持聚合的对象。
如果希望COM对象聚合.Net对象,则必须使用COM对象来执行此操作。典型的例子是ADO聚合OLEDB提供商,ADSI聚合ADSI扩展,WMI(我认为)。但它必须得到对象的支持,你无法告诉任何旧对象聚合你。通常它由另一个调用CoCreateInstance的对象发生,该对象由.Net运行时处理,它将为您调用CreateAggregatedObject,并将innerUnknown传递回调用者。