{"id":6033,"date":"2007-06-01T22:59:00","date_gmt":"2007-06-01T22:59:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/vbteam\/2007\/06\/01\/so-what-does-comclass-actually-do\/"},"modified":"2024-07-05T14:45:55","modified_gmt":"2024-07-05T21:45:55","slug":"so-what-does-comclass-actually-do","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/vbteam\/so-what-does-comclass-actually-do\/","title":{"rendered":"So what does ComClass actually do?"},"content":{"rendered":"<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">I came across a <\/font><a href=\"http:\/\/www.codeproject.com\/useritems\/VB6InteropToolkit2.asp\"><font face=\"Calibri\" color=\"#800080\" size=\"3\">really cool article<\/font><\/a><font face=\"Calibri\" size=\"3\"> yesterday by James Ashley, which shows some of the cool things you can do with the <\/font><a href=\"http:\/\/go.microsoft.com\/?linkid=6886417\"><font face=\"Calibri\" color=\"#800080\" size=\"3\">Interop Forms Toolkit 2.0<\/font><\/a><font face=\"Calibri\" size=\"3\">.&nbsp;&nbsp; The three VB6 examples cover consuming a WebService (complete with a Dilbert icon showing up in the VB6 toolbox!), implementing multithreading using the BackgroundWorker component, and last but not least a cool WPF cube.&nbsp; &nbsp;Best of all there\u2019s tons of code samples and &nbsp;no less than *<b>15<\/b>* screenshots!<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">&nbsp;<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">Along with the samples there\u2019s also some C# translations of the templates that ship with the Interop Toolkit.&nbsp; While playing with these templates I was reminded of some of the subtle differences in how the VB and C# compilers handle COM Interop.&nbsp; The biggest difference is in how they handle the ComClass attribute, which we\u2019ll see by looking at some code:<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">&nbsp;<\/font><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;&nbsp;&nbsp; <span>public<\/span> <span>event<\/span> System.<span>EventHandler<\/span> ButtonClicked;<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;&nbsp;&nbsp; <span>private<\/span> <span>void<\/span> button1_Click(<span>object<\/span> sender, System.<span>EventArgs<\/span> e)<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;&nbsp;&nbsp; {<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>if<\/span> (<span>null<\/span>!=<span>this<\/span>.ButtonClicked)<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>this<\/span>.ButtonClicked.Invoke(<span>this<\/span>, e);<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;&nbsp;&nbsp; }<\/span><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">&nbsp;<\/font><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;&nbsp;&nbsp; <span>Public<\/span> <span>Event<\/span> ButtonClicked <span>As<\/span> System.EventHandler<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;&nbsp;&nbsp; <span>Private<\/span> <span>Sub<\/span> Button1_Click(<span>ByVal<\/span> sender <span>As<\/span> System.Object, <span>ByVal<\/span> e <span>As<\/span> System.EventArgs) <span>Handles<\/span> Button1.Click<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>RaiseEvent<\/span> ButtonClicked(<span>Me<\/span>, e)<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;&nbsp;&nbsp; <span>End<\/span> <span>Sub<\/span><\/span><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">&nbsp;<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">In both cases we\u2019re exposing a public event, and invoking it when the button is clicked.&nbsp; By using <\/font><a href=\"http:\/\/www.aisto.com\/roeder\/dotnet\/\"><font face=\"Calibri\" color=\"#800080\" size=\"3\">Reflector<\/font><\/a><font face=\"Calibri\" size=\"3\">, let\u2019s look at what gets generated under the covers:<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">&nbsp;<\/font><\/p>\n<p class=\"MsoNormal\"><b><font size=\"3\"><font face=\"Calibri\">C#<\/font><\/font><\/b><\/p>\n<pre><span>[<a title=\"Microsoft.VisualBasic.ComClassAttribute.ComClassAttribute(string, string, string);\" href=\"http:\/\/www.aisto.com\/roeder\/dotnet\/Default.aspx?Target=code:\/\/Microsoft.VisualBasic:8.0.0.0:b03f5f7f11d50a3a\/Microsoft.VisualBasic.ComClassAttribute\/.ctor(String,String,String)\"><span>ComClass<\/span><\/a>(<span>\"c6cbbae7-44b8-422e-840f-cbaba8e3238c\"<\/span>, <span>\"bf3ef778-6ca7-4ec8-a045-87be56528803\"<\/span>, <span>\"37b0d42a-6740-45ec-adc6-38fcbcdc48e4\"<\/span>)]<\/span><\/pre>\n<pre><span>public<\/span><span> <span>class<\/span> <a href=\"http:\/\/www.aisto.com\/roeder\/dotnet\/Default.aspx?Target=code:\/\/CSharpControl:1.0.2708.29278\/CSharpControl.InteropUserControl\"><span>InteropUserControl<\/span><\/a> : <a title=\"System.Windows.Forms.UserControl\" href=\"http:\/\/www.aisto.com\/roeder\/dotnet\/Default.aspx?Target=code:\/\/System.Windows.Forms:2.0.0.0:b77a5c561934e089\/System.Windows.Forms.UserControl\"><span>UserControl<\/span><\/a><\/span><\/pre>\n<p class=\"MsoNormal\"><span>{<\/span><\/p>\n<p class=\"MsoNormal\"><span>\u2026<\/span><\/p>\n<p class=\"MsoNormal\"><span>}<\/span><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">&nbsp;<\/font><\/p>\n<p class=\"MsoNormal\"><b><font size=\"3\"><font face=\"Calibri\">VB<\/font><\/font><\/b><\/p>\n<p class=\"MsoNormal\"><span>&lt;DesignerGenerated(), ComClass(<span>&#8220;a2ee6169-9a0d-4930-b8bb-ee71307c43b3&#8221;<\/span>, <span>&#8220;75ff3d57-6448-40ac-a294-68252180cacd&#8221;<\/span>, <span>&#8220;2b04895c-43f8-44b3-b187-00556ef53a6a&#8221;<\/span>), Guid(<span>&#8220;a2ee6169-9a0d-4930-b8bb-ee71307c43b3&#8221;<\/span>), ClassInterface(ClassInterfaceType.None), <b>ComSourceInterfaces(<span>&#8220;VBControl.InteropUserControl+__InteropUserControl&#8221;<\/span>)<\/b>&gt; _<\/span><\/p>\n<p class=\"MsoNormal\"><span>Public<\/span><span> <span>Class<\/span> InteropUserControl<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;&nbsp;&nbsp; <span>Inherits<\/span> UserControl<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;&nbsp;&nbsp; <b><span>Implements<\/span> _InteropUserControl<\/b><\/span><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">&nbsp;<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">\u2026<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">&nbsp;<\/font><\/p>\n<p class=\"MsoNormal\"><span>&lt;InterfaceType(ComInterfaceType.InterfaceIsIDispatch), Guid(<span>&#8220;2b04895c-43f8-44b3-b187-00556ef53a6a&#8221;<\/span>), ComVisible(<span>True<\/span>)&gt; _<\/span><\/p>\n<p class=\"MsoNormal\"><span>Public<\/span><span> <span>Interface<\/span> __InteropUserControl<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;&nbsp;&nbsp; &lt;DispId(1)&gt; _<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;&nbsp;&nbsp; <span>Sub<\/span> Click()<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;&nbsp;&nbsp; &lt;DispId(2)&gt; _<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;&nbsp;&nbsp; <span>Sub<\/span> DblClick()<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;&nbsp;&nbsp; &lt;DispId(3)&gt; _<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;&nbsp;&nbsp; <span>Sub<\/span> ButtonClicked(<span>ByVal<\/span> sender <span>As<\/span> <span>Object<\/span>, <span>ByVal<\/span> e <span>As<\/span> EventArgs)<\/span><\/p>\n<p class=\"MsoNormal\"><span>End<\/span><span> <span>Interface<\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>&lt;Guid(<span>&#8220;75ff3d57-6448-40ac-a294-68252180cacd&#8221;<\/span>), ComVisible(<span>True<\/span>)&gt; _<\/span><\/p>\n<p class=\"MsoNormal\"><span>Public<\/span><span> <span>Interface<\/span> _InteropUserControl<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;&nbsp;&nbsp; &lt;DispId(1)&gt; _<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;&nbsp;&nbsp; <span>Property<\/span> Visible() <span>As<\/span> <span>Boolean<\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;&nbsp;&nbsp; &lt;DispId(2)&gt; _<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;&nbsp;&nbsp; <span>Property<\/span> Enabled() <span>As<\/span> <span>Boolean<\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;&nbsp;&nbsp; &lt;DispId(3)&gt; _<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;&nbsp;&nbsp; <span>Property<\/span> ForegroundColor() <span>As<\/span> <span>Integer<\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;&nbsp;&nbsp; &lt;DispId(4)&gt; _<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;&nbsp;&nbsp; <span>Property<\/span> BackgroundColor() <span>As<\/span> <span>Integer<\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;&nbsp;&nbsp; &lt;DispId(5)&gt; _<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;&nbsp;&nbsp; <span>Property<\/span> BackgroundImage() <span>As<\/span> Image<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;&nbsp;&nbsp; &lt;DispId(6)&gt; _<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;&nbsp;&nbsp; <span>Sub<\/span> Refresh()<\/span><\/p>\n<p class=\"MsoNormal\"><span>End<\/span><span> <span>Interface<\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span>End<\/span><span> <span>Class<\/span><\/span><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">&nbsp;<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">The VB compiler has generated two extra interfaces and applied the ComSourceInterfaces attribute to the control, which it knows to do when it sees the ComClass attribute.&nbsp; ComSourceInterfaces is used to link the event sink interface to the class.&nbsp; (&lt;ComClass&gt; actually does a lot more than just making events work automatically, but we&#8217;ll leave that until another day).<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\"><\/font>&nbsp;<\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">What this means is that the VB.NET-compiled event will be visible in VB6, whereas using the C# compiler we\u2019d have to define this interface ourselves.&nbsp; This also means that certain members the template adds like Visible, ForegroundColor, Refresh etc. are automatically exposed by the VB compiler; it\u2019s still possible to do this in C#, it just takes some extra steps.<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">&nbsp;<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">Both VB and C# offer a lot of powerful features you can use to extend VB6, but it\u2019s important to be aware of the differences, especially when working with events.&nbsp;&nbsp;<\/font><font face=\"Calibri\" size=\"3\">For more information on the Interop Toolkit be sure to check out our <\/font><a href=\"http:\/\/msevents.microsoft.com\/CUI\/WebCastEventDetails.aspx?EventID=1032337474&amp;EventCategory=4&amp;culture=en-US&amp;CountryCode=US\"><font face=\"Calibri\" color=\"#800080\" size=\"3\">webcast<\/font><\/a><font face=\"Calibri\" size=\"3\"> on Wednesday.&nbsp; Also stay tuned to this blog for a series of Interop articles by Todd Apley, one of our QA leads.<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">&nbsp;<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">Jonathan<\/font><\/p>\n","protected":false},"excerpt":{"rendered":"<p>I came across a really cool article yesterday by James Ashley, which shows some of the cool things you can do with the Interop Forms Toolkit 2.0.&nbsp;&nbsp; The three VB6 examples cover consuming a WebService (complete with a Dilbert icon showing up in the VB6 toolbox!), implementing multithreading using the BackgroundWorker component, and last but [&hellip;]<\/p>\n","protected":false},"author":260,"featured_media":8818,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[192,195],"tags":[83,165,170],"class_list":["post-6033","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-featured","category-visual-basic","tag-jonathan-aneja","tag-vb2005","tag-vb6_migrationinterop"],"acf":[],"blog_post_summary":"<p>I came across a really cool article yesterday by James Ashley, which shows some of the cool things you can do with the Interop Forms Toolkit 2.0.&nbsp;&nbsp; The three VB6 examples cover consuming a WebService (complete with a Dilbert icon showing up in the VB6 toolbox!), implementing multithreading using the BackgroundWorker component, and last but [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/posts\/6033","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/users\/260"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/comments?post=6033"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/posts\/6033\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/media\/8818"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/media?parent=6033"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/categories?post=6033"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/tags?post=6033"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}