<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>The COM interface contract rules exist for a reason</title><link>http://blogs.msdn.com/oldnewthing/archive/2005/11/01/487658.aspx</link><description>You can't change an interface once it has shipped.</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>re: The COM interface contract rules exist for a reason</title><link>http://blogs.msdn.com/oldnewthing/archive/2005/11/01/487658.aspx#487670</link><pubDate>Tue, 01 Nov 2005 17:41:59 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:487670</guid><dc:creator>AB</dc:creator><description>A previous company I worked for used a (misguided) attempt to get around this requirement:  Instead of creating a new interface, there was general agreement that you could new functions to an interface, but only to the end.  As long as the client knew that it was talking to a newer version of the service (which it did), it could safely call the additional function.  In theory, older clients would only call the first N functions in the interface, which would always be safe, whether the service was new or old.&lt;br&gt;&lt;br&gt;Now this might have worked if we had been using 'real' COM (or maybe we would have run into the same problem).  However, in order to run cross-platform, we had our own 'COM lite' implementation which in almost all respects worked the same.  Instead of constructing the interfaces using IDL, we just used a C++ abstract base class.  People just added functions to the end of the list, and since they get added to the end of the vtable, we were safe, as long as we were careful.&lt;br&gt;&lt;br&gt;And then one day we started getting crash reports.  When I looked into it, I discovered that the compiler had decided to be 'smart': We had an interface like this:&lt;br&gt;interface IMyComponent {&lt;br&gt;  HRESULT DoSomething( long x );&lt;br&gt;  HRESULT Print( long y );&lt;br&gt;}&lt;br&gt;Then someone had added:&lt;br&gt;  HRESULT DoSomething2( long x, long y );&lt;br&gt;&lt;br&gt;And the compiler, instead of adding it to the bottom of the vtable, like it always had before, decided that DoSomething2 belonged together with DoSomething, so the vtable looked like:&lt;br&gt;  DoSomething&lt;br&gt;  DoSomething2&lt;br&gt;  Print&lt;br&gt;&lt;br&gt;An old client tried to call Print, which ended up calling DoSomething2, which not only did the wrong thing, but popped too many arguments off the stack...  Now I'm not necessarily going to call this a compiler bug, because the whole vtable concept is just an implementation detail, but it was certainly unexpected behavior.  (Since we had a component autoupdate system, we were able to release a 3rd component that would detect the situation, 'fix up' the vtable, and keep the system alive long enough for it to be updated.&lt;br&gt;&lt;br&gt;Lesson learned: stop modifying interfaces, even at the end...</description></item><item><title>re: The COM interface contract rules exist for a reason</title><link>http://blogs.msdn.com/oldnewthing/archive/2005/11/01/487658.aspx#487684</link><pubDate>Tue, 01 Nov 2005 17:55:09 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:487684</guid><dc:creator>Chris Becke</dc:creator><description>hmmm, given that, once you are done with all the IDL stuff, what the c++ compiler gets are generated plain old header files with virtual class definitions... well, if that isn't a bug, how do the MIDL generated header files avoid the compiler re-ordering the interfaces?</description></item><item><title>re: The COM interface contract rules exist for a reason</title><link>http://blogs.msdn.com/oldnewthing/archive/2005/11/01/487658.aspx#487685</link><pubDate>Tue, 01 Nov 2005 18:02:05 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:487685</guid><dc:creator>John C. Kirk</dc:creator><description>Interesting points, and I must confess to having &amp;quot;bent the rules&amp;quot; (ahem) a few times in the past. A couple of minor typos, though:&lt;br&gt;&lt;br&gt;* &amp;quot;GetColorCount&amp;quot; should be &amp;quot;GetColorInfo&amp;quot;.&lt;br&gt;&lt;br&gt;* &amp;quot;IGraphicImage function&amp;quot; should be &amp;quot;IGraphicImage interface&amp;quot;.</description></item><item><title>re: The COM interface contract rules exist for a reason</title><link>http://blogs.msdn.com/oldnewthing/archive/2005/11/01/487658.aspx#487689</link><pubDate>Tue, 01 Nov 2005 18:10:15 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:487689</guid><dc:creator>AB</dc:creator><description>Chris, of course you are right.  I was thinking of the c-style pseudo-virtual tables that the MIDL compiler generates, but of course it generates C++ style class too, which could have the same problem.  This occured in MSVC6, I don't know if it is still around.&lt;br&gt;(Typo: Of course my interface functions were declared virtual ... =0 )</description></item><item><title>re: The COM interface contract rules exist for a reason</title><link>http://blogs.msdn.com/oldnewthing/archive/2005/11/01/487658.aspx#487734</link><pubDate>Tue, 01 Nov 2005 19:55:41 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:487734</guid><dc:creator>Stephane Rodriguez</dc:creator><description>&lt;br&gt;&amp;quot;But remember that if you change an interface, you need to generate a new Interface Identifier (IID).&amp;quot;&lt;br&gt;&lt;br&gt;Huh? As long as you add new methods at the end of your interface (with greater IDs), and never change public methods, both old (version N) and new consumers (version N+1) of that interface are happy.&lt;br&gt;&lt;br&gt;</description></item><item><title>re: The COM interface contract rules exist for a reason</title><link>http://blogs.msdn.com/oldnewthing/archive/2005/11/01/487658.aspx#487735</link><pubDate>Tue, 01 Nov 2005 19:59:52 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:487735</guid><dc:creator>julian_t</dc:creator><description>Stephane said:&lt;br&gt;&lt;br&gt;&amp;quot;Huh? As long as you add new methods at the end of your interface (with greater IDs), and never change public methods, both old (version N) and new consumers (version N+1) of that interface are happy.&amp;quot;&lt;br&gt;&lt;br&gt;And what happens if a new (version N+1) consumer happens to get hold of an older (version N) component? They try calling a method that doesn't exist in the older component and...&lt;br&gt;</description></item><item><title>re: The COM interface contract rules exist for a reason</title><link>http://blogs.msdn.com/oldnewthing/archive/2005/11/01/487658.aspx#487759</link><pubDate>Tue, 01 Nov 2005 20:58:05 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:487759</guid><dc:creator>Bryan</dc:creator><description>Not to mention Raymond's comment about what happens if you have to figure out which version is installed on a specific machine.&lt;br&gt;&lt;br&gt;It's impossible using COM alone (because QueryInterface won't tell you); you'd have to use some other attribute of the component's container file (the EXE or DLL), like a hash or version number.  But this gets unwieldy pretty fast, especially if you're patching relatively often.  It's simpler to just let the component tell you which version it is, based on the IIDs that it supports.</description></item><item><title>re: The COM interface contract rules exist for a reason</title><link>http://blogs.msdn.com/oldnewthing/archive/2005/11/01/487658.aspx#487781</link><pubDate>Tue, 01 Nov 2005 21:55:39 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:487781</guid><dc:creator>Klaus H. Probst</dc:creator><description>AB: That works (worked!) in the 'real world' very well. Because typelib binding is done in vtable order, you will rarely (if ever) brake an existing client by adding methods to an existing interface. This applies to 'semi-late' binding and COM+ interception as well.&lt;br&gt;&lt;br&gt;If you have a component doing some sort of nasty late binding IDispatch stupid tricks then it gets interesting, so you wouldn't want to use it in a *commercial* product. But for COM-based distributed apps within a corporate environment, it was a good compromise between contract and future flexibility. I hate adding numbers to interface names - your typelibs start looking like movie sequel lists.</description></item><item><title>re: The COM interface contract rules exist for a reason</title><link>http://blogs.msdn.com/oldnewthing/archive/2005/11/01/487658.aspx#487879</link><pubDate>Wed, 02 Nov 2005 01:03:39 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:487879</guid><dc:creator>PatriotB</dc:creator><description>The pattern of using both a REFIID and an LPVOID* when retrieving objects is seen throughout the main COM/OLE interfaces as well as shell interfaces.  I always wondered why they didn't just return an IUnknown and make you manually query for the interface you want -- but I suppose this way you can save making an extra call.</description></item><item><title>re: The COM interface contract rules exist for a reason</title><link>http://blogs.msdn.com/oldnewthing/archive/2005/11/01/487658.aspx#487906</link><pubDate>Wed, 02 Nov 2005 01:34:12 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:487906</guid><dc:creator>Michael Grier [MSFT]</dc:creator><description>Re: REFIID/LPVOID pattern in methods other than QueryInterface:&lt;br&gt;&lt;br&gt;One answer is the round tripping one.  When your interfaces are not remoted, you lucky dog, maybe QIing for another interface is cheap.  If your interfaces are remoted, doing two round trips to the remote machine instead of one is just kind of dumb.&lt;br&gt;&lt;br&gt;The second answer is that this is not even semantically equivalent to getting an IUnknown and QIing for a different interface.  The provider is fully allowed to give up a different kind of object depending on the IID passed in.  OLE/DB providers may exploit this pattern by giving different kinds of recordsets depending on the iid passed in when the query is executed or the table is opened.  I use this pattern regularly.</description></item><item><title>re: The COM interface contract rules exist for a reason</title><link>http://blogs.msdn.com/oldnewthing/archive/2005/11/01/487658.aspx#487946</link><pubDate>Wed, 02 Nov 2005 03:00:18 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:487946</guid><dc:creator>foxyshadis</dc:creator><description>&amp;quot;And the compiler, instead of adding it to the bottom of the vtable, like it always had before, decided that DoSomething2 belonged together with DoSomething, so the vtable looked like:&amp;quot;&lt;br&gt;&lt;br&gt;This exact error occured in the new version of avisynth; they were trying to keep it binary compatible with its hundreds of plugins by adding to the end but then whoosh, it reordered a couple new functions. Could it be mitigated by reordering the vtable in the compiled output prior to linking? (As a quick and dirty fix.)</description></item><item><title>re: The COM interface contract rules exist for a reason</title><link>http://blogs.msdn.com/oldnewthing/archive/2005/11/01/487658.aspx#487980</link><pubDate>Wed, 02 Nov 2005 05:12:59 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:487980</guid><dc:creator>Norman Diamond</dc:creator><description>From my reading of the C++ standard, a class can contain some member functions (both static and non-static) and still be a POD-struct as long as it meets stated conditions on the member variables and not having a base class etc.  And it is possible for two different POD-struct classes to be layout-compatible even if they have different member functions as long as their member variables meet stated conditions.  I wonder how compilers handle those vtables.</description></item><item><title>re: The COM interface contract rules exist for a reason</title><link>http://blogs.msdn.com/oldnewthing/archive/2005/11/01/487658.aspx#488084</link><pubDate>Wed, 02 Nov 2005 11:56:09 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:488084</guid><dc:creator>Chris Becke</dc:creator><description>So, as long as you stick to the rules, and ensure that the &amp;quot;interface&amp;quot; class is a POD struct... then you are immune to compiler re-ordering?</description></item><item><title>re: The COM interface contract rules exist for a reason</title><link>http://blogs.msdn.com/oldnewthing/archive/2005/11/01/487658.aspx#488329</link><pubDate>Wed, 02 Nov 2005 21:24:47 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:488329</guid><dc:creator>Mike Weiss</dc:creator><description>I've always developed patchs to versions of software using the ENTRIE set of source code at the point of that versions release.&lt;br&gt;&lt;br&gt;When patching two versions, I would merge those fixes into the source code of each version. And ship all, or just the changed, binaries for each version. The patch to version N was built using the headers from version N, N+1's patch was built using N+1's headers.&lt;br&gt;&lt;br&gt;Other then doubling SOME of the work when patching, whats the problem? A good SCM system helps in this area.&lt;br&gt;&lt;br&gt;</description></item><item><title>re: The COM interface contract rules exist for a reason</title><link>http://blogs.msdn.com/oldnewthing/archive/2005/11/01/487658.aspx#488529</link><pubDate>Thu, 03 Nov 2005 05:33:10 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:488529</guid><dc:creator>Norman Diamond</dc:creator><description>Wednesday, November 02, 2005 4:56 AM by Chris Becke&lt;br&gt;&amp;gt; So, as long as you stick to the rules, and&lt;br&gt;&amp;gt; ensure that the &amp;quot;interface&amp;quot; class is a POD&lt;br&gt;&amp;gt; struct... then you are immune to compiler&lt;br&gt;&amp;gt; re-ordering?&lt;br&gt;&lt;br&gt;As far as I could tell from reading relevant portions of the standard, it looks that way.  But I can't figure out how it can be true.&lt;br&gt;&lt;br&gt;In C days I could pounce on bugs in the standard and prove why they needed fixing.  (A lot of them still need fixing, i.e. weren't fixed, but I proved the need anyway.)  But I don't expect to become a C++ language lawyer.  I'll probably just remain in the status of not figuring out how things can work the way the standard says on this point.</description></item><item><title>re: The COM interface contract rules exist for a reason</title><link>http://blogs.msdn.com/oldnewthing/archive/2005/11/01/487658.aspx#488699</link><pubDate>Thu, 03 Nov 2005 19:09:10 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:488699</guid><dc:creator>Neil</dc:creator><description>Since Mozilla's build system doesn't track interface dependencies its typelibs aren't regenerated when a base interface UUID changes. You can of course work around the problem using forward references and letting the compiler/typelib loader fix up the UUIDs later.</description></item><item><title>My $0.02  &amp;raquo; Blog Archive   &amp;raquo; Don&amp;#8217;t change the rules in the middle of the game (or: There&amp;#8217;s a reason COM interfaces are immutable.)</title><link>http://blogs.msdn.com/oldnewthing/archive/2005/11/01/487658.aspx#3554635</link><pubDate>Wed, 27 Jun 2007 01:43:55 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:3554635</guid><dc:creator>My $0.02  » Blog Archive   » Don’t change the rules in the middle of the game (or: There’s a reason COM interfaces are immutable.)</dc:creator><description>&lt;p&gt;PingBack from &lt;a rel="nofollow" target="_new" href="http://blog.inconspicuous.info/archives/22"&gt;http://blog.inconspicuous.info/archives/22&lt;/a&gt;&lt;/p&gt;
</description></item></channel></rss>