COM Interop, Property Get,Let,Set Interface Attribute?

Hello,

We are in the middle of a rather large piecemeal upgrade of our VB6 system to .NET 2.0.  We started in 1.1 and have sence migrated that code to 2.0.  We have done a few of our libraries to this point, and are gearing up to upgrade a lot more of them in the next month or so.  We ran into a problem in our first library that required a rather nasty fix and I was hoping someone could point us to a better solution.

Problem:  The problem we are having is in VB6 we defined many properties of type Variant for the sole purpose of being able to store Null.  These properties are typically used to store database fields.  So they will either store say a number or null, or a string or null, or a decimal or null, etc.  Hence, the properties were setup as Lets, not Sets.  When these properties are upgraded they become Objects.  When .NET compiles this project for COM interop and creates the TLB these properties become Sets (PropPutRef in the IDL) because their datatype is Object.  We have not found a way to tell .NET to make this a LET (PropPut) when building the TLB.

Because .NET makes these properties Sets our existing VB6 code breaks because it doesn't have  Set <some property> = Whatever.  They simply say <some property> = Whatever.  If we were to go through all our VB6 code and put Sets on them it still breaks because we are not puting objects into these properties, we put things like strings and integers in.  Sets don't work with these types.

Our Solution:  The only work around to this perplexing issue is to manually fix the IDL and build our the TLB ourselves.  We get the IDL, change the PropPutRef to PropPut, fix all the other IDL syntax errors created by OleView.exe and use MIDL.exe to build the TLB based on our new IDL file.  We have some classes with 50 or more variant properties defined as Lets.  This is going to be a very cumbersome task.

Can someone please tell me of a way to trick out .NET when it builds the TLB and make specific properties Lets instead of Sets.  I cannot find any attributes that will help me in my cause.

One final thing.  We are manually building our interfaces for all of our COM classes.  We are doing this upgrade while fixing existing bugs, doing product enhancements, etc.  By defining our own interfaces we should alleviate many problems with breaking existing interfaces.  So a fix that involves a manual interface would be of no concern.  Really, any fix would be better then what we're currently doing

Thanks,

Josh



Answer this question

