locked
How to marshal a c# (VS2010) structure with a method to com interop (vb6) RRS feed

  • Question

  • hi,

    I would like to use my C# structure from VB6, but I can't marshal the method inside the structure :

    public struct AuthorData
        {
            [MarshalAs(UnmanagedType.BStr)]
            public string Prefix;
            [MarshalAs(UnmanagedType.BStr)]
            public string LastName;
            [MarshalAs(UnmanagedType.BStr)]
            public string FirstName;
           
            public void Initialize()
            {
                Prefix = string.Empty;
                LastName = string.Empty;
                FirstName = string.Empty;
            }

    }

    In my vb6 project, I can see the 3 fields but not my method !

    Is it possible to do it ? And is it also possible to marshal a enum field inside a structure ?

    public TypeEtablissement TypeIdNat; --> TypeEtablissement is a C# enum

    Thanks a lot,


    Wednesday, October 24, 2012 1:39 PM

Answers

  • Hello AgnostikFront,

    1. You need to make the TypeEtab enum Com-Visible, e.g. :

    [ComVisible(true)]
    public enum TypeEtab : sbyte
    {
        VALUE_0 = 0,
        VALUE_1 = 1,
        VALUE_2 = 2,
        VALUE_3 = 3,
        VALUE_4 = 4
    }
    
    [ComVisible(true)]
    public struct FAuthorData
    {
        [MarshalAs(UnmanagedType.BStr)]
        public string Prefix;
        [MarshalAs(UnmanagedType.BStr)]
        public string LastName;
        [MarshalAs(UnmanagedType.BStr)]
        public string FirstName;
        [MarshalAs(UnmanagedType.BStr)]
        public string OIDIdNat;
        public TypeEtab TypeIdNat;
    }

    2. This way, the type library information generated for TypeEtab and FAuthorData will be something like the following :

    typedef 
    [
      uuid(902070F7-719A-3585-B93D-6B265F4E2A2D), 
      version(1.0), 
      custom({0F21F359-AB84-41E8-9A78-36D110E6D2F9}, 
      "AgnostikFrontClassLib.TypeEtab")
    ]
    enum 
    {
      TypeEtab_VALUE_0 = 0,
      TypeEtab_VALUE_1 = 1,
      TypeEtab_VALUE_2 = 2,
      TypeEtab_VALUE_3 = 3,
      TypeEtab_VALUE_4 = 4
    } TypeEtab;
    
    
    
    typedef 
    [
      uuid(512D1E6E-045C-3F5A-83FA-69FF0B35D150), 
      version(1.0), 
      custom({0F21F359-AB84-41E8-9A78-36D110E6D2F9}, 
      "AgnostikFrontClassLib.FAuthorData")
    ]
    struct tagFAuthorData 
    {
      BSTR Prefix;
      BSTR LastName;
      BSTR FirstName;
      BSTR OIDIdNat;
      char TypeIdNat;
    } FAuthorData;

    2.1 Notice that the FAuthorData.TypeIdNat field is declared a "char" because the TypeEtab enum type has been declared as of the specific type "sbyte" in C#.

    2.2 Notice also that GUIDs have been generated by the Type Library Exporter when the class library is exported to COM (e.g. via TLBEXP.EXE).

    2.3 You can specify your own GUID by using the GuidAttribute on the TypeEtab enum and the FAuthorData struct.

    - Bio.


    Please visit my blog : http://limbioliong.wordpress.com/

    Saturday, October 27, 2012 5:09 PM

All replies

  • To expose a method to COM, it must be in a class, not a struct.

    To expose a class, add a ClassInterface attribute. Set it to AutoDual for having all public members exposed. You can use ComDefaultInterface to only expose choosen members.

    Enum fields are exposed to COM if their enum type is.

    • Edited by Louis.fr Wednesday, October 24, 2012 3:58 PM
    Wednesday, October 24, 2012 3:55 PM
  • Hi Louis.fr and thank you,

    I suspected it... :(

    But for the Enum, I don't find the correct Marshal type for my fields :

    Enum is : TypeEtab (sbyte)

    public struct FAuthorData
        {
            [MarshalAs(UnmanagedType.BStr)]
            public string Prefix;
            [MarshalAs(UnmanagedType.BStr)]
            public string LastName;
            [MarshalAs(UnmanagedType.BStr)]
            public string FirstName;
            [MarshalAs(UnmanagedType.BStr)]
            public string OIDIdNat;                
            [MarshalAs(UnmanagedType.U1)]   -----> ??
            public TypeEtab TypeIdNat;                

    }

    Do you have an idea ?

    My struct is not exposed if I make a mistake in my Marshal declaration.

    Thanks,
    Thursday, October 25, 2012 8:23 AM
  • You don't need any MarshalAs for an enum type. In fact, none of your fields needs it.
    Thursday, October 25, 2012 5:03 PM
  • I know that I don't need MarshalAs for Enum type but apparently it's necessary for a field in a structure.

    For example, the structure below is not exposed to COM because the TypeIdNat is not recognize even if the Enum Type is exposed ? If I remove this field, no problem.

    public struct FAuthorData
        {
            [MarshalAs(UnmanagedType.BStr)]
            public string Prefix;
            [MarshalAs(UnmanagedType.BStr)]
            public string LastName;
            [MarshalAs(UnmanagedType.BStr)]
            public string FirstName;
            [MarshalAs(UnmanagedType.BStr)]
            public string OIDIdNat;                
            public TypeEtab TypeIdNat;                

    }

    Thanks,

    Friday, October 26, 2012 8:27 AM
  • Hello AgnostikFront,

    1. You need to make the TypeEtab enum Com-Visible, e.g. :

    [ComVisible(true)]
    public enum TypeEtab : sbyte
    {
        VALUE_0 = 0,
        VALUE_1 = 1,
        VALUE_2 = 2,
        VALUE_3 = 3,
        VALUE_4 = 4
    }
    
    [ComVisible(true)]
    public struct FAuthorData
    {
        [MarshalAs(UnmanagedType.BStr)]
        public string Prefix;
        [MarshalAs(UnmanagedType.BStr)]
        public string LastName;
        [MarshalAs(UnmanagedType.BStr)]
        public string FirstName;
        [MarshalAs(UnmanagedType.BStr)]
        public string OIDIdNat;
        public TypeEtab TypeIdNat;
    }

    2. This way, the type library information generated for TypeEtab and FAuthorData will be something like the following :

    typedef 
    [
      uuid(902070F7-719A-3585-B93D-6B265F4E2A2D), 
      version(1.0), 
      custom({0F21F359-AB84-41E8-9A78-36D110E6D2F9}, 
      "AgnostikFrontClassLib.TypeEtab")
    ]
    enum 
    {
      TypeEtab_VALUE_0 = 0,
      TypeEtab_VALUE_1 = 1,
      TypeEtab_VALUE_2 = 2,
      TypeEtab_VALUE_3 = 3,
      TypeEtab_VALUE_4 = 4
    } TypeEtab;
    
    
    
    typedef 
    [
      uuid(512D1E6E-045C-3F5A-83FA-69FF0B35D150), 
      version(1.0), 
      custom({0F21F359-AB84-41E8-9A78-36D110E6D2F9}, 
      "AgnostikFrontClassLib.FAuthorData")
    ]
    struct tagFAuthorData 
    {
      BSTR Prefix;
      BSTR LastName;
      BSTR FirstName;
      BSTR OIDIdNat;
      char TypeIdNat;
    } FAuthorData;

    2.1 Notice that the FAuthorData.TypeIdNat field is declared a "char" because the TypeEtab enum type has been declared as of the specific type "sbyte" in C#.

    2.2 Notice also that GUIDs have been generated by the Type Library Exporter when the class library is exported to COM (e.g. via TLBEXP.EXE).

    2.3 You can specify your own GUID by using the GuidAttribute on the TypeEtab enum and the FAuthorData struct.

    - Bio.


    Please visit my blog : http://limbioliong.wordpress.com/

    Saturday, October 27, 2012 5:09 PM