Events with COM Interop & VB6.0 for C++

Greetings,
I appologize if this is in the wrong forum but this looks like the most applicable for my issue.

I've written in VS 2005 C++ COM visible classes and these work great from VB 6.0 applications. My only problem surrounds events/callbacks.

I've replaced a native ActiveX component with a .NET/COM visible one and everything works, except a simple event it needs. Under no circumstances have I been able to get VB 6.0 to reference a .NET class with the "WithEvents" keyword nor be able to install an event handler/callback.

I need a very simplistic event or callback, which is a simple single-argument "TimeOut" handler for asynchronously processing data in the .NET assembly. It simply needs to call a given VB6.0 function to be alerted for this condition and set a true/false value (which I can do with the callback itself or through API/disk or other methods if the whole STA/MTA thing gets hairy).

I've found numerous ways to accomplish this with VB.NET or C#, but zilch for C++. Hours of scouring have examples with old syntax (__event, etc.etc.) but nothing for new CLR syntax.

Are there any good sources specifically for VS2005 C++ with examples

I've create the public delegate (NOT COM visible outside my class) similar to:
[ComVisible(false)]
public delegate void TimedOut( Int32^ );

Then within my class, I create the event:

[ClassInterface(ClassInterfaceType::AutoDual)]
public ref class MyClass {
...
public:
event TimedOut ^TimedOut;
...
}

In VB60, I can see the add_ and remove_ methods for it, but cannot for the life of me bind, call or utilize this from within my C++ .NET dll. Any examples or insights would be greatly appreciated.

Also, unrelated, but what's the deal with C++ COM Interop and Boolean type In order for return values of Boolean, I've had to manually marshal these for VB6.0 to see them AS Booleans, example
[returnvalue:MarshalAs( UnmanagedType::VariantBool ) ]
Boolean myBooleanFunction( ... );

Not an issue but unsure if I'm just doing something wrong as all other CLR types automatically marshal beautifully and seamlessly (so far..).

Thanks in advance.


Answer this question

Events with COM Interop & VB6.0 for C++

  • Richard87

    Thanks to everyone for the tips, links and insights!

    I found my issue- in C++, I need to refer to the ComSourceInterface in long name (namespaceDOTInterface), compared to everywhere else needing ::.

    So, the sink to class to make this work is:
    [ComSourceInterfaces("MyNamespace.ButtonEvents")]
    In the above example.

    Thanks again to all for the direction!


  • kubmg

    I'll jump on the "unrelated" question. The VB6 Boolean type is very non-standard. True casts to -1. Every other language on the planet casts True to 1. There's a good reason for that, involving the And and Or operators in VB6. Luckily these "good reasons" are a distant memory. But as long as you're stuck interop-ing with VB6, you'll need UnmanagedType::VariantBool to have the marshaler convert True to -1.


  • PeteJM01

    Thank you everyone for the tips. I'm glad my forced Marshalling is a requirement and not just something I'm overlooking. It's a non-issue but wanted to be sure there wasn't a more desired way until the rest of the codebase is over into .NET.

    On the events issue- what I'm running into with C++ is there seems to be a cart-before-the-horse issue with the ComSourceInterfaces in C++ that I'm unable to figure out.

    If we create a very simplistic/C# converted example such as:
    -------------------------------------------------------------------------
    #pragma once
    #include "stdafx.h"
    #using <mscorlib.dll>

    using namespace System;
    using namespace System::Runtime;
    using namespace System::Runtime::InteropServices;
    using namespace System::Runtime::CompilerServices;
    using namespace System::ComponentModel;
    using namespace System::Diagnostics;
    using namespace System::Reflection;
    using namespace System::Resources;

    namespace MyNameSpace {

    public delegate void ClickDelegate(int x, int y);

    // Event sink interface (ButtonEvents)
    [GuidAttribute("1A585C4D-3371-48dc-AF8A-AFFECC1B0967") ]
    [InterfaceTypeAttribute(ComInterfaceType::InterfaceIsIDispatch)]
    public interface class ButtonEvents
    {
    // Note, also tried a distinct ID such as: [DispIdAttribute(0x60020000)]
    void Click(int x, int y);
    };


    // Connects event sink to class
    // HERE is the problem:
    // Tried:
    // [ClassInterface(ClassInterfaceType::None),ComSourceInterfaces(__typeof(ButtonEvents))]
    // [ComSourceInterfaces("ButtonEvents")]
    // [ClassInterface(ClassInterfaceType::None), ComSourceInterfaces(Type::GetType(ButtonEvents))]
    // [ClassInterface(ClassInterfaceType::None), ComSourceInterfaces("ButtonEvents")]
    // [ComSourceInterfaces(Type::GetType("ButtonEvents"))]
    // etc.etc.
    // Cannot RegAsm correctly as C++ seems to want the interface instantiated before sinking
    public ref class Button
    {
    public:
    event ClickDelegate ^Click;

    Button() {}

    void CauseClickEvent(int x, int y)
    {
    Click(x, y);
    }

    }; // end class

    } // end namespace
    -------------------------------------------------------------------------

    How can one in C++ connect the event to a class

  • Alvin Kuiper

    StevePO wrote:
    Are there any good sources specifically for VS2005 C++ with examples

    Not for VS 2005 C++ but Adam Nathan's book .NET and COM: The Complte Interoperability Guide is always useful. http://www.samspublishing.com/title/067232170X

    In VB60, I can see the add_ and remove_ methods for it,

    I think the problem is that you've got the .NET event model implemented (Delegate with add and remove methods) when what you want to implement is the COM event model (IConnectionPointContainer, IConnectionPoint, etc) which is what Visual Basic 6.0 WithEvents is expecting.

    The COMSourceInterfacesAttribute class can be used to get COM Interop to implement IConnectionPointContainer et al. I can't find a C++ sample but perhaps the VB and C# sample here might help. http://msdn.microsoft.com/library/en-us/cpguide/html/cpconraisingeventshandledbycomsink.asp

    Also, unrelated, but what's the deal with C++ COM Interop and Boolean type In order for return values of Boolean, I've had to manually marshal these for VB6.0 to see them AS Booleans

    It isn't really an Interop problem, pure COM suffers from the same difficulty. Visual Basic uses a variant of type boolean to represent true and false and uses -1 (all bits on) to represent true and 0 (all bits off) to represent false. But really (if memory serves) Visual Basic treats any value other than -1 as false. Most of the rest of the Win32 world uses 0 to mean false and any other value to mean true.

    Thus, when writing the IDL description of a COM interface you have to specify if a parameter or return value is of type 'bool' or type VARIANT_BOOL. Interop just has to go along with that and so it also has two types: UnmanagedType.Bool and UnmanagedType.VariantBool.


  • Events with COM Interop & VB6.0 for C++