COM Interop, Property Get,Let,Set Interface Attribute?

  • edithr

    Well, you made do a double take, but...unfortunetately it will not solve this problem. VB6, as I am sure you are well aware, does not support method overloading. So, I am stuck with a singal signature through interop. Because of the design of our legacy (VB6) apps the datatype on these properties must remain object so that they can store Null. It's the .NET compiler that makes the assumption that because the datatype is an object the property Set must be a reference property, rather then a value property.

    I have a post on Microsoft.Public.DotNet.Framework.Interop newsgroup and they have posted that they are currently researching the issue. If you go to that newsgroup look for the post titled - Interop, Property Let vs. Set.... Default .NET .tlb build behavior

    Also, here is the Microsoft documentation on this behavior, which leads me to believe I am fighting a loosing battle. I will post on this forum whatever Microsoft tells me in the newsgroup. Thanks...

    http://msdn.microsoft.com/library/default.asp url=/library/en-us/cpguide/html/cpcontlbexpmemberconversion.asp


  • Norman Headlam

    http://www.c-sharpcorner.com/Code/2002/April/COMInteropP1AJ.asp

    May provide some useful info as its showing a COM with get/let and the .NET application using these properties.


  • Haidar

    I tested it out. The code will blow up in the wrapper class if the value of variant is not an object because you are using a Set. Apparently to VB6 it's not the Variant type it uses to determine if the set is legal, it's what is being stored in that Variant (learn something new everyday). If you pass it an object it works great.

    That was an interesting idea you had, similar to what we've done with our VB6 shared modules that we've been upgrading to .NET. Had this idea worked I probably would have stayed away from it, I think it would be easier to fix the IDL then it would be to create the wrapper classes. I want the .NET compiler to be smarter, is that asking too much. 8-)

    Homer Simpson: Professional atheletes.....always wanting more.

    Still no post on the Newsgroup. Either I've stumped them or they've forgotten about me. We'll see what's churns up next week.


  • John2006

    I'd try searching online and type in the ISBN I gave - the reason nobody else has published anything else of note on COM Interop is that a senior MS tech has published a book that says everything there is on the subject - all 1,579 pages of nothing but COM interop.

    I'm wondering in particular whether you could get the effect you want by using the System.Runtime.InteropServices.MarshallAs attribute, which allows you to specify the unmanaged type that a property represents. In particular, I'm wondering whether you can force it to expose as an unmanaged Variant, rather than as an object.


  • cliffy_1.rm

    How about creating a class in VB6, as a thin wrapper, in which the properties are declared as variant, with the values assigned as now, using LET

    Then define the class in .Net, with the properties declared as object, and the accessors therefore SET.

    Then the wrapper class can issue the SET.   By that point, any integer value or string value is now an explicit Variant variable, not an integer or string, so the SET should succeed   

    You could go further :

    Declare the properties to use their intended type, create matching setnul and isnull methods/functions for each property, have the wrapper test whether the value is null or not, and either pass the value as the right type, or use the setnul function.

    The get can use the isnull property before deciding whether to get the value or just return null.

    You might gain a tad on the efficiency, because the .Net code will be working with strict types not objects.


  • ianhannaford

    Well, I went to B & N over lunch and they had 0 books on COM interop. What a surprise. Documentation on this subject is scarce at best. It seems to me this would have been a widespread problem. I find it hard to believe Microsoft would design the compiler to simply assume a property is a set (PropPutRef) based on the datatype, without building in a work around solution.


  • ury

    Thanks for trying....but this completely misses the point. The example shown in your link is for Let properties of type string and date. These are not a problem. The problem is with Let properties of data type VARIANT. Again, in .NET they become OBJECT and when .NET builds the .TLB it assumes (because of the data type) that the properties is a Set. I need a way to override this asinine behavior without manually rebuilding the .TLB.

    Surely someone at Microsoft, in their infinite wisdom, foreseen this issue and created a workaround!!!

    Thanks again....

    Josh


  • NPrinsloo

    I will definitely check that book out.

    As far as MarshalAs goes, you don't need to do that on the Object type, it's marshaled as a Variant by .NET automatically. However, it is always ByRef, no way to specify ByVal for the property set (well, other then the technique I mentioned above, errr).

    Thank you, I appreciate your suggestions!


  • Tim862000

    If I understand your scenario properly, you have an existing body of VB6 components and you want to create either binary compatible, or at least functionaly compatible components using .NET, exposed to COM.

    I have never figured out a way to get the CLR's type library exporter to treat an Object property Set as a "put". In fact, the VB compiler emits the following warning if you declare a property as Object on a class marked <ComClass>:

    'Public Property Value() As Object' cannot be exposed to COM as a property 'Let'. You will not be able to assign non-object values (such as numbers or strings) to this property from Visual Basic 6.0 using a 'Let' statement.

    My workaround for the issue is not to let .NET generate the COM interface automatically. Instead, I use VB6 to define the interface as desired, import the VB6 type library into .NET., and then implement the interface on my .NET class.

    In the example below, I defined a VB6 ActiveX class library called Variants with a class called Class1. VB6 defines the class interface _Class1. I then import that DLL into my .NET class to implement the interface as follow:

    Imports System.Runtime.InteropServices

    <Guid(ComClass1.ClassId)> _
    <ClassInterface(ClassInterfaceType.None)> _
    <ComDefaultInterface(GetType(Variants._Class1))> _
    Public Class ComClass1
    Implements Variants._Class1

    #Region "COM GUIDs"
    Public Const ClassId As String = "48771f30-c632-47bd-a580-8d8295c9ad45"
    #End Region

    Public Sub New()
    MyBase.New()
    End Sub

    Private variant1 As Object

    Public Property Value() As Object _
    Implements Variants._Class1.Value
    Get
    Return variant1
    End Get
    Set(ByVal value As Object)
    variant1 = value
    End Set
    End Property
    End Class

    When you export the .NET class library to COM, the type library contains a reference to the orignal COM type library where the interface _Class1 was defined.

    I can call the .NET class from VB6 and assign assign Nothing, numbers, strings, variants, and COM objects to the Value property -- using a Let statement in all cases.



  • jkelly295

    Yes, it is a lot of work. We have been doing a pretty good job at side-stepping uses and making COM interop work to this point. I'd like to create a blog at some point explaining the issues and workarounds we've ran into doing it, but haven't had the time...yet.

    We have had to do some create solutions that fall along the same lines as possible workarounds you discussed in your last post. However, most of these are done on the .NET side, which makes things easier. We simply have too many shared components used throughout all of our systems to make changing the VB6 side feasible. Our goal is to build the .NET components in such a manner that the VB6 side just works. So far so good, I guess, although the work around that this issue relates to is a lot of work.

    The good news is once we get the IDL set the first time it can be used from that point on, unless of course we change the interface for any reason. Then we'll be forced to re-do the IDL for that TLB. One of our guidelines for our developers is to do everything possible not to break an interface on our classes once the code is upgraded to .NET and we're still using Interop. Once everything's .NET they'll be free again to make the needed changes.

    Thanks for posting, I appreciate your interest/concern. Again, I'll post here what Microsoft says on the issues.


  • GraemeE

    How about overloading the functions Would that help get around it
  • Skyser

    I don't have a direct answer for you.

    But THE book on this is

    ".Net and COM", "The Complete Interoperability Guide". 

    Pub: SAMS

    Author: Adam Nathan (Microsoft Corporation).

    ISBN 0-672-32170-X

    If the answer to your problem is anywhere, it will be there.


  • coderrich

    I'd thought of overloading, but I didn't suggest it, since I don't think it will help - you can't overload properties by the type of the property,  only by any parameters they take.

    I had also wondered about suggesting making the properties strictly take their types and adding explicit setnull methods and isnull functions for each property.   But it feels clumsy, and I've not yet managed to come up with a way of hiding the clumsiness.


  • NeonLight5325

    Sounds like your piecemeal upgrade is going to mean a lot of work.

    You can press on with the method of fixing statements (Maybe someone can write a program to parse the files automatically Perhaps you could tag lines that need fixing ahead of time with a comment, and look for these comments with a parser..)

    It's either that or start putting conditional statements into VB6 and write multiple methods (sort of like overloading, but each function has a slightlty different name). Of course this has drawbacks too - later if you upgrade all the components, you'll have to fix them back.


  • COM Interop, Property Get,Let,Set Interface Attribute?