在C#中处理VB6事件-为什么它有时才起作用?
我有一个VB6应用程序实现为ActiveX exe。 我还有一个C#应用程序,通过COM与VB6应用程序交互 除了一种情况外,这一切都很好 如果VB6应用程序从C#应用程序中启动,则一切正常。但是,如果VB6应用程序已经独立运行,那么尽管COM接口仍然工作,但C#事件处理程序永远不会启动 下面是(非常简化的)代码摘录,名称和guid被更改以保护无辜者 VB6应用程序:myVB6App.cls(GlobalSingleUse) (部分)由内置VB6 exe生成的IDL:在C#中处理VB6事件-为什么它有时才起作用?,c#,vb6,interop,event-handling,events,C#,Vb6,Interop,Event Handling,Events,我有一个VB6应用程序实现为ActiveX exe。 我还有一个C#应用程序,通过COM与VB6应用程序交互 除了一种情况外,这一切都很好 如果VB6应用程序从C#应用程序中启动,则一切正常。但是,如果VB6应用程序已经独立运行,那么尽管COM接口仍然工作,但C#事件处理程序永远不会启动 下面是(非常简化的)代码摘录,名称和guid被更改以保护无辜者 VB6应用程序:myVB6App.cls(GlobalSingleUse) (部分)由内置VB6 exe生成的IDL: ... [ uuid(
...
[
uuid(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx),
version(1.10),
appobject
]
coclass myApp {
[default] interface _myApp;
[default, source] dispinterface __myApp;
};
...
[
uuid(yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy),
version(1.10),
hidden,
nonextensible
]
dispinterface __myApp {
properties:
methods:
...
[id(0x00000005)]
void myEvent();
...
};
...
C#应用程序:
正如我所说,如果在Activator.CreateInstance
运行时,VB6 exe当前没有运行,一切都按预期工作,并且在VB6应用程序中触发myEvent
时执行DoSomething()
中的代码
如果VB6应用程序事先是独立运行的,C#应用程序仍然可以通过COM(为清晰起见,上面没有显示方法)控制它,但是DoSomething()
代码永远不会运行以响应myEvent
你知道我哪里出错了吗?我认为问题在于为活动设置水槽。快速猜测一下,我会说您正在创建VB组件的一个新实例,并将一个新接收器分配给该实例生成的事件,而不是已经运行的组件 VB6文档说明: 将类的实例化属性设置为GlobalMultiUse或 GlobalSingleUse允许客户端程序使用属性和 类的方法,就像它们是全局函数一样,但在 定义GlobalMultiUse类模块的项目,对象 从类创建的不是全局的 这意味着,当您尝试连接到一个正在运行的实例时,实际上您得到的是VB6类的一个新副本,它有自己的事件,而不是已经在运行的类。因此没有收到事件。我同意,我认为您正在创建VB组件的新实例。您是否尝试过
GlobalMultiUse
而不是GlobalSingleUse
?VB6文档:
SingleUse允许其他应用程序从该类创建对象,但客户机创建的该类的每个对象都会启动组件的新实例
我还将项目线程属性设置为只有一个线程的线程池,以停止在VB6 exe中创建多个线程。这是一个类似的情况。即使VB6应用程序是GlobalSingleUse?由于我在对MarkJ类似答案的第二次评论中提到的VB6行为,将其标记为答案。噢!听起来我脑子里好像有了多用途和单一用途的含义。我会试试多用途的,看看效果如何。VB6应用程序不是我的宝贝,所以它被设置为SingleUse可能有一个很好的理由(尽管我想不出一个)。这些名字太让人困惑了。我每次都要查一下它的意思。
...
[
uuid(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx),
version(1.10),
appobject
]
coclass myApp {
[default] interface _myApp;
[default, source] dispinterface __myApp;
};
...
[
uuid(yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy),
version(1.10),
hidden,
nonextensible
]
dispinterface __myApp {
properties:
methods:
...
[id(0x00000005)]
void myEvent();
...
};
...
public class myAppInterface : IDisposable, ImyAppEvents
{
public delegate void myEventDelegate();
public event myEventDelegate myEventHandler;
private object _myApp = null;
private IConnectionPoint _connectionPoint;
private int _sinkCookie;
public myAppInterface()
{
_myApp = Activator.CreateInstance(Type.GetTypeFromProgID("myVB6ProjectName.myApp"));
Guid g = new Guid("yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy");
connectionPointContainer.FindConnectionPoint(ref g, out _connectionPoint);
_connectionPoint.Advise(this, out _sinkCookie);
}
public void myEvent()
{
if (myEventHandler != null)
{
myEventHandler();
}
}
}
[ComImport, Guid("yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy"), TypeLibType((short)4240)]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)]
public interface ImyAppEvents
{
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(5)]
void myEvent();
}
public class myC#App
{
private static myAppInterface _vb6App;
public static myAppInterface VB6Application
{
get
{
if (_vb6App == null)
{
_vb6App = new myAppInterface();
_vb6App.myEventHandler += new myAppInterface.myEventDelegate(DoSomething);
}
return _vb6App;
}
}
static void DoSomething()
{
//code to actually handle the event
}
}