{"id":3581,"date":"2005-03-09T20:40:00","date_gmt":"2005-03-09T20:40:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/heaths\/2005\/03\/09\/guidelines-for-com-interoperability-from-net-2\/"},"modified":"2005-03-09T20:40:00","modified_gmt":"2005-03-09T20:40:00","slug":"guidelines-for-com-interoperability-from-net-2","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/setup\/guidelines-for-com-interoperability-from-net-2\/","title":{"rendered":"Guidelines for COM Interoperability from .NET"},"content":{"rendered":"<p>In developer forums in which I participate I often read and respond to questions asking about COM interoperability (interop) and my reply is almost always the same. There are guidelines &#8211; if not rules &#8211; for <a href=\"http:\/\/msdn.microsoft.com\/library\/en-us\/cpguide\/html\/cpconexposingnetframeworkcomponentstocom.asp\">exposing .NET Framework components to COM<\/a> and they are all based on guidelines for <a href=\"http:\/\/msdn.microsoft.com\/library\/en-us\/dnanchor\/html\/componentdevelopmentank.asp\">COM development<\/a>. If you have experience writing COM components these guidelines should sound familiar; if not, I hope you find this information useful.\nIn COM, you interact with components&nbsp;through interfaces, which all derive from <font face=\"Courier New\">IUnknown<\/font>. Each interface exposed to COM clients has a unique interface ID (IID) and the classes that implement those interfaces have unique class IDs (CLSIDs). In .NET you should attribute all COM-visible types with a unique value in the <font face=\"Courier New\">GuidAttribute<\/font> attribute. You can create these using <em>uuidgen.exe<\/em> or <em>guidgen.exe<\/em>.<\/p>\n<p class=\"MsoNormal\"><span>[Guid(&#8220;231d685b-6e22-49ef-a046-74e187ed0d21&#8221;)]<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>public<\/span><span> <span>interface<\/span> IFoo<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>{<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>}<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/p>\n<p><\/span>\n<span><\/p>\n<p class=\"MsoNormal\"><span>[Guid(&#8220;54c0c685-4ef2-4a1a-8693-b5773dbed295&#8221;)]<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>[ClassInterface(ClassInterfaceType.None)]<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>public<\/span><span> <span>class<\/span> Foo : IFoo<\/span><\/p>\n<p class=\"MsoNormal\">\n<p><\/span><span>{\n<\/span><\/p>\n<p class=\"MsoNormal\"><span>}<\/p>\n<p><\/span>\nNow the interfaces and classes you register will always have the same IDs from which they&#8217;re identified. To make sure the type library ID doesn&#8217;t change, you should also attribute your assembly with a unique <font face=\"Courier New\">GuidAttribute<\/font> value as well.<\/p>\n<p class=\"MsoNormal\"><span>[<\/span><span>assembly<\/span><span>: Guid(&#8220;1D2E5B02-438F-49d3-8D33-BC3451418551&#8221;)]<\/span>\nAlso, you should never use automatically-generated class interfaces using the enumerations <font face=\"Courier New\">ClassInterfaceType.AutoDispatch<\/font> or <font face=\"Courier New\">ClassInterfaceType.AutoDual<\/font>. You should define your class interface as you see above for <font face=\"Courier New\">IFoo<\/font><font face=\"Times New Roman\"> <\/font>explicitly and implement them as the first interface of your class, as well as use <font face=\"Courier New\">ClassInterfaceType.None<\/font> as the value for the <font face=\"Courier New\">ClassInterfaceAttribute<\/font><font face=\"Times New Roman\"> <\/font>on your class. If you use auto-generated class interfaces, your IID will most likely change (a problem for VTBL or &#8220;early&#8221; binding) and any changes to the order of your methods will change the order of functions in the VTBL, which is also a problem. The VTBL is a virtual table with function address used for COM clients to query using <font face=\"Courier New\">IUnknown::QueryInterface<\/font> and to call those functions. If the functions change order, your compiled client could be calling the wrong function with the wrong parameters. This order problem may also affect automation clients that cache dispatch IDs, though you can resolve that issue by attributing each property or method with the <font face=\"Courier New\">DispIdAttribute<\/font>.\nFor the same reason, you should never change a published interface; that is, you should never change the methods or properties of an interface once you&#8217;ve released it. You should create a new interface that derives from the older interface and implement that interface as your new class interface instead:<\/p>\n<p><span><\/p>\n<p class=\"MsoNormal\"><span>[Guid(&#8220;231d685b-6e22-49ef-a046-74e187ed0d21&#8221;)]<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>public<\/span><span> <span>interface<\/span> IFoo<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>{<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>int<\/span> Add(<span>int<\/span> a, <span>int<\/span> b);<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>int<\/span> Subtract(<span>int<\/span> a, <span>int<\/span> b);<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>}<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>[Guid(&#8220;bbf3e617-ee6a-4e5a-a6a5-1623edd3e6c2&#8221;)]<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>public<\/span><span> <span>interface<\/span> IFoo2 : IFoo<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>{<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>int<\/span> Multiply(<span>int<\/span> a, <span>int<\/span> b);<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>float<\/span> Divide(<span>int<\/span> a, <span>int<\/span> b);<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>}<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/p>\n<p><\/span>\n<span><\/p>\n<p class=\"MsoNormal\"><span>[Guid(&#8220;54c0c685-4ef2-4a1a-8693-b5773dbed295&#8221;)]<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>[ClassInterface(ClassInterfaceType.None)]<\/p>\n<p><\/span>\n<span><\/p>\n<p class=\"MsoNormal\"><span>public<\/span><span><font color=\"#000000\"> <\/font><span>class<\/span><font color=\"#000000\"> Foo : IFoo2<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><font color=\"#000000\">{<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>#region<\/span><span><font color=\"#000000\"> IFoo2 Members<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><font color=\"#000000\">&nbsp;<\/font><\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span><font color=\"#000000\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/font><\/span><span>public<\/span><font color=\"#000000\"> <\/font><span>int<\/span><font color=\"#000000\"> Multiply(<\/font><span>int<\/span><font color=\"#000000\"> a, <\/font><span>int<\/span><font color=\"#000000\"> b)<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><font color=\"#000000\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>{<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><font color=\"#000000\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/font><span>return<\/span><font color=\"#000000\"> a * b;<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><font color=\"#000000\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>}<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><font color=\"#000000\">&nbsp;<\/font><\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span><font color=\"#000000\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/font><\/span><span>public<\/span><font color=\"#000000\"> <\/font><span>float<\/span><font color=\"#000000\"> Divide(<\/font><span>int<\/span><font color=\"#000000\"> a, <\/font><span>int<\/span><font color=\"#000000\"> b)<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><font color=\"#000000\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>{<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><span><font color=\"#000000\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/font><\/span><span>return<\/span><font color=\"#000000\"> (<\/font><span>float<\/span><font color=\"#000000\">)a \/ (<\/font><span>float<\/span><font color=\"#000000\">)b;<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><font color=\"#000000\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>}<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><font color=\"#000000\">&nbsp;<\/font><\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>#endregion<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>#region<\/span><span><font color=\"#000000\"> IFoo Members<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><font color=\"#000000\">&nbsp;<\/font><\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span><font color=\"#000000\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/font><\/span><span>public<\/span><font color=\"#000000\"> <\/font><span>int<\/span><font color=\"#000000\"> Add(<\/font><span>int<\/span><font color=\"#000000\"> a, <\/font><span>int<\/span><font color=\"#000000\"> b)<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><font color=\"#000000\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>{<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><span><font color=\"#000000\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/font><\/span><span>return<\/span><font color=\"#000000\"> a + b;<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><font color=\"#000000\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>}<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><font color=\"#000000\">&nbsp;<\/font><\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span><font color=\"#000000\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/font><\/span><span>public<\/span><font color=\"#000000\"> <\/font><span>int<\/span><font color=\"#000000\"> Subtract(<\/font><span>int<\/span><font color=\"#000000\"> a, <\/font><span>int<\/span><font color=\"#000000\"> b)<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><font color=\"#000000\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>{<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><span><font color=\"#000000\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/font><\/span><span>return<\/span><font color=\"#000000\"> a &#8211; b;<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><font color=\"#000000\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>}<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><font color=\"#000000\">&nbsp;<\/font><\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>#endregion<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><font color=\"#000000\">}<\/font><\/span><\/p>\n<p class=\"MsoNormal\">\n<p><\/span><\/span><\/span>\nWhen registering your managed assembly for exposure to COM, you should use <em>regasm.exe<\/em> that ships with the .NET Framework redistributable. If you&#8217;re installing the assembly into the Global Assembly Cache (GAC) &#8211; which means it must be strong named &#8211; you can run the following:\n<font face=\"Courier New\">regasm.exe <em>AssemblyName.dll<\/em><\/font>\nIf you&#8217;re not installing your assembly into the GAC, you should pass the \/codebase switch to register the full path:\n<font face=\"Courier New\">regasm.exe \/codebase <em>AssemblyName.dll<\/em><\/font>\nIn both cases, you can generate a type library (typelib) using the \/tlb option. This is useful for automation clients.<\/p>\n<p>To summarize:<\/p>\n<ul>\n<li>Always attribute COM-visible classes and interface with the GuidAttribute using unique values.   <\/li>\n<li>Never use auto-generated class interfaces; always explicitly define your interfaces.   <\/li>\n<li>Never change a published interface implementation; derive a new interface as the new class interface or other interface to implement.<\/li>\n<\/ul>\n<p>You can read more about exposing .NET Framework components to COM in <a href=\"http:\/\/msdn.microsoft.com\/library\/en-us\/cpgenref\/html\/cpconExposingFunctionalityToCOM.asp\">Guidelines for Exposing Functionality to COM<\/a> in the .NET Framework SDK, as well as <a href=\"http:\/\/msdn.microsoft.com\/library\/en-us\/cpguide\/html\/cpconexposingnetframeworkcomponentstocom.asp\">Exposing .NET Framework Components to COM<\/a> and <a href=\"http:\/\/msdn.microsoft.com\/library\/en-us\/cpguide\/html\/cpconmarshalingdatawithcominterop.asp\">Marshaling Data with COM Interop<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In developer forums in which I participate I often read and respond to questions asking about COM interoperability (interop) and my reply is almost always the same. There are guidelines &#8211; if not rules &#8211; for exposing .NET Framework components to COM and they are all based on guidelines for COM development. If you have [&hellip;]<\/p>\n","protected":false},"author":389,"featured_media":3843,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[14],"class_list":["post-3581","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-development"],"acf":[],"blog_post_summary":"<p>In developer forums in which I participate I often read and respond to questions asking about COM interoperability (interop) and my reply is almost always the same. There are guidelines &#8211; if not rules &#8211; for exposing .NET Framework components to COM and they are all based on guidelines for COM development. If you have [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/setup\/wp-json\/wp\/v2\/posts\/3581","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/setup\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/setup\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/setup\/wp-json\/wp\/v2\/users\/389"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/setup\/wp-json\/wp\/v2\/comments?post=3581"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/setup\/wp-json\/wp\/v2\/posts\/3581\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/setup\/wp-json\/wp\/v2\/media\/3843"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/setup\/wp-json\/wp\/v2\/media?parent=3581"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/setup\/wp-json\/wp\/v2\/categories?post=3581"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/setup\/wp-json\/wp\/v2\/tags?post=3581"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}