C# - writing a COM server - events not firing on c

2019-06-11 02:48发布

问题:

I have implemented a COM server in C#, that has a vb6 client.

When going to fire my events, the handlers are always null--it appears that the vb6 app never subscribes to my events.

The vb6 application is an existing 3rd party app, and appears to give no error messages.

Normal methods work just fine from COM client -> server.

Is there anything I can do to debug what is going on? Or why my events are not working?

Here is a quick example snippet of my code:

    [ComVisible(true),
        Guid(Constants.CLASS_IID),
        ProgId(Constants.PROG_ID),
        ClassInterface(ClassInterfaceType.None),
        ComSourceInterfaces(typeof(IMyServiceEvents))]
    public class MyClass : Control, IMyService, IMyServiceEvents
    {
       [DispId(1)]
       public event MyEventHandler MyEvent;

       //... also implements IMyService, which is working
    }

    [ComVisible(true),
        InterfaceType(ComInterfaceType.InterfaceIsIDispatch),
        Guid(Constants.EVENTS_IID)]
    public interface IMyServiceEvents
    {
        [PreserveSig, DispId(1)]
        void MyEvent([In]int Status);
    }

    [ComVisible(false)]
    public delegate void MyEventHandler(int Status);

If I try the existing ocx file that I'm trying to replace/implement with my C# com server, the events work as usual. It is written in vb6 as well, so something in my C# server must be wrong.

I also want to add that I tried all 3 settings for ClassInterfaceType, and got the same results--although I had to re-register my COM server for each try.

Looking at my generated IDL, it looks correct to me, and everything seems to be very similar to the original IDL I'm trying to recreate, I can post if I need to.

UPDATE: Well I pulled out the old Visual Studio 6, and made a VB6 application to test my C# COM server, and it worked fine.

So I took a free vb6 decompiler that could output the decompiled code to a vb6 project, and ran it on the 3rd party app that I want to load my COM server--and saw it didn't work.

I noticed that their application is using my COM server as a control from the designer, and my test program merely declared a member variable in the form as WithEvents. Is there something going on behind the scenes with the designer that is breaking this? How can I make my COM server ActiveX compatible? I also notice that the VB6 ide won't let me add my C# com server to the toolbox as a control.

回答1:

I vaguely remember having this error myself, it's like the run time doesn't know how to map the COM registration to your event.

I went back to look at what I did an the only difference I can see is that the delegate definition is inside my COM class which I also see occurring in this example.

So try moving the MyEventHandler inside of MyClass as below:

   [ComVisible(true),
        Guid(Constants.CLASS_IID),
        ProgId(Constants.PROG_ID),
        ClassInterface(ClassInterfaceType.None),
        ComSourceInterfaces(typeof(IMyServiceEvents))]
    public class MyClass : Control, IMyService, IMyServiceEvents
    {
       [ComVisible(false)]
       public delegate void MyEventHandler(int Status);

       [DispId(1)]
       public event MyEventHandler MyEvent;



       //... also implements IMyService, which is working
    }

    [ComVisible(true),
        InterfaceType(ComInterfaceType.InterfaceIsIDispatch),
        Guid(Constants.EVENTS_IID)]
    public interface IMyServiceEvents
    {
        [PreserveSig, DispId(1)]
        void MyEvent([In]int Status);
    }


回答2:

I was deriving from Control, not UserControl, I saw an example of implementing an ActiveX control in C# that brought me to this.

Apparently UserControl implements some interface that makes this work correctly... who knows...



回答3:

You probably have forgot to add [assembly: Guid("...")] to your project, which means the TypeLib ID in COM changes everytime you recompile the C# project.

Without the attribute, the compiler will produce a different typelibrary, but some COM functions works without matching library ids.



回答4:

I found a fix for this which allowed me to use my custom control which inherited from Control (as opposed to UserControl).

In the Code Editor, add a declaration for a WithEvents variable:

Dim WithEvents ControlNameEvents As ControlLibrary.ControlName

In the Form_Load event handler, add the following code to initialize the WithEvents variable:

Private Sub Form_Load()
    Set ControlNameEvents = Me.ControlNameOnVB6Form
End Sub

Add code to handle your custom event in the WithEvents variable's event handler:

Private Sub ControlNameEvents_MyCustomEvent()
    MsgBox("My custom event fired")
End Sub

Source: http://froque.github.io/VSIXInteropFormsToolkit/How%20To/Interop%20User%20Control%20Events.html