在C#中处理VB6事件-为什么它有时才起作用?

在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(

我有一个VB6应用程序实现为ActiveX exe。 我还有一个C#应用程序,通过COM与VB6应用程序交互

除了一种情况外,这一切都很好

如果VB6应用程序从C#应用程序中启动,则一切正常。但是,如果VB6应用程序已经独立运行,那么尽管COM接口仍然工作,但C#事件处理程序永远不会启动

下面是(非常简化的)代码摘录,名称和guid被更改以保护无辜者

VB6应用程序:myVB6App.cls(GlobalSingleUse)

(部分)由内置VB6 exe生成的IDL:

...
[
  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
    }
}