7

I'm trying to use a COM interface from C# that exposes the following interface as generated by tlbimp:

[Guid("7DDCEDF4-3B78-460E-BB34-C7496FD3CD56")]
[TypeLibType(TypeLibTypeFlags.FDual | TypeLibTypeFlags.FNonExtensible | TypeLibTypeFlags.FDispatchable)]
public interface IFred 
{
    [DispId(1)]
    IBarney Pall { get; set; }
}

[Guid("E390230E-EE9C-4819-BC19-08DAB808AEA9")]
[TypeLibType(TypeLibTypeFlags.FDual | TypeLibTypeFlags.FNonExtensible | TypeLibTypeFlags.FDispatchable)]
public interface IBarney
{
    [DispId(1)]
    double Wilma { get; set; }
}

The generated wrapper assembly does not contain an implementation for the IBarney interface. I've created a C# structure that implements the IBarney interface like this:

[Guid("2C61BA37-7047-43DB-84B1-83B4268CF77B")]
[ComVisible(true)]
public struct Barney : IBarney
{
    public double Wilma { get; set; }
}

Which "works", the question now is, will a Barney instance be marshalled by value or by reference? This is important due to the network overhead involved. Ideally executing something like:

fredInstance.Pall = new Barney { Wilma = 0.37 };

will result in a single network round trip. How can I verify this, or how can I tell COM interop my Barney structure should always be marshalled by value?

Update:

Given the comment from Hans Passant. What would be the 'proper' way to design this? What would be the IDL needed to allow for a simple structure to be usable as a value for a 'property' of a COM interface? Looking at the IDL from which the interfaces are generated that I'm currently using adding a coclass declaration with a default IBarney interface would be enough, right?

5
  • 1
    No need to check, COM never cares how an object is implemented and only works with interface pointers. This will be roundtrip for each property access. Technically that can be addressed with a custom proxy/stub but that is out of reach from .NET. Consider implementing IPersistStream. Commented Apr 8, 2016 at 10:55
  • @HansPassant: I'm guessing you mean implementing IPersistStream on the COM/native side? Since googling for it only reveals, references to non .NET stuff. Commented Apr 8, 2016 at 11:15
  • Are you working in C# on both ends? or is there any other language involved? ie: why are you creating COM interfaces in the first place? Why do you use idl to define your interface? Do you need automation compatible interfaces? are you aware of the difference between "pure" COM and COM+automation? Commented Apr 14, 2016 at 6:50
  • I'm working in a company that works both in .NET and in C++ and the interop between the two worlds is done using COM. I'm personally involved in the .NET development. To change the IDL/COM parts some negotiation has to take place but in principle they can be changed. One of the original requirements for the COM interfaces was that they are OLE automation compatible. I'm (as you might guess) not knowledgeable on COM, I don't know about the distinction between COM and COM+ automation. Any pointers to resources are appreciated. Commented Apr 14, 2016 at 8:32
  • ok, so you need C++, and Automation (I was not talking about COM+, but COM + Automation :-). In this case, you have to know Automation will reduce considerably the types you can use (it has its advantages also): msdn.microsoft.com/en-us/library/cc237562.aspx (beware, VT_RECORD is not supported by all clients, it was a late addition). The simplest is to use a SAFEARRAY (of UI1), or a VARIANT (can wrap any automation type). PS: dont' forget to add @ <user> when you want to address a comment. I just passed by and noticed you answered me Commented Apr 15, 2016 at 8:20

1 Answer 1

1

A couple comments... Don't know if this will be an answer or not...

1) I would think that you should make your interfaces [ComVisible(true)]

2) Why do you define Barney as a struct? It should be a class. Unlike C++ where the only difference between a class and a struct is the default of private vs public members, C# structs and classes are fundamentally different.

Sign up to request clarification or add additional context in comments.

4 Comments

Ad 1) The code was taken from a dis-assembly of a assembly generated by tlbimp, I'm assuming it uses [assembly: ComVisible(true)] somewhere in the generated code. Ad 2) Barney is a struct to emphasize the fact that it should be treated as a value type, a 'dump' container for in the example one double. In reality it is a data type that contains two doubles. I have implemented it as a struct on the .NET side and everything just 'works'. However as Hans mentions this still leads to, to many remote calls. I just want to pass the structure as a single data item to the other side of the 'fence'.
If you are worried about network overhead and initializing a struct is what you want to do, try passing as a text blob--XML or JSON, or even a comma separated list.
I'm not necessarily worried about the extra overhead, I just have the feeling that the current solution is 'suboptimal' and was wondering if the current situation could be improved, in a way that is inline with how COM is 'supposed to be used'. I'm not interested in introducing hacks, like passing text strings that have to be parsed on the other side.
I think you are make two basic mistakes. First one is that you surely have not measured anything yet and you don't know whether this is actually something you need to do. Second one is the bigger one, there is no hint in the question at all that this is actually a DCOM scenario. The kind of scenario where a property access might actually be slow and incurs the overhead of a network round-trip. Only directly supported in .NET when you derive your class from ServicedComponent class, clearly your struct does not. The question is too Flintstone to see what you are supposed to implement.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.