A problem converting a C++ COM interface to a C# interface

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • bradyounie
    New Member
    • Aug 2008
    • 20

    A problem converting a C++ COM interface to a C# interface

    I'm trying to make a C# assembly that replaces an old C++ COM DLL. The new interface must have the same API so that the customers don't have to change code to support the new assembly. Sure, they might need to rebuild, but no code changes.

    That said, it's all going fine, except for one method in the IDL. It's defined as this:

    Code:
    [propget, id(3)] HRESULT Field([in] BSTR name, [out, retval] VARIANT *pVal);
    As you can see, it's essentially a property that takes a parameter. In VB, the code that uses this interface would look like this:

    Code:
    Request.Field("IndustryType") = "Something"
    The problem is that C# does not offer properties that take parameters like this. Is there a way to get the above results in a C# COM-interop assembly?
  • bradyounie
    New Member
    • Aug 2008
    • 20

    #2
    I solved it!

    I just use an indexer and add the IndexerName attribute to it, like this:

    Code:
    [IndexerName("Field")]
    public string this [string itemName]
    {
        ...
    }

    Comment

    • Plater
      Recognized Expert Expert
      • Apr 2007
      • 7872

      #3
      Interesting. I have not heard of either of these things (the c++ style or the vbnet/c#)
      Do you have a more complete example you could post? Like usage?

      Comment

      • bradyounie
        New Member
        • Aug 2008
        • 20

        #4
        Okay, let me see...

        The product that I'm developing is an SDK, and my team inherited one. The COM support was done in C++ and had propget line of code in its IDL. Normally, a propget has only the "out, retval" parameter, which behaves like a normal C# property. In fact, to create a COM interop interface in C# that duplicates a normal propget, you would create a property. If the IDL has both a propget and a propput with the same name, then your C# property will have both the get and set code in it.

        That's pretty normal.

        However, in IDL, you can create a prop (get and/or put) that takes a second parameter that is an [in] param. This is defined like the propget IDL sample I included in the original post, and is used like the VB I included in the original post.

        The problem is that in C#, you can't make a property take a parameter like that. So instead, I created an indexer to do what that propget did (the IDL also had a matching propput). But that only got me halfway.

        An indexer, when exposed to COM is accessed as a property called "Item", so the following C# definition:

        Code:
        public string this [string itemName] 
        { 
            get { return myhashtable[itemName]; }
            set { myhashtable.Add(itemName, value); }
        }
        will be used in VB using COM as:

        Code:
        Request.Item("IndustryType") = "Something"
        where Request is the instance of the interface. The indexer gets renamed to "Item" for you, so it works.

        But I needed the indexer to be called "Field" in order for the interface to remain the same and not require clients to make code changes when upgrading to my new C# SDK. To do that, you can use the [IndexerName] attribute to force the compiler to set the name of the indexer to anything you want, like so:

        Code:
        [IndexerName("Field")]
        public string this [string itemName] 
        { 
            get { return myhashtable[itemName]; }
            set { myhashtable.Add(itemName, value); }
        }
        will create the following behavior in VB

        Code:
        Request.Field("IndustryType") = "Something"
        Notice how the only thing that changed in the behavior is that the property name was changed from "Item" to "Field". Voila! Problem solved. I had a VB sample app that ships with the SDK. I changed its reference to point to my new COM object and ran it without modifying any code and it worked like a charm! So, now I can replace the old C++ COM DLL with my shiny new C# COM interop assembly and the clients will only need to update their reference.

        Is that more like what you were looking for?

        Comment

        Working...