我正在编写需要连接到COM事件的C#代码。我实现了使用 IConnectionPointContainer和IConnectionPoint因此:
IConnectionPointContainer connectionPointContainer = internalGenerator as IConnectionPointContainer;
if (connectionPointContainer == null)
{
Debug.Fail("The script generator doesn't support the required interface - IConnectionPointContainer");
throw new InvalidCastException("The script generator doesn't support the required interface - IConnectionPointContainer");
}
Guid IID_IScriptGeneratorEvents = typeof(IScriptGeneratorCallback).GUID;
connectionPointContainer.FindConnectionPoint(ref IID_IScriptGeneratorEvents, out m_connectionPoint);
m_connectionPoint.Advise(this, out m_cookie);
问题是,当COM服务器实际在.Net(例如,C#)中实现时,在.Net创建它之后,它将它作为.Net对象处理,而不是COM对象。由于.Net对象没有实现IConnectionPointContainer接口,因此在尝试将对象强制转换为该接口时,我得到null。
知道我该如何解决这个问题? 我当然可以在C#COM服务器中自己实现IConnectionPointContainer,但是我想要一个更简单的解决方案,我可以很容易地向需要实现COM服务器的其他开发人员解释。
P.S我必须使用IConnectionPointContainer,因为COM服务器可以在非.Net(C ++,Java)中实现。
谢谢, 因巴尔
答案 0 :(得分:1)
IConnectionPointContainer是在CCW(COM可调用包装器)上实现的,.NET在外部将.NET对象公开为COM对象时自动生成。
尝试在.NET对象上调用Marshal.GetComInterfaceForObject来获取IConnectionPointContainer的COM接口,而不是仅仅转换它。
更新 ...如果不起作用,Marshal.GetIUnknownForObject必须返回一些内容,然后这可能会支持Marshal.QueryInterface来电。
答案 1 :(得分:0)
我没有办法做到这一点。 最终我将在.Net中定义另一个接口,并将编写2个代码路径,一个用于.Net对象,另一个用于真正的COM对象。
答案 2 :(得分:0)
问题是执行GetIUnknownForObject调用会返回一个指针,然后您可以使用其GUID成功调用该指针以获取该对象的IConnectionPointContainer。但是,对QueryInterface的调用只会返回原始的.NET对象,而不是IConnectionPointContainer接口。
我也坚持这一点,如果有人有任何进一步的见解,请分享。我的方案是我使用COM互操作将.NET控件公开为ActiveX。我有一个为事件接收器定义的ComSourceInterface,但在VB6主机中,事件没有按预期连接。因此,我试图为我暴露的.NET控件获取IConnectionPointContainer接口,以便手动挂接事件,但是如果确实实现了,则无法访问此接口 - 或者我可能只是在查看错误的对象? / p>
答案 3 :(得分:0)
我进一步说,因为我在使用COM互操作将.NET控件作为ActiveX公开时手动连接事件时遇到了同样的问题。
如果你使用Reflector(例如Redgate Reflector)挖掘一下UserControl类,你会看到一个'ActiveXImpl'嵌套类成员,它包含另一个名为'AdviseHelper'的嵌套静态类,它有成员ComConnectionPointContainer和ComConnectionPoint。它还具有辅助功能,可根据需要连接点。
有一个问题。当COM interop从您的控件(事件源)连接到连接点容器(其中包含控件事件的事件接收器)时,将调用IQuickActivate.QuickActivate函数,然后调用AdviseHelper类''AdviseConnectionPoint '功能。
在客户端(即不是你的控件,包含它的东西)上的事件接收器的IUnknown接口指针被传递给这个QuickActivate函数(参数'pUnkEventSink'。在反射器中这个函数看起来像这样,我是突出显示实际事件连接的位置:
internal void QuickActivate(UnsafeNativeMethods.tagQACONTAINER pQaContainer, UnsafeNativeMethods.tagQACONTROL pQaControl)
{
int num;
this.LookupAmbient(-701).Value = ColorTranslator.FromOle((int) pQaContainer.colorBack);
this.LookupAmbient(-704).Value = ColorTranslator.FromOle((int) pQaContainer.colorFore);
if (pQaContainer.pFont != null)
{
Control.AmbientProperty ambient = this.LookupAmbient(-703);
IntSecurity.UnmanagedCode.Assert();
try
{
Font font2 = Font.FromHfont(((UnsafeNativeMethods.IFont) pQaContainer.pFont).GetHFont());
ambient.Value = font2;
}
catch (Exception exception)
{
if (ClientUtils.IsSecurityOrCriticalException(exception))
{
throw;
}
ambient.Value = null;
}
finally
{
CodeAccessPermission.RevertAssert();
}
}
pQaControl.cbSize = UnsafeNativeMethods.SizeOf(typeof(UnsafeNativeMethods.tagQACONTROL));
this.SetClientSite(pQaContainer.pClientSite);
if (pQaContainer.pAdviseSink != null)
{
this.SetAdvise(1, 0, (IAdviseSink) pQaContainer.pAdviseSink);
}
IntSecurity.UnmanagedCode.Assert();
try
{
((UnsafeNativeMethods.IOleObject) this.control).GetMiscStatus(1, out num);
}
finally
{
CodeAccessPermission.RevertAssert();
}
pQaControl.dwMiscStatus = num;
if ((pQaContainer.pUnkEventSink != null) && (this.control is UserControl))
{
Type defaultEventsInterface = GetDefaultEventsInterface(this.control.GetType());
if (defaultEventsInterface != null)
{
IntSecurity.UnmanagedCode.Assert();
try
{
**AdviseHelper.AdviseConnectionPoint(this.control, pQaContainer.pUnkEventSink, defaultEventsInterface, out pQaControl.dwEventCookie);**
}
catch (Exception exception2)
{
if (ClientUtils.IsSecurityOrCriticalException(exception2))
{
throw;
}
}
finally
{
CodeAccessPermission.RevertAssert();
}
}
}
if ((pQaContainer.pPropertyNotifySink != null) && UnsafeNativeMethods.IsComObject(pQaContainer.pPropertyNotifySink))
{
UnsafeNativeMethods.ReleaseComObject(pQaContainer.pPropertyNotifySink);
}
if ((pQaContainer.pUnkEventSink != null) && UnsafeNativeMethods.IsComObject(pQaContainer.pUnkEventSink))
{
UnsafeNativeMethods.ReleaseComObject(pQaContainer.pUnkEventSink);
}
}
'pUnkEventSink'变量通过tagQACONTROL结构传递给此函数,但正如您所看到的,与IAdviseSink,控件容器,字体样式等不同,此变量未设置为'ActiveXImpl'的任何成员class,因此在框架最初调用此函数后,您无法访问它。
您需要获取此IUnknown pUnkEventSink变量来调用AdviseHelper.AdviseConnectionPoint()函数,该函数将执行手动事件连接。这就是我遇到的问题 - 遗憾的是你似乎无法掌握它。
其他人有任何进一步的发展,请告诉我!
答案 4 :(得分:0)
我知道我有点迟到了,但我能够使用IConnectionPoint获得接收事件。请参阅我的回答here。具体检查MyAppDotNetWrapper
类及其在测试中的使用方式。
最终,我认为您的m_connectionPoint.Advise(this, out m_cookie);
失败了,因为this
必须是[ComVisible(true)]
,[ClassInterface(ClassInterfaceType.None)]
和public
。