locked
ATL COM Server - Array of Structs

    Question

  • Hi all,

    I have an ATL COM Server (in C++) and I am trying to use that server from a C# Client.

    The Server's IDL has the following:

     typedef struct MyStruct
     {
     [helpstring("Name")]
     BSTR name
     [helpstring("Number")]
     BSTR number;
     }MyStruct;
    
     [
     object,
     uuid(00000000-0000-0000-0000-000000000000),
     dual,
     nonextensible,
     helpstring("IDummy Interface"),
     pointer_default(unique)
     ]
     interface IDummy : IDispatch{
     [id(1), helpstring("method MyMethod")] HRESULT MyMethod(SAFEARRAY(MyStruct) myArray);
     };
     [
     uuid(00000000-0000-0000-0000-000000000000),
     helpstring("Dummy Class")
     ]
     coclass Dummy
     {
     [default] interface IDummy;
     };
    


    In the C# Client, when I add a reference to the COM server and view Dummy in the object browser, I can see that MyMethod takes System.Array as input. Why can't I see that MyMethod takes an array of MyStruct as defined on the server side?

    Thank you :)
    Friday, September 24, 2010 2:16 PM

Answers

  • Hello Douda123,

     

    1. When you reference a COM Type Library for a C# project, the VS IDE uses tlbimp.exe (the type library importer) to import the COM Type Library and create an Interop Assembly for it.

    1.1 The crucial point is that the IDE will use the /sysarray option.

    1.2 This means that every SAFEARRAY is converted to a .NET System.Array type.

     

    2. To change this, manually create your own Interop Assembly via the command line. Here is an example :

    tlbimp MyCOMDLL.tlb /out:Interop.MyCOMDLL.dll

    2.1 After creating your own interop assembly, drop the reference to the original type library (e.g. MyCOMDLL.tlb).

    2.2 Instead, reference the newly created interop assembly (e.g. Interop.MyCOMDLL.dll) in the C# project.

    2.3 Since Interop.MyCOMDLL.dll was created by tlbimp.exe without the /sysarray option, you will see MyMethod() listed as :

    IDummy.MyMethod(Interop.MyCOMDLL.MyStruct[])

     

    3. As an experiment, try the following :

    3.1 Add a /sysarray option to the call to tlbimp, e.g. :

    tlbimp MyCOMDLL.tlb /sysarray /out:Interop.MyCOMDLL.dll

    3.2 Make sure that you reference the newly created Interop Assembly (i.e. Interop.MyCOMDLL.dll).

    3.3 You will see MyMethod() listed as :

    IDummy.MyMethod(System.Array)

     

    - Bio.

     

    • Marked as answer by Douda123 Saturday, September 25, 2010 11:24 AM
    Saturday, September 25, 2010 7:59 AM

All replies

  • Friday, September 24, 2010 10:52 PM
  • Hello Douda123,

     

    1. When you reference a COM Type Library for a C# project, the VS IDE uses tlbimp.exe (the type library importer) to import the COM Type Library and create an Interop Assembly for it.

    1.1 The crucial point is that the IDE will use the /sysarray option.

    1.2 This means that every SAFEARRAY is converted to a .NET System.Array type.

     

    2. To change this, manually create your own Interop Assembly via the command line. Here is an example :

    tlbimp MyCOMDLL.tlb /out:Interop.MyCOMDLL.dll

    2.1 After creating your own interop assembly, drop the reference to the original type library (e.g. MyCOMDLL.tlb).

    2.2 Instead, reference the newly created interop assembly (e.g. Interop.MyCOMDLL.dll) in the C# project.

    2.3 Since Interop.MyCOMDLL.dll was created by tlbimp.exe without the /sysarray option, you will see MyMethod() listed as :

    IDummy.MyMethod(Interop.MyCOMDLL.MyStruct[])

     

    3. As an experiment, try the following :

    3.1 Add a /sysarray option to the call to tlbimp, e.g. :

    tlbimp MyCOMDLL.tlb /sysarray /out:Interop.MyCOMDLL.dll

    3.2 Make sure that you reference the newly created Interop Assembly (i.e. Interop.MyCOMDLL.dll).

    3.3 You will see MyMethod() listed as :

    IDummy.MyMethod(System.Array)

     

    - Bio.

     

    • Marked as answer by Douda123 Saturday, September 25, 2010 11:24 AM
    Saturday, September 25, 2010 7:59 AM
  • Thanks Bio for your reply :)

    Finally I can see that MyMethod taking an array for MyStruct!

    However, when I tried to call the method, I got a COM exception:

    "System.Runtime.InteropServices.COMException (0x8002802B): Element not found. (Exception from HRESULT: 0x8002802B (TYPE_E_ELEMENTNOTFOUND))"

    Here is the client code I used:

    Interop.COMArray.MyStruct struct1 = new Interop.COMArray.MyStruct();
    struct1.name = "Name";
    struct1.number = "1";

    Interop.COMArray.MyStruct[] myArray = new Interop.COMArray.MyStruct[1];
    myArray[0] = struct1;

    dummy.MyMethod(myArray);

    Please advise.

    Thanks a lot

    Saturday, September 25, 2010 8:32 AM
  • Hello Douda123,

     

    1. You need to specify a GUID for MyStruct, e.g. :

        typedef
        [
          uuid(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx),
          version(1.0),
          helpstring("MyStruct")
        ]
        struct MyStruct
        {
         [helpstring("Name")] BSTR name;
         [helpstring("Number")] BSTR number;
        } MyStruct;

     

    2. The GUID is the means by which the struct can be discovered in the type library.

     

    - Bio.

     

    Saturday, September 25, 2010 10:50 AM
  • Thanks a LOT Bio!

    You helped me a lot :)

    Saturday, September 25, 2010 11:24 AM
  • Congratulations, Douda123. You're most welcome :-)

    - Bio.

     

    Saturday, September 25, 2010 11:31 AM
  • Hi Douda123,

    I am stuck in a situation where vb.net doesnot support Bit data type but c++ can .So i wanted to create the UDT (Structures) in c++ and export the structure(not object or pointer) to vb.net so that it can be used there. I think your this thread shows some related issue and you have solved it also. So can you please help me with a sample solution.

    Thanks

    Shailendra Kumar


    Shail

    Thursday, May 31, 2012 7:28 AM