none
Interop: How to KEEP binary compatibility for a COM-visible type? RRS feed

  • Question

  • This is the flip side to the question I asked yesterday about breaking binary compatibility.

    My company has a C# assembly containing COM-visible types. None of the COM-visible types or interfaces have GUIDs assigned in the code. Apparently the GUIDs get auto-generated on build.

    If we want to maintain binary compatibility from one build to the next, I believe we'd need to start using GUID attributes in the code. So here's the first question:

    1) Is there any way to maintain binary compatibility with the current DLL, when we build the next point release?

    I do see that we can use regasm /regfile:myRegFile.tx to retrieve at least some of the GUIDs which exist for the current build. For each type, one unique GUID shows up in the file. This raises two more questions:

    2) Do the GUIDs in the regfile refer to the types themselves, or their interfaces?

    3) Is it necessary to know the GUIDs which don't appear in the regfile, and if so how would we discover them?
    Tuesday, January 13, 2009 4:10 PM

Answers

  • mfisher_ix said:

    If we want to maintain binary compatibility from one build to the next, I believe we'd need to start using GUID attributes in the code.



    You don't have to do that, but on the other hand there's nothing wrong with being explicit.

    The auto-generated GUIDs should be stable across builds, as long as you don't actually do any changes to the type that would break compatibility anyway (like adding, removing or reordering methods). To quote the docs

    "COM interfaces include an interface identifier (IID) to distinguish one interface from another. You can assign a fixed IID to any managed interface by applying the GuidAttribute attribute. If you omit this attribute and do not assign a fixed IID, the export process automatically assigns one during the conversion. A runtime-assigned IID comprises the interface name (including namespace) and the complete signature of all methods defined within the interface. By reordering the methods on the managed interface or by changing method argument and return types, you change the IID assigned to that interface. Changing a method name does not affect the IID."
    Mattias, C# MVP
    • Marked as answer by Matt Fisher Wednesday, January 14, 2009 9:50 PM
    Wednesday, January 14, 2009 12:36 PM
    Moderator

All replies

  • COM's all pretty new to me, but I poked around using OleView. From there, I opened the TLB file for our C# type using File > View TypeLib.

    It looks to me like the GUIDs I'd need to extract for the C# types and interfaces are all right there in ITypeLib Viewer as uuids. I'll try plugging those uuids into the C# code as GUID attributes, and will see if the resulting DLL can be used by code which references the existing TLB.

    Wednesday, January 14, 2009 6:58 AM
  • This seemed to work.

    I added GUID attributes, and built the DLL. I did not generate a new TLB or re-register the DLL.

    Code which references the old TLB still runs from the IDE. Code which was compiled against the old DLL still runs.

    Am I missing something, or does this count as binary compatibility? Thanks.
    Wednesday, January 14, 2009 8:10 AM
  • mfisher_ix said:

    If we want to maintain binary compatibility from one build to the next, I believe we'd need to start using GUID attributes in the code.



    You don't have to do that, but on the other hand there's nothing wrong with being explicit.

    The auto-generated GUIDs should be stable across builds, as long as you don't actually do any changes to the type that would break compatibility anyway (like adding, removing or reordering methods). To quote the docs

    "COM interfaces include an interface identifier (IID) to distinguish one interface from another. You can assign a fixed IID to any managed interface by applying the GuidAttribute attribute. If you omit this attribute and do not assign a fixed IID, the export process automatically assigns one during the conversion. A runtime-assigned IID comprises the interface name (including namespace) and the complete signature of all methods defined within the interface. By reordering the methods on the managed interface or by changing method argument and return types, you change the IID assigned to that interface. Changing a method name does not affect the IID."
    Mattias, C# MVP
    • Marked as answer by Matt Fisher Wednesday, January 14, 2009 9:50 PM
    Wednesday, January 14, 2009 12:36 PM
    Moderator
  • It has always been murky to me how the .NET compilers ensure that the IIDs don't change when it auto-generates them.  Especially when you do a clean build or use a build server.  Or if it actually changes the IID when the interface changes, that's a hard COM requirement.  Assuming it is always done right is too dangerous for my blood, nothing like DLL hell to ruin a perfectly good day.

    Always apply the [Guid] attribute to an interface declaration, change it when you change the interface.  Apply [Guid] to a class as well if you make it ComVisible, it generates the CLSID.  Change the first 2 numbers of the [AssemblyVersion], it generates the type library version number.

    Hans Passant.
    Wednesday, January 14, 2009 1:10 PM
    Moderator
  • I believe the IIDs are basically generated with a hash function, taking stuff like the LIBID, interface name and method signatures as input.

    I agree that explicitly specifying [Guid] is better if you know what you're doing. But when compared to a COM interop newbie, I'd rather trust the runtime to get it right. It's too easy to forget to update a guid if when you make changes in your code.

    Mattias, C# MVP
    Wednesday, January 14, 2009 2:36 PM
    Moderator
  • You missed the original referenced thread, the newbie aspect was the problem.  Hash function makes sense, never seen it documented anywhere.  Odd, it is important.
    Hans Passant.
    Thursday, January 15, 2009 1:34 AM
    Moderator