0


0

C#でVB6イベントを処理する - なぜそれが時々しか動作しないのですか?

私はActiveXのexeファイルとして実装されたVB6アプリケーションを持っています。 COMを介してVB6アプリとやり取りするC#アプリケーションもあります。

1つのシナリオを除いて、これはすべてうまくいきます。

VB6アプリがC#アプリから起動されれば、すべて問題ありません。 ただし、VB6アプリが既にスタンドアロンで実行されている場合は、COMインターフェイスはまだ機能しますが、C#イベントハンドラは起動しません。

(非常に単純化された)コードの抜粋は次のとおりです。

VB6アプリ:myVB6App.cls(GlobalSingleUse)

Event myEvent()

public function RaiseMyEvent()
    RaiseEvent myEvent
end function

ビルドされた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#アプリ:

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

私が言うように、 Activator.CreateInstance`が実行されている時点でVB6 exeが現在実行されていない場合、すべてが期待通りに動作し、 DoEomething() のコードはVB6アプリで myEvent`が起動されると実行されます。

VB6アプリケーションが事前にスタンドアロンで実行されている場合、C#アプリケーションはCOM(明確にするために上記に示されていないメソッド)を介してそれを制御することができます

私が間違っているところで何かアイデア?

2 Answer


3


問題はイベントの流しを設定することにあると思います。 ちょっと推測すると、VBコンポーネントの新しいインスタンスを作成し、すでに実行中のコンポーネントではなく、そのインスタンスによって生成されたイベントに新しいシンクを割り当てるということです。


3


私はあなたがそうだと思うVBコンポーネントの新しいインスタンスを作成します。 GlobalSingleUseではなくGlobalMultiUseを試したことがありますか。 VB6のドキュメントhttp://msdn.microsoft.com/en-us/library/aa242107(VS.60).aspx[says]:

_ _SingleUse_を使用すると、他のアプリケーションがクラスからオブジェクトを作成できますが、クライアントが作成するこのクラスのオブジェクトはすべて、コンポーネントの新しいインスタンスを開始します。 _

また、VB6 exe内で複数のスレッドが作成されるのを防ぐために、プロジェクトのスレッドプロパティを1つのスレッドのみを持つスレッドプールに設定します。 同様の状況でそれはhttps://stackoverflow.com/questions/914628/getobject-and-vb6-activex-exe [私のために働く]。