📄 olerant.html.primary
字号:
<html>
<head>
<title> OLE Rant </title>
<meta name="description" content=" Criticism of OLE ">
<meta name="keywords" content="reliable, software, cplusplus, source code, example, tutorial, object oriented, programming, windows">
</head>
<body background="../images/grid.gif" bgcolor="white" text="black">
<!--Home button and Title-->
<table cellpadding=10 width="100%">
<tr>
<td width=100 align=center valign=middle>
<a href="../index.htm">
<img src="../images/rsbullet.gif" alt="RS" border=0 width=39 height=39>
<br>Home</a>
<td>
<font face="arial" color="#009966">
<center><i><b>
<font size="+3">What's Wrong with OLE</font>
<p align=center><font size="+1">Insider's story</font>
</b></i></center>
</font>
</table>
<table width="100%"><!-- main table -->
<tr>
<td width=10> <!-- Left margin -->
<td> <!-- Middle column, there is also the right margin at the end -->
<table cellpadding=10 cellspacing=0 width="100%">
<tr>
<td bgcolor=white>
<hr><!--Text-->
<font size="+1"><b>You might have heard</b></font> or read critical opinions about OLE. Programmers mostly complain about the complex system of reference counting and the lack of support for inheritance. Microsoft evangelists counter this by saying that there is no other way, and that it's for your own good<sup>1</sup>. Interfaces, it is said, <i>have to</i> be refcounted, and there is a clever hack called <b>aggregation</b> (fondly called <i>aggravation</i> by OLE programmers) that provides the same functionality as inheritance. Maybe they are right, maybe the problem of interacting with run-time-loadable objects is so complex that there simply isn't any better way? On the other hand, maybe OLE has a fatal flaw that just keeps popping up all over the place.
<!--Yellow background.-->
<table cellpadding=10 cellspacing=0 width="100%">
<tr>
<td width=20>
<td bgcolor="#e0e080">
<font face="courier" color="#cc0066"><b>
The fatal design flaw of OLE is the requirement that one should be able to get from any interface to any other interface.
</b></font>
<td width=20>
</table>
<!--End of yellow background-->
Technically this interface jumping it is done by having every interface inherit from the mother of all interfaces, <i>IUnknown</i>. <i>IUnknown</i> has the fatal method <i>QueryInterface</i> that is supposed to return any interface supported by the current object. This single assumption precludes any possibility of having simple implementation of inheritance. Let me explain why.
<p>Suppose that you have an object <i>FooObj</i> with an interface <i>IFoo</i>. This situation is easily modeled in C++ by having an abstract class (all methods pure virtual) <i>IFoo</i> and a concrete class <i>FooObj</i> that inherits from <i>IFoo</i> and implements all its methods.
<p>Now you would like to extend this object by adding support for another interface <i>IBar</i>. In C++ it's trivial, you just define a class <i>FooBarObj</i> that inherits from <i>FooObj</i> and <i>IBar</i>. This new class supports the <i>IFoo</i> interface together with its implementation through inheritance from <i>FooObj</i>. It also supports the interface <i>IBar</i> and provides the implementation of <i>IBar</i> methods.
<center><img src="images/inherit.gif" width=267 height=300 vspace=10 border=0 align="middle" alt="Inheritance diagram"></center>
Anybody who knows C++ can do it with their eyes closed. So why can't you do the same in OLE? Here comes the Flaw. You have to be able to obtain the <i>IBar</i> interface from the <i>IFoo</i> interface using its <i>QueryInterface</i>. But, wait a minute, the object <i>FooObj</i> that provides the implementation of all methods of <i>IFoo</i>, including <i>QueryInterface</i>, had no clue about <i>IBar</i>! It could have been created long before anyone even thought about the possibility of <i>IBar</i>. So how can it provide access to <i>IBar</i>?
<p>Good question. I'm not going to go into the gory details of the aggregation hack that is supposed to solve this problem. Given the constraints of the flawed initial design, it is a truly ingenious hack. So is there a better design? Read on...
<hr>
<font size="+1"><b>Have you ever noticed</b></font> how one is forced to distinguish between the <b>object</b> that implements interfaces and the <b>interfaces</b> themselves? These are two completely different notions. You can't explain anything in OLE without talking about objects, sometimes called components. Interfaces are important, but objects are even more important. When can you get one interface from another? When they share the same underlying object. You can change the state of an object using one interface and then examine this state through another interface. It's obviously the same object! In my example I described two interfaces, <i>IFoo</i> and <i>IBar</i>, and two objects (or classes of objects), <i>FooObject</i> and <i>FooBarObject</i>.
<p>In fact, anybody who's the <i>implementor</i> of interfaces (whether in C++, C, or Basic) has to deal with objects. Nevertheless, this very important abstraction is completely absent from the client's view of OLE. All that the client sees are interfaces. The underlying object is like a ghost.
<p>But it's <i>not</i> a ghost, it is physically present in the address space of your program, either directly, or as a forwarding stub. So why hide it? Indeed, wouldn't OLE be simpler with the explicit notion of an object? Let's see how it would work.
<p>The client of this "smart OLE" would call <b>CoCreateInstance</b> or <b>ClassFactory::CreateInstance</b> to obtain a pointer to an object (not an interface!). Using this pointer, the client would call <i>QueryInterface</i> to obtain an interface. If the client wanted to obtain another interface, he or she would make another <i>QueryInterface</i> call <i>through the object</i>, not through the interface. You could <i>not</i> obtain an interface from another interface. Only the object would have the ability to dispense interfaces. Bye, bye <i>IUnknown</i>!
<p>Let me show you some hypothetical code in this new "smart OLE."
<hr><!--End Text-->
<!--Yellow background-->
<table cellpadding=10 cellspacing=0 width="100%">
<tr>
<td width=20>
<td bgcolor="#e0e080">
<pre><font face="courier"><!--Code-->
CoObject * obj <font color="#000099"><b>CoCreateInstance</b></font> (CLSID_FooBarObject);
IFoo * foo = obj->QueryInterface (IID_FOO);
foo->FooMethod ();
IBar * bar = obj->QueryInterface (IID_BAR);
bar->BarMethod ();
delete obj;</font></pre><!--End Code-->
<td width=20>
</table>
<!--End of yellow background-->
<hr><!--Text-->
I purposely omitted all the error checking and reference counting. In fact, I wouldn't write code like this in a serious application, I'd use smart pointers and exceptions. But notice one thing, in "smart OLE" inheritance is as simple as in C++. Since there is no way to jump from interface to interface and there is no <i>IUnknown</i>; extending <i>FooObject</i> by adding <i>IBar</i> requires no more work than having <i>FooBarObject</i> inherit from <i>FooObject</i> and <i>IBar</i>, implementing <i>IBar</i> methods and overriding the <i>QueryInterface</i> method of <i>CoObject</i>. I assume that all "smart OLE" objects inherit from the abstract class <i>CoObject</i> and override its <i>QueryInterface</i> method (it's very much different from having every interface inherit from <i>IUnknown</i>!).
<hr>
<font size="+1"><b>What about reference counting?</b></font> The truth is, there is very little need for refcounting as long as you agree not to destroy the object while you are using its interfaces. That's not such a big deal--we do it all the time when we are using methods in C++. We don't think it's an especially harsh requirement, not to destroy the object while we are using its methods. If we were to follow OLE's current model to its full extent, we should require the client to get a refcount of any method he or she is planning to use, and then release it after the call? It would be absurd, wouldn't it?
<p>So why does OLE so meticulously count references? Simple--it's because it is hiding the object from the client. The OLE object is created implicitly when you get its first interface, and destroyed implicitly when you release its last interface. You see, OLE is doing you a big favor by hiding this bookkeeping from you. Or is it? Funny you'd ask.
<hr>
<table cellpadding=10>
<tr>
<td bgcolor="#ffccff">
<font size="+1"><b>Long, long time ago</b></font>, when computer languages were still in their infancy, the wizards of C were trying to implement a stack. They made the discovery that all the client needed in order to operate a stack were two functions, <i>push</i> and <i>pop</i>. They also realized that they would have to allocate some memory to hold stack data and, since they were neat programmers, they would have to release it when the client was done. But how would they know when the client was done? Well, obviously, the client was done when he or she didn't need to call <i>push</i> or <i>pop</i> any more. Once the wizards of C realized that, the rest was simple. The stack was created and memory allocated when the client requested the first pointer to <i>push</i>. He could then call <i>push</i> with a special argument to obtain the corresponding <i>pop</i>. In fact, using the same scheme he could create as many <i>pushes</i> and <i>pops</i> as he wished. Then, when he was done with a given <i>push</i> or <i>pop</i>, he'd simply release it. Once all the <i>pushes</i> and <i>pops</i> were released, the stack would be freed. This ingeniuos scheme simplified programming tremendously, because the clients didn't have to deal with the stack itself. The system took care of all the bookkeeping. Programmers were ecstatic and they gave all their money to the wizards of C. And, by the way, the new functions were called <i>i_push</i> and <i>i_pop</i>.
</table>
<hr>
<font size="+1"><b>Here's the best part of the story.</b></font> You might think, "Oh, right, big deal! It's easy to come up with these ideas now, after OLE has been on the market for almost a decade." What if I told you that yours truly, who worked for Microsoft back then, soon after OLE 1.0 was released, had these ideas written down and sent to the responsible people. To make the long story short, the ideas were accepted as valid, but rejected on the premise that there already had been too much code written to the OLE specification (mostly at Microsoft). No manager was willing to take the risk of redesigning OLE<sup>2</sup>.
<p>So here we are now, reference counting, aggregating and all. The moral of the story is,
<!--Yellow background.-->
<table cellpadding=10 cellspacing=0 width="100%">
<tr>
<td width=20>
<td bgcolor="#e0e080">
<font face="courier" color="#cc0066"><b>
There is nothing sacred about OLE. It <i>can</i> be done better!
</b></font>
<td width=20>
</table>
<!--End of yellow background-->
But can we have the cake and eat it too? In other words, is it possible to build "smart OLE" on top of "the other OLE"? You bet! Go straight to the <a href="ole.html">next tutorial</a>.
<hr><!--End Text-->
<sup>1</sup>It really cracked me up when I read the introduction to the chapter on Aggregation in the otherwise fine (although somehow dorky) book "Inside COM" by Dale Rogerson. If he knew the real story, he wouldn't be so adamant in his defense of aggregation.
<hr>
<sup>2</sup>All right, why should I protect the names of the perpetrators? The short-sighted manager was Jim Allchin, now senior vice-president at Microsoft. Yest, the same guy who made these outrageous statements that were cited in the DOJ's lawsuit agains Microsoft.
<p>
Microsoft Senior Vice President<B> </B>Allchin had similarly
written on December 20, 1996, that unless Microsoft were to
"<i>leverage Windows . . . . <font color="Red">I don't understand how IE is going to
win</font> . . . . Maybe being free helps us, but once people are used
to a product it is hard to change them . . . . My conclusion is
that we must leverage Windows more. Treating IE as just an add-
on to Windows which is cross-platform loses our biggest advantage
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -