<?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>Fabulous Adventures In Coding : COM Programming</title><link>http://blogs.msdn.com/ericlippert/archive/tags/COM+Programming/default.aspx</link><description>Tags: COM Programming</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Human sacrifice, dogs and cats living together, mass hysteria! and thread model errors!</title><link>http://blogs.msdn.com/ericlippert/archive/2007/05/07/human-sacrifice-dogs-and-cats-living-together-mass-hysteria-and-thread-model-errors.aspx</link><pubDate>Tue, 08 May 2007 02:22:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:2482620</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/2482620.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=2482620</wfw:commentRss><description>&lt;DIV class=mine&gt;
&lt;P&gt;Reader Shaka comments on &lt;A class="" href="http://blogs.msdn.com/ericlippert/archive/2006/07/07/659259.aspx" mce_href="http://blogs.msdn.com/ericlippert/archive/2006/07/07/659259.aspx"&gt;my post about error messages&lt;/A&gt; that "catastrophic failure" really does take the cake as being a terrible error message.&lt;/P&gt;
&lt;P&gt;I fondly remember the first time I saw "catastrophic failure" as an error message. I was an intern, running the build lab for Visual Basic for Applications, and I was trying to get the PowerPC cross-compiler working so that we could build PPC binaries on x86 hardware. (Note that this was in the early 1990's. The VS build lab is now an entire team of people who have dedicated circuits just for the cooling equipment for all their computers. We've come a long way from an intern, a closet, and six machines named after opponents of Godzilla (*).)&lt;/P&gt;
&lt;P&gt;Anyway, the compiler had a bug which caused it to run out of stack while compiling a particular module and the error was "catastrophic failure". This amused me to no end at the time. I laughed out loud, literally. I mean, &lt;EM&gt;fatal&lt;/EM&gt;, sure. That process is going &lt;EM&gt;down&lt;/EM&gt;. But "catastrophic"? I expect catastrophes to at least result in my hard disk becoming unreadable. I want bridges collapsing and floods and &lt;A href="http://frogstar.soylentgeek.com/wav/disaster.wav"&gt;mass hysteria&lt;/A&gt;!&lt;/P&gt;
&lt;P&gt;I have therefore always been rather embarrassed that the error message you get when you call the script engine on the &lt;A class="" href="http://blogs.msdn.com/ericlippert/archive/2003/09/18/53041.aspx" mce_href="http://blogs.msdn.com/ericlippert/archive/2003/09/18/53041.aspx"&gt;wrong thread&lt;/A&gt; is "catastrophic failure". That, unfortunately, is the somewhat breathless and overstated string associated with &lt;SPAN class=code&gt;E_UNEXPECTED&lt;/SPAN&gt;. Basically we want to say "you called us in a completely unexpected way which thoroughly violates the engine contract, please don't do that". But "catastrophic failure" is what you get. I wish now that we'd declared a new &lt;A href="http://blogs.msdn.com/ericlippert/archive/2003/10/22/53267.aspx"&gt;HRESULT&lt;/A&gt; just for "you've violated the engine contract". But it's far, far too late now.&lt;/P&gt;
&lt;P&gt;(*) In the interests of total accuracy: the OLE Automation build machines were named after Godzilla's opponents: Mothra, Monster Zero, etc. The VBA build machines were named after species of marine mammals: sei, humpback, etc.&lt;/P&gt;&lt;/DIV&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=2482620" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Scripting/default.aspx">Scripting</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/COM+Programming/default.aspx">COM Programming</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Threading/default.aspx">Threading</category></item><item><title>Chained user-defined explicit conversions in C#, Part Three</title><link>http://blogs.msdn.com/ericlippert/archive/2007/04/20/chained-user-defined-explicit-conversions-in-c-part-three.aspx</link><pubDate>Fri, 20 Apr 2007 17:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:2178829</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/2178829.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=2178829</wfw:commentRss><description>&lt;DIV class=mine&gt;
&lt;P&gt;Jeroen Frijters knew the answer to my challenge of last time: how is it that &lt;SPAN class=code&gt;Foo foo = new Foo();&lt;/SPAN&gt; can cause a runtime conversion failure? And how is it that &lt;SPAN class=code&gt;Bar bar = (Bar)(new Baz());&lt;/SPAN&gt; can succeed even if there is no user-defined conversion or built-in implicit conversion between &lt;SPAN class=code&gt;Baz&lt;/SPAN&gt; and &lt;SPAN class=code&gt;Bar&lt;/SPAN&gt;?&lt;/P&gt;
&lt;P&gt;The answer is that it is, as Stuart Ballard editorialized, “a goofy COM interop thing that the language should never have supported directly”.&lt;/P&gt;
&lt;P&gt;In COM programming you never talk to a object directly, as a class. Rather, the object has a number of public interfaces; the client of a particular object asks the object for the interface it wants, and it talks to the object on that interface. COM provides a special function called &lt;SPAN class=code&gt;CoCreateInstance&lt;/SPAN&gt; which gets the ball rolling; it knows how to create an instance of a specific class and provides a pointer to a given interface on that object.&lt;/P&gt;
&lt;P&gt;Suppose you need to interoperate with an existing COM object in C#. We could have made you do all the work you’d do in a C++ program: call &lt;SPAN class=code&gt;CoCreateInstance&lt;/SPAN&gt;, get the interface, blah blah blah. But that’s kind of gross and ugly. Instead, we take advantage of the fact that the vast majority of the time that you are talking to a COM object is via an interop library created with the type library importer. The type library importer knows from the information in the type library which interfaces are associated with which coclasses. The typical pattern of interop classes created by the type library importer would look something like this if we wrote out the code in C#:&lt;/P&gt;&lt;SPAN class=code&gt;
&lt;P&gt;using System.Runtime.InteropServices;&lt;BR&gt;[ComImport]&lt;BR&gt;[Guid("12345678-1234-1234-1234-123412341234")]&lt;BR&gt;[CoClass(typeof(InteropClass))]&lt;BR&gt;public interface IMyInterface&lt;BR&gt;{ /* whatever */}&lt;BR&gt;public class InteropClass : IMyInterface {/*whatever*/}&lt;/P&gt;&lt;/SPAN&gt;
&lt;P&gt;So the C# compiler knows that &lt;SPAN class=code&gt;IMyInterface&lt;/SPAN&gt; is associated with the coclass &lt;SPAN class=code&gt;InteropClass&lt;/SPAN&gt;. We therefore allow this:&lt;/P&gt;&lt;SPAN class=code&gt;
&lt;P&gt;IMyInterface x = new IMyInterface();&lt;/P&gt;&lt;/SPAN&gt;
&lt;P&gt;as is a syntactic sugar for&lt;/P&gt;&lt;SPAN class=code&gt;
&lt;P&gt;IMyInterface x = (IMyInterface)(new InteropClass());&lt;/P&gt;&lt;/SPAN&gt;
&lt;P&gt;So this is yet another place where we introduce an explicit cast on your behalf. &lt;/P&gt;
&lt;P&gt;This means that it is legal to say&lt;/P&gt;&lt;SPAN class=code&gt;
&lt;P&gt;InteropClass x = (InteropClass)(new IMyInterface());&lt;/P&gt;&lt;/SPAN&gt;
&lt;P&gt;And it will not fail at run time, even though there is no user-defined conversion or built-in implicit conversion from &lt;SPAN class=code&gt;IMyInterface&lt;/SPAN&gt; to &lt;SPAN class=code&gt;InteropClass&lt;/SPAN&gt;!&lt;/P&gt;
&lt;P&gt;Unfortunately, there’s a bit of a bug in the C# compiler. We assume two things. First, that the type library importer always generates this pattern correctly, and second, that no one other than the type library importer pulls shenanigans like this. The first assumption is probably good, but there’s nothing stopping anyone from pulling shens like:&lt;/P&gt;&lt;SPAN class=code&gt;
&lt;P&gt;using System.Runtime.InteropServices;&lt;BR&gt;[ComImport]&lt;BR&gt;[Guid("12345678-1234-1234-1234-123412341234")]&lt;BR&gt;[CoClass(typeof(InteropClass))]&lt;BR&gt;public interface IMyInterface&lt;BR&gt;{ /* whatever */}&lt;BR&gt;public class InteropClass {/*whatever*/} // oops, no interface&lt;/P&gt;&lt;/SPAN&gt;
&lt;P&gt;The compiler does not check to see if &lt;SPAN class=code&gt;InteropClass&lt;/SPAN&gt; actually implements &lt;SPAN class=code&gt;IMyInterface&lt;/SPAN&gt;! Therefore this guaranteed-to-fail explicit cast gets through at compile time and fails at run time.&lt;/P&gt;
&lt;P&gt;Obviously this is really gross. I don’t think we’ll get to fixing this in C# 3.0, but perhaps in a later version of the language we will tighten this up and make it illegal to have a coclass which does not actually implement the given interface.&lt;/P&gt;
&lt;P&gt;Next time, one more place where poorly specified compiler behaviour causes us to insert an explicit cast.&lt;/P&gt;&lt;/DIV&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=2178829" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/COM+Programming/default.aspx">COM Programming</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Puzzles/default.aspx">Puzzles</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Conversions/default.aspx">Conversions</category></item><item><title>Do Not Call IsBadFooPtr, Indeed</title><link>http://blogs.msdn.com/ericlippert/archive/2006/09/27/774117.aspx</link><pubDate>Wed, 27 Sep 2006 21:16:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:774117</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>11</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/774117.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=774117</wfw:commentRss><description>&lt;DIV class=mine&gt;
&lt;P&gt;Here’s a story that I said &lt;A href="http://blogs.msdn.com/ericlippert/archive/2004/03/31/105329.aspx"&gt;a long time ago that I was going to tell you all&lt;/A&gt;, and then promptly forgot about it. &lt;A href="http://blogs.msdn.com/oldnewthing/archive/2006/09/27/773741.aspx"&gt;Raymond Chen’s blog entry today&lt;/A&gt; reminded me of it, because this is the story of how I found out the hard way that &lt;SPAN class=code&gt;IsBadFooPtr&lt;/SPAN&gt; is bad, bad, bad. Those of you who have been following releases of the script engines incredibly carefully may remember this story, but hopefully we caused and then fixed the problem sufficiently quickly that the vast majority of customers never noticed. &lt;/P&gt;
&lt;P&gt;But I’m getting ahead of myself. &lt;/P&gt;
&lt;P&gt;One of the most basic and important rules of COM programming is that you never, ever, &lt;B&gt;EVER&lt;/B&gt; change an interface without changing its &lt;SPAN class=code&gt;GUID&lt;/SPAN&gt;. Or, to put it another way, you simply never change an interface; if you need to, you create an entirely new interface. &lt;/P&gt;
&lt;P&gt;You may have wondered why is COM so strict about this rule. It’s because when you write a C++ program that uses an interface, the compiler will generate code that depends upon the particular pattern of stack frame layouts for passing arguments remaining exactly the same even when the user installs a new version of the COM object on their machine. Because COM objects and their “clients” can be versioned independently, the &lt;SPAN class=code&gt;GUID&lt;/SPAN&gt; has to be associated with a particular “binary contract” describing how the two pieces of code communicate. &lt;/P&gt;
&lt;P&gt;Now, the script engines always talk to scriptable objects via &lt;SPAN class=code&gt;IDispatch&lt;/SPAN&gt; or &lt;SPAN class=code&gt;IDispatchEx&lt;/SPAN&gt;, so if a scriptable object accidentally breaks its contract, the script engines don’t notice a bit. They let the dispatch layer take care of all those irksome details about stack frame layout, and the dispatch layer figures all this stuff out from the type library data in the object itself. &lt;/P&gt;
&lt;P&gt;Perhaps you see where this is going. &lt;/P&gt;
&lt;P&gt;The &lt;SPAN class=code&gt;Replace&lt;/SPAN&gt; method of the VBScript regular expression object originally took two “in” arguments, both strings, and returned a string. This was the &lt;SPAN class=code&gt;IRegExp&lt;/SPAN&gt; interface. Later we realized that we wanted to be able to pass things other than strings for the second argument, so we created a new &lt;SPAN class=code&gt;IRegExp2&lt;/SPAN&gt; interface where the &lt;SPAN class=code&gt;Replace&lt;/SPAN&gt; method took a string and a variant, and returned a string. So far, so good. &lt;/P&gt;
&lt;P&gt;Then we ported the script engines to the IA64 processor. During the port for some unknown reason one of the developers temporarily changed the second argument from a &lt;SPAN class=code&gt;VARIANT&lt;/SPAN&gt; to a &lt;SPAN class=code&gt;VARIANT*&lt;/SPAN&gt;, put a comment in the code saying that this needed to be changed back before it was checked in, checked it in, and, uh, we kinda shipped it like that. &lt;/P&gt;
&lt;P&gt;We thoroughly violated the rules of COM, but none of our automated tests showed this, because of course, all of the scripting automated tests were written – you guessed it – in &lt;I&gt;script&lt;/I&gt;. &lt;B&gt;We had no tests which used the scriptable objects from early-bound code.&lt;/B&gt; (We do now!) &lt;/P&gt;
&lt;P&gt;Unfortunately, some of our developer customers were using the VBScript regular expression object from C++ and other early bound languages, so as soon as &lt;EM&gt;their&lt;/EM&gt; customers upgraded to the latest version of scripting, all hell broke loose. The caller was fulfilling their end of the contract by putting a sixteen byte variant on the stack, and the callee was suddenly expecting a four byte pointer to a variant, so it was both crashing and misaligning the stack. &lt;/P&gt;
&lt;P&gt;We &lt;I&gt;immediately&lt;/I&gt; started getting bug reports, of course. About half the bug reports said “please change this back ASAP, our customers are broken”, and the other half said “we have already shipped a patch of our code to our customers using the new stack layout, please do not change it back, ever, we do not want to ship another patch”. &lt;/P&gt;
&lt;P&gt;Obviously we realized that we had badly screwed up and were now in a hideous bind. We came up with three options: &lt;/P&gt;
&lt;P&gt;First, we could revert to the previous layout, and inconvenience the small number of customers who had already shipped patches to &lt;I&gt;their&lt;/I&gt; customers. (And of course, inconvenience all of those people as well, who would have to apply a second patch in as many days.) &lt;/P&gt;
&lt;P&gt;Second, we could keep the current layout and tell the rest of our affected customers that they needed to patch our mistake. &lt;/P&gt;
&lt;P&gt;Third, we could revert to the previous layout and yet NOT inconvenience anyone. &lt;/P&gt;
&lt;P&gt;Obviously the third option is best, but how to do it? &lt;/P&gt;
&lt;P&gt;I ended up writing heuristics into the &lt;SPAN class=code&gt;Replace&lt;/SPAN&gt; method that examined the stack frame, and then rerouted the call to a special helper method if we detected a &lt;SPAN class=code&gt;VARIANT*&lt;/SPAN&gt; on the stack when we were expecting a &lt;SPAN class=code&gt;VARIANT&lt;/SPAN&gt;. The helper method did all the necessary magic to adjust the stack pointer, and so on, so that from the caller’s perspective, everything looked perfectly normal. &lt;/P&gt;
&lt;P&gt;Now, remember, we expected that in the vast majority of cases, a &lt;SPAN class=code&gt;VARIANT&lt;/SPAN&gt; would be passed, not a &lt;SPAN class=code&gt;VARIANT*&lt;/SPAN&gt;. My heuristic detected which case we were in by extracting four bytes from the middle of the stack frame and calling &lt;SPAN class=code&gt;IsBadReadPtr&lt;/SPAN&gt; on it. If that was a valid pointer then I’d cast it to a &lt;SPAN class=code&gt;VARIANT*&lt;/SPAN&gt;, check to see whether the variant type field was a string (by far the most likely argument to &lt;SPAN class=code&gt;Replace&lt;/SPAN&gt;), and then call &lt;SPAN class=code&gt;IsBadWritePtr&lt;/SPAN&gt; on the &lt;SPAN class=code&gt;bstrVal&lt;/SPAN&gt; (because &lt;SPAN class=code&gt;BSTR&lt;/SPAN&gt; pointers are &lt;A href="http://blogs.msdn.com/ericlippert/archive/2003/09/12/52976.aspx"&gt;almost always writeable&lt;/A&gt;). There were a few other details to the heuristic, but the point is that in the vast majority of cases, &lt;SPAN class=code&gt;IsBadReadPtr&lt;/SPAN&gt; was expected to fail. Only in the rare cases where we were in an early-bound and third-party patched program should it succeed. &lt;/P&gt;
&lt;P&gt;We shipped the fixed version with the heuristics out immediately. &lt;/P&gt;
&lt;P&gt;At the time I did not realize how &lt;SPAN class=code&gt;IsBadReadPtr&lt;/SPAN&gt; was implemented. It actually puts a &lt;SPAN class=code&gt;try-except&lt;/SPAN&gt; around an attempt to read the pointer! If it gets an exception then it&amp;nbsp;eats the exception and says yeah, it's bad. Essentially what I had done was inserted an almost-always-thrown exception into every call to &lt;SPAN class=code&gt;Replace&lt;/SPAN&gt;. &lt;/P&gt;
&lt;P&gt;My goal of not inconveniencing anyone turned out to not quite work out as planned. The Active Server Pages team went nuts that afternoon. Their tests assume that all exceptions, whether handled or not, are flaws somewhere in ASP or scripting. Their test machines are all configured to track and report &lt;I&gt;all&lt;/I&gt; first-chance exceptions, and suddenly every compatibility and stress test machine they had that happened to do a regular expression replace – that is, approximately all of them – suddenly started reporting hundreds of first-chance exceptions per minute when they upgraded to the latest released version. &lt;/P&gt;
&lt;P&gt;So just when I thought that I could breathe easy again for a few minutes I started getting calls from the now highly vexed ASP team. I ended up writing my own versions of &lt;SPAN class=code&gt;IsBadFooPtr&lt;/SPAN&gt; which do the right thing – they call &lt;SPAN class=code&gt;VirtualQuery&lt;/SPAN&gt; to ask the operating system what the protection state of a given address is, rather than simply trying it out and throwing a first-chance exception on failure. &lt;/P&gt;
&lt;P&gt;Long story short: don’t change an interface, don’t call &lt;SPAN class=code&gt;IsBadFooPtr&lt;/SPAN&gt;, and run your changes by &lt;I&gt;all&lt;/I&gt; your important consumers &lt;I&gt;before&lt;/I&gt; you ship a tricky fix! &lt;/P&gt;&lt;/DIV&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=774117" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/VBScript/default.aspx">VBScript</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/COM+Programming/default.aspx">COM Programming</category></item><item><title>Checking For Script Syntax Errors, This Time With Code</title><link>http://blogs.msdn.com/ericlippert/archive/2005/10/12/480154.aspx</link><pubDate>Wed, 12 Oct 2005 19:37:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:480154</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>9</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/480154.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=480154</wfw:commentRss><description>&lt;FONT face="lucida sans unicode" color=purple size=2&gt;
&lt;P&gt;A number of people asked me to clarify yesterday's entry.&amp;nbsp;Rather than try to talk you through it, I think the code is straightforward enough to speak for itself.&amp;nbsp;Here's a little skeleton that I just whipped up.&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face="lucida console" color=navy size=2&gt;
&lt;P&gt;#include &amp;lt;stdio.h&amp;gt;&lt;BR&gt;#include &amp;lt;activscp.h&amp;gt;&lt;BR&gt;#include &amp;lt;new&amp;gt;&lt;/P&gt;
&lt;P&gt;const GUID CLSID_VBScript = {0xb54f3741, 0x5b07, 0x11cf, {0xa4, 0xb0, 0x00, 0xaa, 0x00, 0x4a, 0x55, 0xe8}};&lt;BR&gt;const GUID CLSID_JScript&amp;nbsp; = {0xf414c260, 0x6ac0, 0x11cf, {0xb6, 0xd1, 0x00, 0xaa, 0x00, 0xbb, 0xbb, 0x58}};&lt;/P&gt;
&lt;P&gt;class MySite : public IActiveScriptSite {&lt;BR&gt;private:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;ULONG m_cref;&lt;BR&gt;&amp;nbsp; virtual ~MySite() {}&lt;/P&gt;
&lt;P&gt;public:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;MySite() {&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;this-&amp;gt;m_cref = 1;&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp; STDMETHOD_(ULONG, AddRef)() {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return ++this-&amp;gt;m_cref;&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp; STDMETHOD_(ULONG,Release)() {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; --this-&amp;gt;m_cref;&lt;BR&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;if (this-&amp;gt;m_cref == 0) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;delete this;&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;return 0;&lt;BR&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return this-&amp;gt;m_cref;&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;STDMETHOD(QueryInterface)(REFIID iid, void ** ppv) {&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;if (ppv == NULL)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;return E_POINTER;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (IsEqualIID(iid, IID_IUnknown))&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;*ppv = (IUnknown*)this;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; else if (IsEqualIID(iid, IID_IActiveScriptSite))&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;*ppv = (IActiveScriptSite*)this;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; else {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;*ppv = NULL;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;return E_NOINTERFACE;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; this-&amp;gt;AddRef();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return S_OK;&lt;BR&gt;&amp;nbsp; }&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;STDMETHOD(GetLCID)(LCID * plcid) {&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;return E_NOTIMPL;&lt;BR&gt;&amp;nbsp; }&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;STDMETHOD(GetItemInfo)(&lt;BR&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;LPCOLESTR pstrName,&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;DWORD dwReturnMask,&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; IUnknown ** ppunkItem,&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ITypeInfo ** ppti) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return E_NOTIMPL;&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp; STDMETHOD(GetDocVersionString)(BSTR * pbstrVersion) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return E_NOTIMPL;&lt;BR&gt;&amp;nbsp; }&lt;/P&gt;
&lt;P&gt;&amp;nbsp; STDMETHOD(OnScriptTerminate)(&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;const VARIANT * pvarResult,&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;const EXCEPINFO * pexcepinfo) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return S_OK;&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp; STDMETHOD(OnStateChange)(SCRIPTSTATE state) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return S_OK;&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;STDMETHOD(OnEnterScript)() {&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;return S_OK;&lt;BR&gt;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&amp;nbsp; STDMETHOD(OnLeaveScript)() {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return S_OK;&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp; STDMETHOD(OnScriptError)(IActiveScriptError * perror) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; EXCEPINFO excepinfo;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; LONG column = 0;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ULONG line = 0;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; DWORD context = 0;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; BSTR bstrLine = NULL;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; memset(&amp;amp;excepinfo, 0x00, sizeof excepinfo);&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;perror-&amp;gt;GetExceptionInfo(&amp;amp;excepinfo);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (excepinfo.pfnDeferredFillIn != NULL)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;excepinfo.pfnDeferredFillIn(&amp;amp;excepinfo);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; perror-&amp;gt;GetSourceLineText(&amp;amp;bstrLine);&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;perror-&amp;gt;GetSourcePosition(&amp;amp;context, &amp;amp;line, &amp;amp;column);&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;wprintf(L"Error on line %ld column %ld\n", line, column);&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;if (bstrLine != NULL)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; wprintf(L"Line: %s\n", bstrLine);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (excepinfo.bstrDescription != NULL)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;wprintf(L"Description: %s\n", excepinfo.bstrDescription);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (excepinfo.bstrSource != NULL)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;wprintf(L"Source: %s\n", excepinfo.bstrSource);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (excepinfo.bstrHelpFile != NULL)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;wprintf(L"Help: %s\n", excepinfo.bstrHelpFile);&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SysFreeString(bstrLine);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SysFreeString(excepinfo.bstrDescription);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SysFreeString(excepinfo.bstrSource);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SysFreeString(excepinfo.bstrHelpFile);&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return S_OK;&lt;BR&gt;&amp;nbsp; }&lt;BR&gt;};&lt;/P&gt;
&lt;P&gt;void main() {&lt;BR&gt;&amp;nbsp; HRESULT hr = S_OK;&lt;BR&gt;&amp;nbsp; HRESULT hrInit;&lt;BR&gt;&amp;nbsp; IClassFactory * pfactory = NULL;&lt;BR&gt;&amp;nbsp; IActiveScript * pscript = NULL;&lt;BR&gt;&amp;nbsp; IActiveScriptParse * pparse = NULL;&lt;BR&gt;&amp;nbsp; IActiveScriptSite * psite = NULL;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; hr = hrInit = OleInitialize(NULL);&lt;BR&gt;&amp;nbsp; if (FAILED(hr))&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; goto LError;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; hr = CoGetClassObject(CLSID_VBScript, CLSCTX_SERVER, NULL, &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; IID_IClassFactory, (void**)&amp;amp;pfactory);&lt;BR&gt;&amp;nbsp; if (FAILED(hr))&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; goto LError;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; hr = pfactory-&amp;gt;CreateInstance(NULL, IID_IActiveScript, (void**)&amp;amp;pscript);&lt;BR&gt;&amp;nbsp; if (FAILED(hr))&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; goto LError;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; psite = new(std::nothrow) MySite();&lt;BR&gt;&amp;nbsp; if (psite == NULL) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; hr = E_OUTOFMEMORY;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; goto LError;&lt;BR&gt;&amp;nbsp; }&lt;/P&gt;
&lt;P&gt;&amp;nbsp; hr = pscript-&amp;gt;SetScriptSite(psite);&lt;BR&gt;&amp;nbsp; if (FAILED(hr))&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; goto LError;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; hr = pscript-&amp;gt;QueryInterface(IID_IActiveScriptParse, (void**)&amp;amp;pparse);&lt;BR&gt;&amp;nbsp; if (FAILED(hr))&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; goto LError;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; hr = pparse-&amp;gt;ParseScriptText(L"Function Foo \n Foo = 123 \n End Funtcion \n",&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; NULL, NULL, NULL, 0, 1, 0, NULL, NULL);&lt;/P&gt;
&lt;P&gt;&amp;nbsp; if (FAILED(hr))&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;goto LError;&lt;BR&gt;&amp;nbsp;&lt;BR&gt;LError:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;if (FAILED(hr))&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;printf("%0x\n", hr);&lt;/P&gt;
&lt;P&gt;&amp;nbsp; if (pparse != NULL)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; pparse-&amp;gt;Release();&lt;/P&gt;
&lt;P&gt;&amp;nbsp; if (psite != NULL)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; psite-&amp;gt;Release();&lt;/P&gt;
&lt;P&gt;&amp;nbsp; if (pscript != NULL) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; pscript-&amp;gt;Close();&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;pscript-&amp;gt;Release();&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp; if (pfactory != NULL)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; pfactory-&amp;gt;Release();&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;if (SUCCEEDED(hrInit))&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;OleUninitialize();&lt;BR&gt;}&lt;/P&gt;&lt;FONT face="lucida sans unicode" color=purple size=2&gt;
&lt;P&gt;As you would expect, this program prints out the information about the error, and ParseScriptText returns SCRIPT_E_REPORTED to indicate that there was an error but it has already been reported. Had there been no error, the script would not have actually&amp;nbsp;run; the engine is not &lt;STRONG&gt;started&lt;/STRONG&gt;, just &lt;STRONG&gt;initialized&lt;/STRONG&gt;.&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;Error on line 3 column 5&lt;BR&gt;Line:&amp;nbsp; End Funtcion&lt;BR&gt;Description: Expected 'Function'&lt;BR&gt;Source: Microsoft VBScript compilation error&lt;BR&gt;80020101&lt;/P&gt;&lt;/FONT&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=480154" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/JScript/default.aspx">JScript</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/VBScript/default.aspx">VBScript</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Scripting/default.aspx">Scripting</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/COM+Programming/default.aspx">COM Programming</category></item><item><title>Implementing Event Handling, Part Two</title><link>http://blogs.msdn.com/ericlippert/archive/2005/09/21/472465.aspx</link><pubDate>Wed, 21 Sep 2005 21:51:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:472465</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/472465.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=472465</wfw:commentRss><description>&lt;FONT face="lucida sans unicode" color=purple size=2&gt;
&lt;P&gt;It's been an insanely busy month for me, between having multiple out-of-town guests, throwing a party for the people who couldn't make it to the wedding, and oh yeah, getting up to speed on the C# compiler and trying to understand the implications that LINQ features are going to have on the current implementation.&amp;nbsp; Not much time for blogging.&amp;nbsp;Hopefully October will be a little bit more under control.&lt;/P&gt;
&lt;P&gt;Anyway, &lt;a href="http://blogs.msdn.com/ericlippert/archive/2005/09/09/463215.aspx"&gt;I was talking about early-bound event binding&lt;/A&gt;. Basically the idea is that the source and the sink agree upon an interface that the source can call on the sink whenever the source wishes to fire an event. Before we get into that more, I want to talk briefly about early- and late-bound code.&lt;/P&gt;
&lt;P&gt;At an implementation level, what is the difference between early- and late- bound code? In the early-bound world, a particular function on an interface&amp;nbsp;gets called&amp;nbsp;when the caller&amp;nbsp;dereferences the callee's virtual function table and transfers control directly to the function by changing the instruction pointer on the chip.&amp;nbsp;In the late-bound world, the caller calls &lt;FONT color=#000080&gt;IDispatch::Invoke&lt;/FONT&gt; and passes in a magic number that tells the callee what function it should be calling, and the callee is then responsible for dispatching the function appropriately. (Hence the name "&lt;FONT color=#000080&gt;IDispatch&lt;/FONT&gt;".)&lt;/P&gt;
&lt;P&gt;The script engines use &lt;FONT color=#000080&gt;IDispatch&lt;/FONT&gt; all the time to call out to functions on objects. When calling an object late-bound, you don't know until you actually try the call whether or not it is going to succeed, because you do not know the interface the object implements.&amp;nbsp; So you call &lt;FONT color=#000080&gt;GetIdsOfNames&lt;/FONT&gt; to get the magic number associated with a particular function, Invoke on that magic number,&amp;nbsp;and let the callee sort it out. In this situation, the caller (the script engine)&amp;nbsp;knows the name of the function it wants to call, and the callee (the object)&amp;nbsp;can map the name to the appropriate identifier.&lt;/P&gt;
&lt;P&gt;Now consider how this works if &lt;FONT color=#000080&gt;IDispatch&lt;/FONT&gt; is the interface over which the source (the object) is calling back the sink (the script host). This &lt;EM&gt;appears&lt;/EM&gt; to be the same situation, but in fact it is completely different.&amp;nbsp; It appears the same because from the perspective of how COM actually manages all the calls, its exactly the same.&amp;nbsp; &lt;FONT color=#000080&gt;IDispatch&lt;/FONT&gt; is an interface like any other, and the source can call the sink's &lt;FONT color=#000080&gt;IDispatch&lt;/FONT&gt; to its heart's content if that's the interface that they agree to talk over.&lt;/P&gt;
&lt;P&gt;But look at it from the point of view of the sink: the &lt;EM&gt;caller&lt;/EM&gt; knows what the magic number means and the callee does not, but it's the callee who is being asked to do the dispatching!&amp;nbsp;You're sitting there sinking events of who knows what object, and every now and then you get a call on &lt;FONT color=#000080&gt;IDispatch::Invoke&lt;/FONT&gt; with some unknown dispid.&amp;nbsp; What the heck are you supposed to do with that?&amp;nbsp; In the late-bound world, instead of getting a nice direct call on "&lt;FONT color=#000080&gt;Tick()... Tick()...&amp;nbsp; Tick()...&lt;/FONT&gt;"&amp;nbsp; you're getting "12...&amp;nbsp; 12...&amp;nbsp; 12..." and &lt;EM&gt;you have no idea what "12" means.&lt;BR&gt;&lt;/EM&gt;&amp;nbsp;&lt;BR&gt;Let's tie this in to scripting.&amp;nbsp; Suppose you're in Windows Script Host and you do something like:&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&lt;FONT color=#000080&gt;Sub Timer_Tick()&lt;BR&gt;&amp;nbsp; 'whatever&lt;BR&gt;End Sub&lt;BR&gt;Set Timer = CreateObject("mytimer")&lt;BR&gt;WScript.ConnectObject Timer, "Timer_"&lt;BR&gt;Timer.Start 10&lt;BR&gt;WScript.Sleep 1000&lt;/FONT&gt;&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&lt;FONT color=#000080&gt;&lt;FONT color=#800080&gt;There are many&amp;nbsp;&lt;FONT color=#000080&gt;IDispatch&lt;/FONT&gt; objects here and we'll look at three of them.&amp;nbsp;First, there's the source, that is, the timer object.&amp;nbsp;Then there's the sink, owned by the host and created when the source is connected to it.&amp;nbsp;Finally there is the script engine itself, upon which the host can dispatch calls to global functions such as the event handler.&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#000080&gt;ConnectObject&lt;/FONT&gt;&amp;nbsp;is given a source&amp;nbsp;object.&amp;nbsp; It has no idea what early-bound &lt;EM&gt;outgoing&lt;/EM&gt; interface is on that object, and it certainly doesn't have an implementation of such an interface even if there is one, so it is going to have to do a late bound sink.&amp;nbsp; It creates an object to act as the sink, gets an &lt;FONT color=#000080&gt;IDispatch&lt;/FONT&gt;-enabled connection point from the source, and advises it.&lt;BR&gt;&amp;nbsp;&lt;BR&gt;Now the script engine calls &lt;FONT color=#000080&gt;Start&lt;/FONT&gt; (via &lt;FONT color=#000080&gt;IDispatch &lt;/FONT&gt;on the source)&amp;nbsp;and goes to sleep.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;Pretty soon the timer invokes the sink, passing in the dispatch identifier for &lt;FONT color=#000080&gt;Tick&lt;/FONT&gt;.&amp;nbsp;&amp;nbsp;&lt;BR&gt;&lt;BR&gt;The sink&amp;nbsp;needs to know which sub to call in the script engine.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;Fortunately, it has an &lt;FONT color=#000080&gt;IDispatch&lt;/FONT&gt; pointer to the source, and a dispatch identifier.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;Unfortunately, though &lt;FONT color=#000080&gt;IDispatch&lt;/FONT&gt; provides a function which maps from name to id, it provides no function&amp;nbsp;that&amp;nbsp;maps the other way. &lt;/P&gt;
&lt;P&gt;Fortunately, &lt;FONT color=#000080&gt;IDispatch&lt;/FONT&gt; &lt;EM&gt;does&lt;/EM&gt; provide a function that enables the host to obtain a type information structure which contains a list of all the methods and what their dispatch identifiers are. Therefore&amp;nbsp;we can search all the methods in the type info and check to see which has the desired dispatch identifier.&amp;nbsp; That then gives us the method name, so we know which event handler function to dispatch on the script engine. &lt;/P&gt;
&lt;P&gt;Unfortunately there is a major design flaw in &lt;FONT color=#000080&gt;IDispatch&lt;/FONT&gt; -- it gives you the&amp;nbsp;type info for the incoming interface -- the &lt;FONT color=#000080&gt;ITimer&lt;/FONT&gt;.&amp;nbsp; But there is no way to take the &lt;FONT color=#000080&gt;ITypeInfo&lt;/FONT&gt; for &lt;FONT color=#000080&gt;ITimer&lt;/FONT&gt; and say "give me the type info &lt;EM&gt;for the class as a whole&lt;/EM&gt; so that I can obtain the type info for the &lt;EM&gt;outgoing&lt;/EM&gt; interface".&lt;BR&gt;&amp;nbsp;&lt;BR&gt;Fortunately,&amp;nbsp;&lt;FONT color=#000080&gt;IProvideClassInfo&lt;/FONT&gt; was invented.&amp;nbsp; IPCI gives you back the "root" type info for an object, from which you can obtain a type info for the default outgoing interface, from which you can map the dispatch identifier to the name.&lt;/P&gt;
&lt;P&gt;Unfortunately, many objects do not implement &lt;FONT color=#000080&gt;IProvideClassInfo&lt;/FONT&gt;, and therefore cannot&amp;nbsp;have their events hooked up by&amp;nbsp;&lt;FONT color=#000080&gt;ConnectObject&lt;/FONT&gt;.&lt;/P&gt;
&lt;P&gt;(I feel a little bit like the ending of Dr. Strangelove here.&amp;nbsp; Fortunately, they stop General Ripper in time.&amp;nbsp; Unfortunately, the secret code died with him. Fortunately they figure out the code. Unfortunately, the radio is broken.&amp;nbsp; Fortunately, the bomb bay doors are stuck. Unfortunately, they fix them, and the Doomsday Device destroys the world. Bummer.)&lt;/P&gt;
&lt;P&gt;The moral of this story is simple: &lt;STRONG&gt;for late bound events to work, at some point the class of the source must be known&lt;/STRONG&gt;. And therefore:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;"automagic event binding" in IE only works on "named items" present in the script engine.&amp;nbsp; (The script engines require that the host provide a coclass type info for named items, and build the sinks very early on, before other code runs.) 
&lt;LI&gt;&lt;FONT color=#000080&gt;WScript.CreateObject&lt;/FONT&gt; can &lt;EM&gt;always&lt;/EM&gt; hook up events. The class type info is known because &lt;FONT color=#000080&gt;CreateObject&lt;/FONT&gt; had to create an instance of the class. 
&lt;LI&gt;&lt;FONT color=#000080&gt;WScript.ConnectObject&lt;/FONT&gt; can hook up events&amp;nbsp;only if&amp;nbsp;the object implements &lt;FONT color=#000080&gt;IProvideClassInfo&lt;/FONT&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;I hope that clears up any confusion about what &lt;FONT color=#000080&gt;IProvideClassInfo&lt;/FONT&gt; is for!&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;/FONT&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=472465" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/JScript/default.aspx">JScript</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/VBScript/default.aspx">VBScript</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Scripting/default.aspx">Scripting</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/COM+Programming/default.aspx">COM Programming</category></item><item><title>Implementing Event Handling, Part One</title><link>http://blogs.msdn.com/ericlippert/archive/2005/09/09/463215.aspx</link><pubDate>Sat, 10 Sep 2005 01:35:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:463215</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/463215.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=463215</wfw:commentRss><description>&lt;FONT face="lucida sans Unicode" color=purple size=2&gt;
&lt;P&gt;Back in February I posted a bit about &lt;a href="http://blogs.msdn.com/ericlippert/archive/2005/02/15/373330.aspx"&gt;how script hosts such as Windows Script Host dynamically hook up event sources (objects) to event sinks (chunks of script that run when the event fires.)&lt;/A&gt; It has become apparent from some questions I've received recently that it would be helpful to have a more detailed explanation of how event handling works in COM, and how that applies to late-bound scripting languages. &lt;/P&gt;
&lt;P&gt;We'll start in the early-bound world and then move into the scripting world&amp;nbsp;next week.&lt;/P&gt;
&lt;P&gt;Suppose you've got an object &lt;FONT color=#000080&gt;Timer&lt;/FONT&gt; that has methods &lt;FONT color=#000080&gt;Start&lt;/FONT&gt; and &lt;FONT color=#000080&gt;Stop&lt;/FONT&gt;, and event &lt;FONT color=#000080&gt;Tick&lt;/FONT&gt;. The methods are straightforward. We define an interface that has these methods on it:&lt;/P&gt;
&lt;P&gt;&lt;FONT face="lucida console" color=#000080&gt;interface ITimer : public IUnknown&lt;BR&gt;{&lt;BR&gt;public:&lt;BR&gt;&amp;nbsp; virtual void Start(int interval) = NULL;&lt;BR&gt;&amp;nbsp; virtual void Stop() = NULL;&lt;BR&gt;}&lt;BR&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;When users want to call those methods, they just get a pointer to the &lt;FONT color=#000080&gt;IUnknown&lt;/FONT&gt; of the object, &lt;FONT color=#000080&gt;QueryInterface&lt;/FONT&gt; it for &lt;FONT color=#000080&gt;ITimer&lt;/FONT&gt;, and then call the appropriate method on the virtual function table. &lt;/P&gt;
&lt;P&gt;But the user doesn't just want to call the timer. Not much point in that! They want the timer to inform some &lt;EM&gt;other&lt;/EM&gt; piece of code whenever a tick event occurs. Somehow the sink - the listener function&amp;nbsp;- is going to have to be called. This means that the timer code has to be &lt;EM&gt;running&lt;/EM&gt; and it has to &lt;EM&gt;call some arbitrary code&lt;/EM&gt; that it knows nothing about.&lt;/P&gt;
&lt;P&gt;How the timer code manages to run itself is a topic for another day; today we'll just worry about getting the call from the source to the sink. The sink is going to have to somehow register itself with the source, and they'll negotiate what interface the source will call on the sink when the event occurs. In this case the sink wants to know when a tick happens, so the sink should implement something like&lt;/P&gt;
&lt;P&gt;&lt;FONT face="lucida console" color=#000080&gt;interface ITick : public IUnknown&lt;BR&gt;{&lt;BR&gt;public:&lt;BR&gt;&amp;nbsp; virtual void Tick(ITimer * pSource) = NULL;&lt;BR&gt;}&lt;BR&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;OK, so suppose we have a source that implements &lt;FONT color=#000080&gt;ITimer&lt;/FONT&gt; and a sink that implements &lt;FONT color=#000080&gt;ITick&lt;/FONT&gt;. Somehow they have to get hooked up.&amp;nbsp; (Error checking removed.) &lt;/P&gt;
&lt;P&gt;
&lt;P&gt;&lt;FONT face="lucida console" color=#000080&gt;pSource-&amp;gt;QueryInterface(IID_IConnectionPointContainer, &amp;amp;pContainer);&lt;BR&gt;pContainer-&amp;gt;FindConnectionPoint(IID_ITick, &amp;amp;pConnection);&lt;BR&gt;pConnection-&amp;gt;Advise(pSink, &amp;amp;cookie);&lt;BR&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;The sink says to the source "&lt;EM&gt;do you contain connection points that can call me back on &lt;FONT color=#000080&gt;ITick&lt;/FONT&gt;?"&lt;/EM&gt; The source says "&lt;EM&gt;sure, here's an object that you can register yourself with that will call you back&lt;/EM&gt;". The sink then says "&lt;EM&gt;Super, here's a pointer back to me, and please give me a 'cookie' number that I can use to uniquely identify this relationship so that I can shut it down later&lt;/EM&gt;."&lt;/P&gt;
&lt;P&gt;The source now has a pointer to the sink, so when a tick event occurs, the source can call the sink.&lt;/P&gt;
&lt;P&gt;Next time we'll explore what happens in the scripting world where the sink only speaks &lt;FONT color=#000080&gt;IDispatch&lt;/FONT&gt;. &lt;/P&gt;&lt;/FONT&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=463215" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Scripting/default.aspx">Scripting</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/COM+Programming/default.aspx">COM Programming</category></item><item><title>VBScript Default Property Semantics</title><link>http://blogs.msdn.com/ericlippert/archive/2005/08/30/458051.aspx</link><pubDate>Tue, 30 Aug 2005 20:15:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:458051</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>10</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/458051.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=458051</wfw:commentRss><description>&lt;FONT face="lucida sans unicode"&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;Here’s a question I recently got about VBScript, where by "recently" I mean August 28th, 2003.&amp;nbsp;This code works just fine:&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face=Arial size=2&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;
&lt;P&gt;Set myObject = CreateObject("myObject")&lt;BR&gt;myObject.myName = "Eric" &lt;BR&gt;WScript.Echo myObject ' myName is the default property, so prints "Eric"&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face=Arial size=2&gt;&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;But &lt;FONT face="Lucida Console" color=#333399&gt;myObject = "Robert"&lt;/FONT&gt; doesn't set the default property, it sets the variable to the string. &lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;Why does reading work but writing fail? This works in VB6, why not VBScript?&amp;nbsp;&lt;/P&gt;
&lt;P&gt;In a strongly typed language such as VB6 the compiler can look at the compile-time types of the left and right sides of an assignment and determine that the type of the left hand side is an object, the right hand side is a string, and the object has a default property which is a string.&amp;nbsp; The VB6 compiler can then generate the appropriate code to assign the string to the default property.&lt;/P&gt;
&lt;P&gt;But what if you wrote a VB6 program using only variants?&amp;nbsp; When the compiler sees &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;foo = bar&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; typed as variants it cannot tell whether this means "set the default property of &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;foo&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; to &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;bar&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;" or "set &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;foo&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; to &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;bar&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;".&amp;nbsp; The VB compiler chooses the latter every time. VBScript is a weakly typed subset of VB -- in VBScript, everything is a variant.&amp;nbsp; So in VBScript, all assignments are treated as though the value is actually being assigned to the variable, not the default property.&amp;nbsp;Therefore this is by design - this is for compatibility with VB6's behaviour.&amp;nbsp; Had&amp;nbsp;we written the same program in weakly-typed VB6, we'd get the same result.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;I hear you exclaiming "The fact that a difference in available type information leads to a difference in run-time behaviour violates a basic principle of programming language design!&amp;nbsp; Namely, the principle that late-bound calls have exactly the same semantics as early-bound calls!"&amp;nbsp; &lt;/P&gt;
&lt;P&gt;Indeed, as I've mentioned before,&amp;nbsp;VB6 and VBScript violate this principle in several places.&amp;nbsp; Default properties were, in my opinion, a bad idea all around, for this and other reasons.&amp;nbsp; They make the language harder to parse and hence harder to understand.&amp;nbsp; In particular, &lt;EM&gt;parameterless&lt;/EM&gt; default properties make very little sense in VBScript.&amp;nbsp; However, we are stuck with them now.&lt;/P&gt;
&lt;P&gt;However, I should call out that there are some things we can do at runtime.&amp;nbsp;Suppose &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;blah&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; is an object with a property &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;fred&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; that is an object, and &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;fred&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; has a default property which is a string. If you say &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;foo = blah.fred&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; then &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;foo&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; &lt;I&gt;is&lt;/I&gt; assigned the default value of &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;fred&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; even though we lack the compile-time type information.&amp;nbsp; &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;foo&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; isn't set to the object &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;fred. &lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;Of course, in this case we know to fetch the default property at runtime &lt;I&gt;because we know the runtime type&lt;/I&gt; of &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;fred&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; and also know that there is no &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;Set&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; keyword.&amp;nbsp; These two facts are sufficient to cause the runtime engine to always fetch the default property.&lt;/P&gt;
&lt;P&gt;Or suppose you have an object &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;Baz&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; with a property &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;Table&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;, &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;Table&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; has a default &lt;I&gt;parameterized&lt;/I&gt; property &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;Item&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; which returns an object that has a string property &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;Blah&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;: Then this works just fine:&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;
&lt;P&gt;x = Baz.Table(1).Blah&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;But why? In this case we do &lt;I&gt;not&lt;/I&gt; have enough compile-time information to determine that we really should call &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;Baz.Table.Item(1).Blah&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;.&amp;nbsp; The script engine has every reason to believe that &lt;FONT color=#000080&gt;Table&lt;/FONT&gt; is a function or parameterized property of &lt;FONT color=#000080&gt;Baz&lt;/FONT&gt;.&amp;nbsp;This problem is solved by pushing it off to the implementation!&amp;nbsp;The rule for implementers of &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;IDispatch::Invoke&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; is if all of the following are true:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;the caller invokes a property 
&lt;LI&gt;the caller passes an argument list 
&lt;LI&gt;the property does not actually take an argument list 
&lt;LI&gt;that property returns an object 
&lt;LI&gt;that object has a default property 
&lt;LI&gt;that default property takes an argument list&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;then invoke the default property with the argument list.&amp;nbsp;Strange but true.&lt;/P&gt;
&lt;P&gt;Perhaps unsurprisingly, not very many people know about that rule!&amp;nbsp; This is yet another reason to never, ever write your own implementation of &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;IDispatch::Invoke&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;.&amp;nbsp; It also leads to some mind-numbingly complex code in the VBScript IntelliSense engine that Visual Studio uses.&amp;nbsp; Making default property IntelliSense work with such a dynamically typed language was a piece of work, lemme tell ya.&amp;nbsp;As I mentioned earlier, there are &lt;a href="http://blogs.msdn.com/ericlippert/archive/2004/05/04/125893.aspx"&gt;in fact some odd corner cases that are slightly different between VB6 and VBScript IntelliSense&lt;/A&gt;.&amp;nbsp; I also talked a bit about &lt;a href="http://blogs.msdn.com/ericlippert/archive/2004/05/04/125837.aspx"&gt;left-hand-side default property semantics &lt;/A&gt;earlier. &lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=458051" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/VBScript/default.aspx">VBScript</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Scripting/default.aspx">Scripting</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/COM+Programming/default.aspx">COM Programming</category></item><item><title>Caching Dispatch Identifiers Is A Bad Idea</title><link>http://blogs.msdn.com/ericlippert/archive/2005/08/24/caching-dispatch-identifiers-is-a-bad-idea.aspx</link><pubDate>Thu, 25 Aug 2005 01:22:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:455879</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/455879.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=455879</wfw:commentRss><description>&lt;FONT face="lucida sans unicode"&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;About two years ago I wrote a bit about &lt;a href="http://blogs.msdn.com/ericlippert/archive/2003/09/16/53027.aspx"&gt;when it was legal to cache a dispatch identifier so that you didn’t have to look it up a second time&lt;/A&gt;. &lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;I was reminded of this today because the scripting sustaining engineering team was working on a bug that involved a customer incorrectly caching a dispatch identifier. I’d like to take this opportunity to expand a bit on the rules I mentioned two years ago.&lt;/P&gt;
&lt;P&gt;Suppose you've got two script engines that are totally identical – same script code added in the same order, similarly the same named items – running on two different threads. I’m sure you can see why that would be useful; think of an ASP server serving up two pages on two threads, for example. The customer needed to call a particular script function by invoking each&amp;nbsp;script engine’s global dispatch. They were getting the dispatch identifier once, caching&amp;nbsp;it &lt;B&gt;and using it for calling&amp;nbsp;both engines&lt;/B&gt;. Depending on what build of the script engine they were using, that either worked fine or died horribly.&lt;/P&gt;
&lt;P&gt;Unfortunately it turns out that dying horribly is both legal and expected. &lt;B&gt;A given dispatch identifier can only be cached in the context of a particular dispatch object&lt;/B&gt;. Two identical dispatch objects with identical functions are allowed to give different dispatch identifiers for a given method!&lt;/P&gt;
&lt;P&gt;The script engines have changed their algorithm for how dispatch identifiers are generated several times over the years. In some builds of the script engines, dispatch identifiers are generated sequentially, so that the first function added is one, the second is two, and so on. In those builds, two identical engines that have had the same functions added in the same order will have identical dispatch identifiers for a given name. In other builds of the script engines, the dispatch identifiers are globally unique, so that two engines with two functions will always have different dispatch identifiers even if everything is identical otherwise. &lt;/P&gt;
&lt;P&gt;Unfortunately the customer built and tested their code against the former kind of engine and then upgraded to a more recent version using the latter algorithm, which broke them. I regret the problem -- I'm the guy who screwed around with the algorithm -- but still, you've got to follow the rules. Calling &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;GetIdsOfNames&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; is almost always very fast compared to &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;Invoke&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;, so &lt;STRONG&gt;please don’t cache dispatch identifiers for performance reasons&lt;/STRONG&gt;. We don’t do so in the script engines, as I mentioned two years ago, because the trouble you get into when you do it wrong is not worth the time you save.&lt;/P&gt;
&lt;P&gt;While I’m on the subject, a quick word of advice for implementers too: If you are implementing &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;IDispatch&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; on an expando object it is very tempting to say "I’ll use a pointer to my function object as the dispatch identifier for that function". Just cast the pointer to int and you’ve guaranteed uniqueness and have an easy way to map back to the function when invoked, right? &lt;B&gt;Please do not do this&lt;/B&gt;. First off, it’s not portable to 64 bit machines. Second, it’s dangerous – a hostile or broken caller can make you invoke pointers to garbage. Third, on processes with 3GB of user-accessible memory, pointers can be cast to negative integers and negative integers are illegal dispatch ids. Come up with some safer way to guarantee uniqueness of your dispatch ids, such as maintaining a global counter and lookup table.&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=455879" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/COM+Programming/default.aspx">COM Programming</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Performance/default.aspx">Performance</category></item><item><title>How Do Script Engines Implement Object Identity?</title><link>http://blogs.msdn.com/ericlippert/archive/2005/04/26/412199.aspx</link><pubDate>Tue, 26 Apr 2005 21:49:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:412199</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>7</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/412199.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=412199</wfw:commentRss><description>&lt;FONT face="lucida sans unicode"&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;I've talked a few times in this blog about the semantics of the equality operators in various languages. (Such as &lt;/FONT&gt;&lt;a href="http://blogs.msdn.com/ericlippert/archive/2004/07/26/197302.aspx"&gt;&lt;U&gt;&lt;FONT color=#0000ff size=2&gt;here&lt;/U&gt;&lt;/FONT&gt;&lt;/A&gt;&lt;FONT color=#800080 size=2&gt;, and &lt;/FONT&gt;&lt;a href="http://blogs.msdn.com/ericlippert/archive/2004/07/30/202432.aspx"&gt;&lt;U&gt;&lt;FONT color=#0000ff size=2&gt;here&lt;/U&gt;&lt;/FONT&gt;&lt;/A&gt;&lt;FONT color=#800080 size=2&gt;.) Recently a reader asked me how JScript &lt;I&gt;implements&lt;/I&gt; object identity. That is, given two objects, how do we know if they are "the same object" or not? &lt;/P&gt;
&lt;P&gt;For the remainder of this discussion I'm going to assume that we've got two non-null objects that we're comparing for identity. The details of how objects are compared to strings, numbers, etc, will have to wait for another blog entry.&lt;/P&gt;
&lt;P&gt;Note also that in VBScript, the comparison operator for objects is &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;Is&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;, not &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;=.&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; Also, &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;==&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; and &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;===&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; in JScript behave identically if both arguments are objects; essentially the implementation of &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;Is&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;, &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;==&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; and &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;===&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; are all the same as far as object comparison goes.&lt;/P&gt;
&lt;P&gt;Behind the scenes, everything in a VBScript/JScript program is represented as a variant. Most of the time, variants containing objects will have their variant type field set to VT_DISPATCH, and their pdispVal field set with a pointer to the object. (Occasionally we'll have a VT_UNKNOWN with a punkVal field instead, but lets ignore that corner case for now.) Suppose we want to compare two such objects for equality. We could pass the pdispVal of each to a helper function and compare the pointers.&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;
&lt;P&gt;bool AreObjectsEqual(IDispatch * pdisp1, IDispatch * pdisp2)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp; if (pdisp1 == pdisp2)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return true;&lt;BR&gt;&amp;nbsp;&amp;nbsp;return false;&lt;BR&gt;}&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;And we're done. Wow, that was easy.&lt;/P&gt;
&lt;P&gt;Except that it's wrong. In VBScript, those objects could be two different dispatch pointers to the same object because &lt;/FONT&gt;&lt;a href="http://blogs.msdn.com/ericlippert/archive/2003/10/10/53188.aspx"&gt;&lt;U&gt;&lt;FONT color=#0000ff size=2&gt;VBScript supports non-default dispatches&lt;/U&gt;&lt;/FONT&gt;&lt;/A&gt;&lt;FONT color=#800080 size=2&gt;. JScript does not support non-default dispatches, but in JScript there are also situations in which you can have two different dispatch pointers to the same object; we'll come to that later.&lt;/P&gt;
&lt;P&gt;If its not clear why the two pointers to the same object could be numerically different, read &lt;/FONT&gt;&lt;a href="http://blogs.msdn.com/oldnewthing/archive/2004/02/05/68017.aspx"&gt;&lt;U&gt;&lt;FONT color=#0000ff size=2&gt;Raymond's article on how COM objects are laid out in memory&lt;/U&gt;&lt;/FONT&gt;&lt;/A&gt;&lt;FONT color=#800080 size=2&gt;, and you'll see why. There can be many dispatch vtables.&lt;/P&gt;
&lt;P&gt;How can we ever determine when two COM objects are the same? We have to rely upon one of the most important rules of COM: if an object multiply inherits &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;IUnknown&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; then calling &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;QueryInterface&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; for &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;IUnknown&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; on &lt;I&gt;any&lt;/I&gt; of those implementations must &lt;I&gt;always&lt;/I&gt; give back the same pointer. As you can see in Raymond's example of multiple inheritance, there are two &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;IUnknown&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; vtables. It is illegal for each of them to return a pointer to itself when QI'd for &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;IUnknown&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;; the implementation must consistently pick one of them every time.&lt;/P&gt;
&lt;P&gt;So now it's pretty clear what we must do:&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;
&lt;P&gt;bool AreObjectsEqual(IDispatch * pdisp1, IDispatch * pdisp2)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp; IUnknown * punk1 = NULL;&lt;BR&gt;&amp;nbsp; IUnknown * punk2 = NULL;&lt;BR&gt;&amp;nbsp; if (pdisp1 == pdisp2)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return true;&lt;BR&gt;&amp;nbsp; if (pdisp1 == NULL || pdisp2 == NULL)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return false;&lt;BR&gt;&amp;nbsp; pdisp1-&amp;gt;QueryInterface(IID_IUnknown, (void**)&amp;amp;punk1);&lt;BR&gt;&amp;nbsp; pdisp2-&amp;gt;QueryInterface(IID_IUnknown, (void**)&amp;amp;punk2);&lt;BR&gt;&amp;nbsp; // This should never fail, but better safe than sorry.&lt;BR&gt;&amp;nbsp; if (punk1 != NULL)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; punk1-&amp;gt;Release();&lt;BR&gt;&amp;nbsp; if (punk2 != NULL)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; punk2-&amp;gt;Release();&lt;BR&gt;&amp;nbsp; // We're not dereferencing the pointers, so it is OK to use the&lt;BR&gt;&amp;nbsp;&amp;nbsp;// locals even after their release.&lt;BR&gt;&amp;nbsp; if (punk1 == punk2)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return true;&lt;BR&gt;&amp;nbsp; return false;&lt;BR&gt;}&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;Unfortunately, that's not the whole story either. &lt;/P&gt;
&lt;P&gt;For security reasons, Internet Explorer sometimes creates proxy objects -- little objects that detect if they are being used safely, and if they are, then they forward the call to the real implementation, on a separate object. You can run into situations in IE where you have two proxy objects to the same "real" object -- as far as COM is concerned, all three are different objects, but as far as IE is concerned, that's an implementation detail of the security system which we would like to hide from the script users.&lt;/P&gt;
&lt;P&gt;To solve this problem, IE implements a special interface that knows when two IUnknown objects are both proxies for the same object. The script engines actually do something like this:&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;
&lt;P&gt;bool AreObjectsEqual(IDispatch * pdisp1, IDispatch * pdisp2) {&lt;BR&gt;&amp;nbsp; IUnknown * punk1 = NULL;&lt;BR&gt;&amp;nbsp; IUnknown * punk2 = NULL;&lt;BR&gt;&amp;nbsp; IObjectIdentity * pObjectIdentity;&lt;BR&gt;&amp;nbsp; bool fRet = false;&lt;BR&gt;&amp;nbsp; HRESULT hr;&lt;BR&gt;&amp;nbsp; if (pdisp1 == pdisp2)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; fRet = true;&lt;BR&gt;&amp;nbsp; else if (pdisp1 != NULL &amp;amp;&amp;amp; pdisp2 != NULL) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // This must always succeed.&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; pdisp1-&amp;gt;QueryInterface(IID_IUnknown, (void**)&amp;amp;punk1);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; pdisp2-&amp;gt;QueryInterface(IID_IUnknown, (void**)&amp;amp;punk2);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (punk1 == punk2)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; fRet = true;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; else if (punk1 != NULL &amp;amp;&amp;amp; punk2 != NULL) {&amp;nbsp;// This should never be false.&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; hr = punk1-&amp;gt;QueryInterface(IID_IObjectIdentity, (void **)&amp;amp;pObjectIdentity);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (SUCCEEDED(hr)) &amp;amp;&amp;amp; pObjectIdentity != NULL) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; hr = pObjectIdentity-&amp;gt;IsEqualObject(punk2);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (hr == S_OK)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; fRet = true;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp; }&lt;BR&gt;&amp;nbsp; if (pObjectIdentity != NULL)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; pObjectIdentity-&amp;gt;Release();&lt;BR&gt;&amp;nbsp; if (punk1 != NULL)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; punk1-&amp;gt;Release();&lt;BR&gt;&amp;nbsp; if (punk2 != NULL)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; punk2-&amp;gt;Release();&lt;BR&gt;&amp;nbsp; return fRet;&lt;BR&gt;}&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;Which is a heck of a lot of code just to determine if two pointers are equal, but that's the tax you pay for object-oriented programming. Of course, you don't need to do any of this rigamarole with &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;IObjectIdentity&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; unless you're writing code that messes around with IE objects.&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=412199" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/JScript/default.aspx">JScript</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/VBScript/default.aspx">VBScript</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Scripting/default.aspx">Scripting</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/COM+Programming/default.aspx">COM Programming</category></item><item><title>Why does WScript.ConnectObject not always work?</title><link>http://blogs.msdn.com/ericlippert/archive/2005/02/15/373330.aspx</link><pubDate>Tue, 15 Feb 2005 19:54:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:373330</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>6</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/373330.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=373330</wfw:commentRss><description>&lt;font face="Lucida Sans Unicode"&gt;&lt;font color="#800080" size="2"&gt; &lt;p&gt;I've had a tiny handful of entries in my &lt;/font&gt;&lt;A href="http://blogs.msdn.com/ericlippert/archive/2005/02/10/370884.aspx"&gt;&lt;u&gt;&lt;font color="#0000ff" size="2"&gt;VBScript quiz&lt;/u&gt;&lt;/font&gt;&lt;/a&gt;&lt;font color="#800080" size="2"&gt;. I know from my logs that 2600+ people have read it. Come on people, there are fabulous prizes at stake here!&amp;nbsp; Go for it!&lt;/p&gt; &lt;p&gt;I'm going to keep the contest open until Friday morning, at which point I'll start posting answers and analysis.&lt;/p&gt; &lt;p&gt;&lt;font color="#000000"&gt;****************************************************&lt;/font&gt;&lt;/p&gt; &lt;p&gt;Earlier today someone asked me why it is that sometimes &lt;/font&gt;&lt;font face="Lucida Console" color="#333399" size="2"&gt;WScript.ConnectObject&lt;/font&gt;&lt;font color="#800080" size="2"&gt; does not connect an object to an event sink even if the object sources events. That reminded me that back in &lt;/font&gt;&lt;A href="http://blogs.msdn.com/ericlippert/archive/2004/06/01/145686.aspx"&gt;&lt;u&gt;&lt;font color="#0000ff" size="2"&gt;June&lt;/u&gt;&lt;/font&gt;&lt;/a&gt;&lt;font color="#800080" size="2"&gt; I said that I'd explain this at some point, and I never did.&lt;/p&gt;&lt;/font&gt;&lt;font face="Lucida Console" color="#333399" size="2"&gt; &lt;p&gt;WScript.ConnectObject&lt;/font&gt;&lt;font color="#800080" size="2"&gt; only works if the object implements &lt;/font&gt;&lt;font face="Lucida Console" color="#333399" size="2"&gt;IProvideClassInfo&lt;/font&gt;&lt;font color="#800080" size="2"&gt; or &lt;/font&gt;&lt;font face="Lucida Console" color="#333399" size="2"&gt;IProvideMultipleClassInfo&lt;/font&gt;&lt;font color="#800080" size="2"&gt;. Not all objects do.&lt;/p&gt;&lt;/font&gt;&lt;font face="Times New Roman"&gt;&lt;/font&gt;&lt;font color="#800080" size="2"&gt; &lt;p&gt;Why?&lt;/p&gt; &lt;p&gt;An object can implement multiple interfaces both incoming and outgoing. Incoming interfaces are the interfaces &lt;i&gt;you call&lt;/i&gt; an object on. Outgoing interfaces are interfaces that &lt;i&gt;they call you&lt;/i&gt; on. That's how events work: you tell the object that you want a particular method to be called on a particular outgoing interface when a particular event occurs. &lt;/p&gt; &lt;p&gt;Each interface supported by an object, whether incoming or outgoing, can have its own interface typeinfo describing it.&amp;nbsp; For a given object all these interfaces are "summarized" by one "parent" type info called the "coclass type info".&amp;nbsp; Once you have the coclass type info, you can figure out everything about the object's incoming and outgoing interfaces.&lt;/p&gt; &lt;p&gt;Clearly, in order to build an event sink for an object, you need to know what events the event source is going to source! You need the outgoing interface typeinfo, or, equivalently, the coclass typeinfo.&lt;/p&gt; &lt;p&gt;The flaw in the design of the automation interfaces is this: given an &lt;/font&gt;&lt;font face="Lucida Console" color="#333399" size="2"&gt;IDispatch&lt;/font&gt;&lt;font color="#800080" size="2"&gt; object, there is no way to discover what its coclass typeinfo is!&amp;nbsp; You can get a type info for the &lt;b&gt;dispatch interface&lt;/b&gt; -- that is, the &lt;b&gt;incoming call interface&lt;/b&gt; -- by calling &lt;/font&gt;&lt;font face="Lucida Console" color="#333399" size="2"&gt;GetTypeInfo&lt;/font&gt;&lt;font color="#800080" size="2"&gt;. But there is no way to get the coclass type info, and therefore no way to determine what the outgoing interfaces are on the object, and therefore no way to bind its events.&lt;/p&gt; &lt;p&gt;When that omission was realized, &lt;/font&gt;&lt;font face="Lucida Console" color="#333399" size="2"&gt;IProvideClassInfo&lt;/font&gt;&lt;font color="#800080" size="2"&gt; was invented.&amp;nbsp; (And for aggregate objects, which may have aggregated multiple coclasses, &lt;/font&gt;&lt;font face="Lucida Console" color="#333399" size="2"&gt;IProvideMultipleClassInfo&lt;/font&gt;&lt;font color="#800080" size="2"&gt; was invented.) &lt;/font&gt;&lt;font face="Lucida Console" color="#333399" size="2"&gt;IProvideClassInfo&lt;/font&gt;&lt;font color="#800080" size="2"&gt;&amp;nbsp;returns the coclass type info. That's why &lt;/font&gt;&lt;font face="Lucida Console" color="#333399" size="2"&gt;WScript.ConnectObject&lt;/font&gt;&lt;font color="#800080" size="2"&gt; requires &lt;/font&gt;&lt;font face="Lucida Console" color="#333399" size="2"&gt;IProvideClassInfo&lt;/font&gt;&lt;font color="#800080" size="2"&gt; -- it just has the object and knows nothing about its class.&lt;/p&gt; &lt;p&gt;You may then wonder how it is that &lt;/font&gt;&lt;font face="Lucida Console" color="#333399" size="2"&gt;WScript.CreateObject&lt;/font&gt;&lt;font color="#800080" size="2"&gt; does event binding on objects that do not implement &lt;/font&gt;&lt;font face="Lucida Console" color="#333399" size="2"&gt;IProvideClassInfo&lt;/font&gt;&lt;font color="#800080" size="2"&gt;.&amp;nbsp; That's easy -- &lt;/font&gt;&lt;font face="Lucida Console" color="#333399" size="2"&gt;WScript.CreateObject&lt;/font&gt;&lt;font color="#800080" size="2"&gt; &lt;em&gt;is&lt;/em&gt; &lt;em&gt;given enough information to find the coclass type info&lt;/em&gt;.&amp;nbsp; &lt;/font&gt;&lt;font face="Lucida Console" color="#333399" size="2"&gt;WScript.CreateInstance&lt;/font&gt;&lt;font color="#800080" size="2"&gt; is passed the progid.&amp;nbsp; It uses that to look up the class id in the registry.&amp;nbsp; It obtains the incoming interface typeinfo from the newly-created dispatch object, obtains the typelibrary from the typeinfo, and searchs the typelibrary for a coclass type info which matches the class id.&lt;/p&gt; &lt;p&gt;This also explains how it is that Visual Basic can do event binding on objects which do not implement &lt;/font&gt;&lt;font face="Lucida Console" color="#333399" size="2"&gt;IProvideClassInfo&lt;/font&gt;&lt;font color="#800080" size="2"&gt;.&amp;nbsp; VB has compile-time information about the progid of the object and can look up the outgoing interface in the same way.&lt;/font&gt;&lt;/p&gt; &lt;p&gt;&lt;font color="#800080" size="2"&gt;We&amp;nbsp;considered creating another version of &lt;font color="#000080"&gt;WScript.ConnectObject&lt;/font&gt;&lt;font color="#800080" size="2"&gt; &lt;/font&gt;which took a classid or progid, but&amp;nbsp;we decided that it wouldn't be useful in very many situations, and would be confusing and hard to document well.&lt;/font&gt;&lt;/p&gt; &lt;p&gt;&lt;font color="#800080" size="2"&gt;&lt;/font&gt;&lt;/font&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=373330" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Scripting/default.aspx">Scripting</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/COM+Programming/default.aspx">COM Programming</category></item><item><title>VBScript Terminators, Part Two</title><link>http://blogs.msdn.com/ericlippert/archive/2004/12/29/344074.aspx</link><pubDate>Thu, 30 Dec 2004 03:47:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:344074</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>9</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/344074.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=344074</wfw:commentRss><description>&lt;font face="lucida sans unicode" color="purple" size="2"&gt; &lt;p&gt;You guys came up with good answers to three of my four questions, which is about what I expected; question 2 was pretty hard.&lt;/p&gt; &lt;p&gt;To sum up:&lt;/p&gt; &lt;p&gt;&lt;font color="#000080"&gt;QUESTION #1: Why does the termination logic go terminate, terminate, terminate, clear, clear, clear, instead of terminate and clear, terminate and clear, terminate and clear?&lt;/font&gt;&lt;/p&gt; &lt;p&gt;Because if the &lt;em&gt;second&lt;/em&gt; object to be terminated has a terminator that&amp;nbsp;accesses a property of the &lt;em&gt;first&lt;/em&gt; object to be terminated and cleared, it will fail, which seems bad.&amp;nbsp;We want to run all the terminators while the objects are still in good shape, and then blow them all away.&lt;/p&gt; &lt;p&gt;&lt;font color="#000080"&gt;QUESTION #3: Why do we want to ensure that terminators don’t run twice?&lt;/font&gt;&lt;/p&gt; &lt;p&gt;Imagine a terminator which writes a "logging complete" message to a log file; you don't want it to run twice.&lt;/p&gt; &lt;p&gt;&lt;font color="#000080"&gt;QUESTION #4: Why do we run the garbage collector at the end of every statement, instead of only at the end of every procedure/global block?&lt;/font&gt;&lt;/p&gt; &lt;p&gt;Because, though local variables are not going to go out of scope, temporary anonymous slots are.&amp;nbsp;Consider&lt;/p&gt; &lt;p&gt;&lt;font color="#000080"&gt;x = MyFunc("a" + s, new Foo)&lt;/font&gt;&lt;/p&gt; &lt;p&gt;That's going to allocate one temporary slot for the string and one for the object. The temporary string can be cleared whenever, but the temporary object should be released ASAP so that it's terminator runs ASAP. We therefore clean up all temporaries after every statement.&lt;/p&gt; &lt;p&gt;That leaves&lt;/p&gt; &lt;p&gt;&lt;font color="#000080"&gt;QUESTION #2: In what scenario can a bad implementation crash the process and/or terminate the object twice?&lt;/font&gt;&lt;/p&gt; &lt;p&gt;When I first wrote the termination logic, the release code looked like this:&lt;/p&gt; &lt;p&gt;&lt;font face="lucida console" color="#000080"&gt;ULONG VBSClassInstance::Release(){&lt;br /&gt;&amp;nbsp; --this-&amp;gt;m_cRef;&lt;br /&gt;&amp;nbsp; if (this-&amp;gt;m_cRef == 0)&lt;br /&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; this-&amp;gt;RunTerminator();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; delete this;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return 0;&lt;br /&gt;&amp;nbsp; }&lt;br /&gt;&amp;nbsp; return this-&amp;gt;m_cRef;&lt;br /&gt;}&lt;/font&gt;&lt;/p&gt; &lt;p&gt;Looks like a perfectly straightforward implementation, right? But what if some bozo does this?&lt;/p&gt; &lt;p&gt;&lt;font face="lucida console" color="#000080"&gt;Dim Global&lt;br /&gt;Class Foo&lt;br /&gt;&amp;nbsp; Private Sub Class_Terminate()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Set Global = Me&lt;br /&gt;&amp;nbsp; End Sub&lt;br /&gt;End Class&lt;br /&gt;Sub Blah&lt;br /&gt;&amp;nbsp; Dim Local&lt;br /&gt;&amp;nbsp; Set Local = New Foo&lt;br /&gt;End Sub&lt;br /&gt;Blah&lt;br /&gt;Set Global = Nothing&lt;/font&gt;&lt;br /&gt;&lt;/p&gt; &lt;p&gt;When &lt;font face="lucida console" color="#000080"&gt;Local&lt;/font&gt; goes out of scope, the terminator runs and sets the &lt;font face="lucida console" color="#000080"&gt;Global&lt;/font&gt; variable to the object which has just been terminated! Therefore it must live. We must write the &lt;font face="lucida console" color="#000080"&gt;VBSClassInstance::RunTerminator&lt;/font&gt; method to ensure that the terminator doesn't run twice, but that's the least of our problems. Look at the implementation of &lt;font color="#000080"&gt;Release&lt;/font&gt; above carefully.&amp;nbsp;When the terminator runs, the ref count will go back up to one, but we still delete the object! The script engine now has a global variable containing a pointer to deleted memory; this will crash the process, corrupt the heap, who knows what?&lt;/p&gt; &lt;p&gt;OK, so what if we go&lt;/p&gt; &lt;p&gt;&lt;font face="lucida console" color="#000080"&gt;ULONG VBSClassInstance::Release(){&lt;br /&gt;&amp;nbsp; --this-&amp;gt;m_cRef;&lt;br /&gt;&amp;nbsp; if (this-&amp;gt;m_cRef == 0)&lt;br /&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; this-&amp;gt;RunTerminator();&lt;br /&gt;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;if (this-&amp;gt;m_cRef == 0)&lt;br /&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; delete this;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return 0;&lt;br /&gt;&amp;nbsp; }&lt;br /&gt;&amp;nbsp; return this-&amp;gt;m_cRef;&lt;br /&gt;}&lt;/font&gt;&lt;/p&gt; &lt;p&gt;Is that better?&amp;nbsp;Well, sure, it's &lt;em&gt;better&lt;/em&gt;, but it's still &lt;em&gt;wrong&lt;/em&gt;. Forget globals; consider this:&lt;/p&gt; &lt;p&gt;&lt;font face="lucida console" color="#000080"&gt;&amp;nbsp; Private Sub Class_Terminate()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Dim&amp;nbsp;TermLocal&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Set&amp;nbsp;TermLocal = Me&lt;br /&gt;&amp;nbsp; End Sub&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;Now what happens?&amp;nbsp; The "final" release when &lt;font face="lucida console" color="#000080"&gt;Local&lt;/font&gt; goes out of scope sets the ref count to zero and calls the terminator. The terminator increases the ref count to one by assigning it.&amp;nbsp;Then when &lt;font face="lucida console" color="#000080"&gt;TermLocal&lt;/font&gt; goes out of scope, it calls &lt;font face="lucida console" color="#000080"&gt;Release&lt;/font&gt; on the object. We've now got a re-entrant &lt;font face="lucida console" color="#000080"&gt;Release&lt;/font&gt; method! The "inner" &lt;font face="lucida console" color="#000080"&gt;Release&lt;/font&gt; detects that the ref count has gone to zero and deletes the object. Then the "outer"&amp;nbsp; &lt;font face="lucida console" color="#000080"&gt;Release&lt;/font&gt;&amp;nbsp; reads from the now-invalid "this" pointer. Assuming that doesn't crash, it then probably corrupts the heap by releasing the object a second time.&lt;/p&gt; &lt;p&gt;The correct logic looks something like this:&lt;/p&gt; &lt;p&gt;&lt;font face="lucida console" color="#000080"&gt;ULONG VBSClassInstance::Release(){&lt;br /&gt;&amp;nbsp; --this-&amp;gt;m_cRef;&lt;br /&gt;&amp;nbsp; if (this-&amp;gt;m_cRef == 0)&lt;br /&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;++this-&amp;gt;m_cRef;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // protects against re-entrant&amp;nbsp;final release&lt;/font&gt;&lt;font face="lucida console" color="#000080"&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; this-&amp;gt;RunTerminator();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; --this-&amp;gt;m_cRef;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (this-&amp;gt;m_cRef == 0)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; delete this;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return 0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;/font&gt;&lt;font face="lucida console" color="#000080"&gt;&lt;br /&gt;&amp;nbsp; return this-&amp;gt;m_cRef;&lt;br /&gt;}&lt;/font&gt;&lt;/p&gt; &lt;p&gt;Writing correct shutdown logic is surprisingly tricky!&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;/font&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=344074" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/VBScript/default.aspx">VBScript</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Scripting/default.aspx">Scripting</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/COM+Programming/default.aspx">COM Programming</category></item><item><title>T4: VBScript and the Terminator</title><link>http://blogs.msdn.com/ericlippert/archive/2004/12/22/330276.aspx</link><pubDate>Wed, 22 Dec 2004 23:42:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:330276</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>11</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/330276.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=330276</wfw:commentRss><description>&lt;font face="Lucida Sans Unicode" color="purple" size="2"&gt; &lt;p&gt;I had some free time on the flight to Canada and my laptop with me, so maybe I will do a little blogging on my vacation after all. &lt;/p&gt; &lt;p&gt;A week ago or so a reader asked me to talk a bit about how class termination works in VBScript.&amp;nbsp; Let’s start by looking at a simple case:&lt;/p&gt; &lt;p&gt;&lt;font color="#000080"&gt;Class Foo&lt;br /&gt;&amp;nbsp; &amp;nbsp;Public Name&lt;br /&gt;&amp;nbsp; &amp;nbsp;Public Other&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp; &amp;nbsp;Private Sub Class_Terminate&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; MsgBox Name &amp;amp; ": Goodbye, world!"&lt;br /&gt;&amp;nbsp; &amp;nbsp;End Sub&lt;br /&gt;End Class&lt;/font&gt;&lt;/p&gt; &lt;p&gt;As you can see, the class has an “event handler” which is executed when an instance is just about to be released.&amp;nbsp; (I put scare quotes on there because, though it has the &lt;em&gt;form&lt;/em&gt; of an event handler, in fact the underlying mechanism that runs the terminator is completely distinct from the other event handling code in VBScript.)&lt;/p&gt; &lt;p&gt;&lt;A href="http://blogs.msdn.com/ericlippert/archive/2003/09/17/53038.aspx"&gt;JScript, as you may know, has a nondeterministic mark-and-sweep garbage collector&lt;/a&gt;.&amp;nbsp; It’s “nondeterministic” because it runs pretty much when it feels like it. There is a scheduling algorithm, but from the perspective of the program, it’s pretty much random; it’s quite tricky to predict when it’s going to run.&amp;nbsp; And it’s “mark and sweep” because every collection, it runs through every script-allocated memory block, checks if it is still accessible by the script, and if it isn’t, the memory is freed.&amp;nbsp; This makes it mostly immune to the “circular reference” problem, where two or more otherwise dead objects reference each other. &lt;/p&gt; &lt;p&gt;VBScript’s garbage collector is completely different.&amp;nbsp; It runs at the end of every statement and procedure, and does not do a search of all memory.&amp;nbsp; Rather, it keeps track of everything allocated in the statement or procedure; if anything has gone out of scope, it frees it immediately.&amp;nbsp; We can see this in action by watching terminators run.&lt;/p&gt; &lt;p&gt;Let’s consider a simple example.&lt;/p&gt; &lt;p&gt;&lt;font color="#000080"&gt;Sub Bar&lt;br /&gt;&amp;nbsp;&amp;nbsp; Dim X&lt;br /&gt;&amp;nbsp;&amp;nbsp; Set X = New Foo&lt;br /&gt;&amp;nbsp;&amp;nbsp; X.Name = "X"&lt;br /&gt;End Sub&lt;br /&gt;MsgBox "Starting Bar"&lt;br /&gt;Bar&lt;br /&gt;MsgBox "Done Bar"&lt;br /&gt;&lt;/font&gt;&amp;nbsp;&lt;br /&gt;outputs, as you’d expect:&lt;/p&gt; &lt;p&gt;&lt;font color="#000080"&gt;Starting Bar&lt;br /&gt;X: Goodbye, world!&lt;br /&gt;Done Bar&lt;/font&gt;&lt;/p&gt; &lt;p&gt;As soon as &lt;font color="#000080"&gt;Bar&lt;/font&gt;’s &lt;font color="#000080"&gt;End Sub&lt;/font&gt; runs, &lt;font color="#000080"&gt;X&lt;/font&gt; goes out of scope.&amp;nbsp; Since that’s its last reference, the terminator runs.&lt;/p&gt; &lt;p&gt;It’s that “last reference” part that’s the rub.&amp;nbsp; Objects are reference counted in COM – every object keeps track of how many other objects are keeping it alive, and when that drops to zero, the object deletes itself.&lt;/p&gt; &lt;p&gt;The trouble is, what if two objects are each keeping a ref on each other, but are otherwise dead?&amp;nbsp; The “circular reference” problem wasn’t so much a problem before we added classes to VBScript. After all, without the ability to define new objects in script, the only objects you really need to worry about are external ActiveX objects – and not even JScript can break circular references involving ActiveX objects, because the ActiveX objects know nothing about JScript’s garbage collector, and vice versa.&lt;/p&gt; &lt;p&gt;But with objects in VBScript, suddenly it becomes quite bad.&amp;nbsp; You can very easily write scripts that consume memory in the form of objects that reference each other circularly, and they won’t go away when they go out of scope:&lt;/p&gt; &lt;p&gt;&lt;font color="#000080"&gt;Sub XYZ&lt;br /&gt;&amp;nbsp; &amp;nbsp;Dim Alpha, Bravo&lt;br /&gt;&amp;nbsp;&amp;nbsp; Set Alpha = New Foo&lt;br /&gt;&amp;nbsp; &amp;nbsp;Alpha.Name = "Alpha"&lt;br /&gt;&amp;nbsp; &amp;nbsp;Set Bravo = New Foo&lt;br /&gt;&amp;nbsp; &amp;nbsp;Bravo.Name = "Bravo"&lt;br /&gt;&amp;nbsp; &amp;nbsp;Set Alpha.Other = Bravo&lt;br /&gt;&amp;nbsp; &amp;nbsp;Set Bravo.Other = Alpha&lt;br /&gt;End Sub&lt;/font&gt;&lt;/p&gt; &lt;p&gt;&lt;font color="#000080"&gt;MsgBox "Starting XYZ"&lt;br /&gt;XYZ&lt;br /&gt;MsgBox "Done XYZ"&lt;/font&gt;&lt;/p&gt; &lt;p&gt;outputs&lt;/p&gt; &lt;p&gt;&lt;font color="#000080"&gt;Starting XYZ&lt;br /&gt;Done XYZ&lt;/font&gt; &lt;/p&gt; &lt;p&gt;Uh oh.&amp;nbsp; Neither of those guys was terminated when their variables went out of scope.&amp;nbsp; All the memory associated with them is still reserved by the heap. But they’re not reachable now.&amp;nbsp; There are no variables that reference them.&amp;nbsp; There’s nothing the script programmer can do about it now.&lt;/p&gt; &lt;p&gt;It would be unfortunate indeed if such circular references really did live until the end of the process, when the whole heap is cleaned up, both because we’d leak memory, and because those terminators might be doing something interesting. &lt;/p&gt; &lt;p&gt;Fortunately, we can do slightly better than that. If you run the code above in Windows Script Host, you’ll see that the terminators run as soon as the script ends; they are cleaned up eventually.&amp;nbsp; In IE, the terminators run when the page is torn down.&amp;nbsp; And in ASP, the terminators run when the page is served.&amp;nbsp; (Though of course in ASP you don’t want to be putting up message boxes, or accessing the ASP object model – the page is just about to get served, don’t try to mess with it!)&lt;/p&gt; &lt;p&gt;How was this implemented?&amp;nbsp; And how does this solve the memory leak problem?&lt;/p&gt; &lt;p&gt;It’s pretty straightforward. Every time a new instance of a VBScript class is created, it adds itself to a special list maintained by the engine, and whenever one is destroyed, it removes itself from the list.&amp;nbsp; When the VBScript engine itself is closed by the host, the engine runs down the list and runs all the terminators of all the VBScript objects left on the list. Then it runs down the list a second time and clears every field of the object.&amp;nbsp; This breaks the circular reference. Better late than never.&lt;/p&gt; &lt;p&gt;In Windows Script Host, this really isn’t much help because the engine isn’t closed until the process is about to be torn down anyway. But in IE and even more importantly, ASP, script engines are closed much more aggressively. It was very important that we not add a new feature to the language that made it really easy to write ASP pages which leaked memory and forced you to reboot your server frequently.&lt;/p&gt; &lt;p&gt;There are some wrinkles that we ran into when implementing the shutdown logic. Let’s see if you can deduce what they are; I’ll give the answers in my next post.&lt;/p&gt; &lt;p&gt;QUESTION #1: When I first wrote the VBScript class code, that’s not exactly the shutdown sequence I wrote. The original logic&amp;nbsp;ran down the list of objects once,&amp;nbsp;going&amp;nbsp;terminate, clear, terminate, clear, terminate, clear.&amp;nbsp; Soon after that I rewrote the shutdown sequence to the present terminate, terminate, terminate, clear, clear, clear.&amp;nbsp; Why did I make the change to a two-pass implementation? What was wrong with the original one-pass implementation?&lt;/p&gt; &lt;p&gt;QUESTION #2: The code that implements VBScript classes checks to see if the instance has been terminated already before it calls the &lt;font color="#000080"&gt;Class_Terminate&lt;/font&gt; method.&amp;nbsp; It should be clear from the foregoing why that is – if an object is in a circular reference and manages to survive until the engine shuts down, then the object will probably be terminated while there are still references held on it.&amp;nbsp; The later “clear all fields” phase of the shutdown sequence could then release all the references, triggering the “we’ve just released the last reference, so call the terminator” logic.&amp;nbsp; We therefore have to protect against the terminator running twice.&lt;/p&gt; &lt;p&gt;There’s another way that an object can be terminated twice that we protect against.&amp;nbsp; In this scenario, not only can the object be terminated twice, but an incorrect implementation of the object deletion code can crash the process.&amp;nbsp; What is it?&lt;/p&gt; &lt;p&gt;Hint: the scenario does not involve circular references. It has just a single object being terminated because it is going out of scope and has no other references.&lt;/p&gt; &lt;p&gt;QUESTION #3: Speaking of which, why do we want to ensure that terminators don’t run twice?&lt;/p&gt; &lt;p&gt;QUESTION #4: This is not a question about termination per se, but there is a termination angle in the answer.&amp;nbsp; Why do we run the garbage collector at the end of every statement, instead of only at the end of every procedure/global block?&amp;nbsp; After all, no local variable is going to go out of scope until the end of its procedure! Doesn’t that seem like a lot of work for no possible gain?&lt;/p&gt; &lt;p&gt;"I'll be back" in the new year -- have a&amp;nbsp;good festive holiday season everyone!&lt;/p&gt; &lt;p&gt;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;&lt;/font&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=330276" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/VBScript/default.aspx">VBScript</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Scripting/default.aspx">Scripting</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/COM+Programming/default.aspx">COM Programming</category></item><item><title>Why do built-in JScript functions not appear in the typeinfo?</title><link>http://blogs.msdn.com/ericlippert/archive/2004/12/06/275900.aspx</link><pubDate>Mon, 06 Dec 2004 21:08:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:275900</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>14</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/275900.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=275900</wfw:commentRss><description>&lt;font face="Lucida Sans Unicode" color="#800080" size="2"&gt; &lt;p&gt;A reader&amp;nbsp;sent me an email over the weekend asking about some odd behaviour in the guts of the JScript engine.&amp;nbsp; Unfortunately, they didn't include an email address that worked; I just got a bounce message back, Ben.&amp;nbsp; Therefore I'll just answer the question here.&lt;/p&gt; &lt;p&gt;To briefly describe the problem: the user fetches the JScript "Math" object from the script engine by calling &lt;font color="#000080"&gt;ParseScriptText&lt;/font&gt; to evaluate the expression &lt;font color="#000080"&gt;"Math".&lt;/font&gt; This returns an &lt;font color="#000080"&gt;IDispatch&lt;/font&gt; object. The dispatch object can be queried for dispatch ids for "&lt;font color="#000080"&gt;sin&lt;/font&gt;" and "&lt;font color="#000080"&gt;cos&lt;/font&gt;" and all that. It can be successfully&amp;nbsp;invoked. Everything&amp;nbsp;appears to be&amp;nbsp;good. But when the user calls &lt;font color="#000080"&gt;GetTypeInfo&lt;/font&gt;, the type&amp;nbsp;description structure says that the object has zero functions.&amp;nbsp;What's up with that?&lt;/p&gt; &lt;p&gt;Clearly the typeinfo is out of step with reality. The user has in fact found two bugs. The first is that the typeinfo building code only adds to the typeinfo those functions which have already been dereferenced. So, had you called "&lt;font color="#000080"&gt;sin&lt;/font&gt;" once already, "&lt;font color="#000080"&gt;sin&lt;/font&gt;" would be added but nothing else.&lt;/p&gt; &lt;p&gt;However, the second bug trumps the first one; built-in functions are automatically skipped when adding function descriptions&amp;nbsp;to the typeinfo. I'm not sure &lt;em&gt;what&lt;/em&gt; I was thinking when I wrote that logic; it was a long time ago.&amp;nbsp;So even if you have already dereferenced a built-in function object, it won't get added to the typeinfo.&lt;/p&gt; &lt;p&gt;User-defined functions should be always correctly added to the typeinfo; they are automatically dereferenced when they are created.&lt;/p&gt; &lt;p&gt;I wrote almost all the typelibrary code, and I regret the errors. However, it's unlikely that either of these flaws will ever be fixed, and clearly both would have to be fixed in order to make&amp;nbsp;the given scenario&amp;nbsp;work correctly. Both fixes&amp;nbsp;would touch a lot of complex code and are therefore&amp;nbsp;quite risky.&amp;nbsp;We try to not apply risky fixes to&amp;nbsp;fix a problem that, to my knowledge, only one person has ever noticed in the last seven or eight years!&amp;nbsp; If there's a massive outcry to make typeinfos for built-in objects work correctly, I'll pass that along to the sustaining engineering team; I wouldn't hold my breath waiting for a fix if I were you.&lt;/p&gt; &lt;p&gt;Thanks for bringing this to my attention.&lt;/p&gt;&lt;/font&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=275900" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/JScript/default.aspx">JScript</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Scripting/default.aspx">Scripting</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/COM+Programming/default.aspx">COM Programming</category></item><item><title>Wherefore IDispatchEx?</title><link>http://blogs.msdn.com/ericlippert/archive/2004/10/07/239289.aspx</link><pubDate>Thu, 07 Oct 2004 17:32:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:239289</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>17</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/239289.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=239289</wfw:commentRss><description>&lt;font face="Lucida Sans Unicode" color="#800080" size="2"&gt; &lt;p&gt;&lt;A href="http://weblogs.asp.net/ericlippert/archive/2004/01/23/62302.aspx"&gt;Quite a&amp;nbsp;while back&lt;/a&gt; I said that I'd write a post describing why we invented &lt;font color="#000080" size="2"&gt;IDispatchEx&lt;/font&gt;&lt;font color="#800080" size="2"&gt;. I already covered the part about using it to probe the stack for security reasons, but what other reasons did we implement that thing? The &lt;/font&gt;&lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/script56/html/jslrfIDispatchEx.asp"&gt;documentation&lt;/a&gt; is pretty much accurate, but sparse in places. (According to the doc, &lt;font color="#000080" size="2"&gt;GetNameSpaceParent&lt;/font&gt;, uh, &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/script56/html/lrfIDispatchExGetNameSpaceParent.asp"&gt;&lt;u&gt;&lt;font color="#0000ff" size="2"&gt;gets the namespace parent&lt;/u&gt;&lt;/font&gt;&lt;/a&gt;&lt;font color="#800080" size="2"&gt;.) I won't go into the flag-for-flag level of detail that the doc does well, but I thought I might describe what features motivated the various methods on &lt;/font&gt;&lt;font color="#000080" size="2"&gt;IDispatchEx&lt;/font&gt;&lt;font color="#800080" size="2"&gt;. The features are:&lt;/p&gt;&lt;b&gt; &lt;p&gt;Expando objects&lt;/p&gt;&lt;/b&gt; &lt;p&gt;In most objects, the methods you've got are the ones you get. But JScript objects and some IE DOM objects can have arbitrary, user-defined properties and methods added to them at will. We call such objects "expando" objects. &lt;/p&gt; &lt;p&gt;Strictly speaking, &lt;/font&gt;&lt;font color="#000080" size="2"&gt;IDispatchEx&lt;/font&gt;&lt;font color="#800080" size="2"&gt; is not required to implement an expando object. You could have an implementation of &lt;/font&gt;&lt;font color="#000080" size="2"&gt;IDispatch&lt;/font&gt;&lt;font color="#800080" size="2"&gt; which added a new named field every time &lt;/font&gt;&lt;font color="#000080" size="2"&gt;GetIdsOfNames&lt;/font&gt;&lt;font color="#800080" size="2"&gt; was called, and everything would work just fine. What &lt;/font&gt;&lt;font color="#000080" size="2"&gt;IDispatchEx&lt;/font&gt;&lt;font color="#800080" size="2"&gt; gives you is the ability to pass in a flag (&lt;/font&gt;&lt;font color="#000080" size="2"&gt;fdexNameEnsure&lt;/font&gt;&lt;font color="#800080" size="2"&gt;) that specifically requests expando semantics. An object model could choose to, say, only create new fields when the flag was passed in and error out if an unknown name was passed in without the flag. This would then allow the caller to probe for the existence of a property without creating it as a side effect. (Those semantics are up to the callee though -- callers cannot assume that not passing the flag means no expando semantics!) &lt;/p&gt; &lt;p&gt;Use the &lt;/font&gt;&lt;font color="#000080" size="2"&gt;GetDispID&lt;/font&gt;&lt;font color="#800080" size="2"&gt; method to access this feature.&lt;/p&gt;&lt;b&gt; &lt;p&gt;Delete members&lt;/b&gt; &lt;/p&gt; &lt;p&gt;JScript has a &lt;/font&gt;&lt;font color="#000080" size="2"&gt;delete&lt;/font&gt;&lt;font color="#800080" size="2"&gt; operator which does not work at all like C++'s &lt;/font&gt;&lt;font color="#000080" size="2"&gt;delete&lt;/font&gt;&lt;font color="#800080" size="2"&gt; operator. Rather, JScript's &lt;/font&gt;&lt;font color="#000080" size="2"&gt;delete&lt;/font&gt;&lt;font color="#800080" size="2"&gt; operator removes an expando field from an object. It's pretty useless actually, because doing so does not free up any memory beyond simply clearing the field. Why not? Because implementers must ensure that if the property is re-added that it gets the same dispatch identifier the second time; someone might be &lt;/font&gt;&lt;A href="http://weblogs.asp.net/ericlippert/archive/2003/09/16/53027.aspx"&gt;&lt;u&gt;&lt;font color="#0000ff" size="2"&gt;caching the dispid&lt;/u&gt;&lt;/font&gt;&lt;/a&gt;&lt;font color="#800080" size="2"&gt;. That means that the property bucket and its name has to be kept around, and worse, that every property bucket needs a flag that marks whether it's deleted or not. (The implementer must also ensure that property enumeration continues to work even if the enumerator -- see below -- is presently sitting on a property that was just deleted.) Use &lt;/font&gt;&lt;font color="#000080" size="2"&gt;DeleteMemberByName&lt;/font&gt;&lt;font color="#800080" size="2"&gt; or &lt;/font&gt;&lt;font color="#000080" size="2"&gt;DeleteMemberByDispID&lt;/font&gt;&lt;font color="#800080" size="2"&gt; in the unlikely event that you want to use this feature.&lt;/p&gt;&lt;b&gt; &lt;p&gt;Case sensitivity&lt;/p&gt;&lt;/b&gt; &lt;p&gt;Visual Basic is case-insensitive, and &lt;/font&gt;&lt;font color="#000080" size="2"&gt;IDispatch&lt;/font&gt;&lt;font color="#800080" size="2"&gt; was built by the VBA team back in the day, so they never implemented support for case-sensitive languages. JScript is case sensitive, so &lt;/font&gt;&lt;font color="#000080" size="2"&gt;IDispatchEx&lt;/font&gt;&lt;font color="#800080" size="2"&gt; lets you pass in flags (&lt;/font&gt;&lt;font color="#000080" size="2"&gt;fdexNameCaseSensitive&lt;/font&gt;&lt;font color="#800080" size="2"&gt;, &lt;/font&gt;&lt;font color="#000080" size="2"&gt;fdexNameCaseInsensitive&lt;/font&gt;&lt;font color="#800080" size="2"&gt;) on &lt;/font&gt;&lt;font color="#000080" size="2"&gt;GetDispID&lt;/font&gt;&lt;font color="#800080" size="2"&gt; that control the case-sensitivity of the lookup.&lt;/p&gt;&lt;b&gt; &lt;p&gt;Property enumeration&lt;/p&gt;&lt;/b&gt; &lt;p&gt;In the non-expando world, the property set of an object is stable, so there's little need to enumerate it. If you did need to enumerate it, you could always just look at the static typeinfo. But constructing dynamic typeinfos in a world with expando objects is difficult and expensive, so instead we added the ability to enumerate the valid dispatch identifiers (&lt;/font&gt;&lt;font color="#000080" size="2"&gt;GetNextDispID&lt;/font&gt;&lt;font color="#800080" size="2"&gt;) and turn the identifier back into a name (&lt;/font&gt;&lt;font color="#000080" size="2"&gt;GetMemberName&lt;/font&gt;&lt;font color="#800080" size="2"&gt;). This is how &lt;/font&gt;&lt;A href="http://weblogs.asp.net/ericlippert/archive/2003/09/22/53063.aspx"&gt;&lt;u&gt;&lt;font color="#0000ff" size="2"&gt;JScript's for-in loop&lt;/u&gt;&lt;/font&gt;&lt;/a&gt;&lt;font color="#800080" size="2"&gt; is implemented.&lt;/p&gt;&lt;b&gt; &lt;p&gt;Constructors&lt;/p&gt;&lt;/b&gt; &lt;p&gt;JScript functions may be called as constructors, which is a little weird and has &lt;/font&gt;&lt;A href="http://weblogs.asp.net/ericlippert/archive/2003/11/06/53352.aspx"&gt;&lt;u&gt;&lt;font color="#0000ff" size="2"&gt;different semantics from calling a regular function&lt;/u&gt;&lt;/font&gt;&lt;/a&gt;&lt;font color="#800080" size="2"&gt;. &lt;/font&gt;&lt;font color="#000080" size="2"&gt;IDispatchEx&lt;/font&gt;&lt;font color="#800080" size="2"&gt; adds a &lt;/font&gt;&lt;font color="#000080" size="2"&gt;DISPATCH_CONSTRUCT&lt;/font&gt;&lt;font color="#800080" size="2"&gt; flag that can be passed to &lt;/font&gt;&lt;font color="#000080" size="2"&gt;InvokeEx&lt;/font&gt;&lt;font color="#800080" size="2"&gt; to let the callee know that it is being invoked as a constructor.&lt;/p&gt;&lt;b&gt; &lt;p&gt;Namespace chaining&lt;/p&gt;&lt;/b&gt; &lt;p&gt;JScript supports some pretty intense scope resolution semantics, well beyond the local/class/global &lt;/font&gt;&lt;A href="http://weblogs.asp.net/ericlippert/archive/2004/06/18/159378.aspx"&gt;&lt;u&gt;&lt;font color="#0000ff" size="2"&gt;scoping rules&lt;/u&gt;&lt;/font&gt;&lt;/a&gt;&lt;font color="#800080" size="2"&gt; in VBScript. Think &lt;/font&gt;&lt;a href="http://blogs.msdn.com/ericlippert/archive/2003/09/17/53028.aspx"&gt;&lt;u&gt;&lt;font color="#0000ff" size="2"&gt;closures&lt;/u&gt;&lt;/font&gt;&lt;/a&gt;&lt;font color="#800080" size="2"&gt;, or &lt;/font&gt;&lt;A href="http://weblogs.asp.net/ericlippert/archive/2003/10/03/53136.aspx"&gt;&lt;u&gt;&lt;font color="#0000ff" size="2"&gt;with&lt;/u&gt;&lt;/font&gt;&lt;/a&gt;&lt;font color="#800080" size="2"&gt; blocks, which allow construction of scope chains of arbitrary length. But that's not all -- it gets even more fun.&lt;/p&gt; &lt;p&gt;To make the &lt;/font&gt;&lt;font color="#000080" size="2"&gt;this&lt;/font&gt; object semantics that &lt;A href="http://weblogs.asp.net/ericlippert/archive/2004/09/20/231852.aspx"&gt;you guys were arguing about the other day&lt;/a&gt;&lt;font color="#800080" size="2"&gt; work, if you call a function that has a &lt;/font&gt;&lt;font color="#000080" size="2"&gt;this&lt;/font&gt;&lt;font color="#800080" size="2"&gt; argument, and it was invoked with the &lt;/font&gt;&lt;font color="#000080" size="2"&gt;fdexImplicitParents&lt;/font&gt;&lt;font color="#800080" size="2"&gt; flag, then we run up the &lt;/font&gt;&lt;font color="#000080" size="2"&gt;GetNameSpaceParent&lt;/font&gt;&lt;font color="#800080" size="2"&gt; chain to get all the parent scope objects and stuff them into the scope chain for the function invocation. Don't try this at home, kids; I barely remember how any of this stuff works.&lt;/p&gt;&lt;b&gt; &lt;p&gt;Debugger support &lt;/p&gt;&lt;/b&gt; &lt;p&gt;Finally &lt;/font&gt;&lt;font color="#000080" size="2"&gt;IDispatchEx&lt;/font&gt;&lt;font color="#800080" size="2"&gt; has a &lt;/font&gt;&lt;font color="#000080" size="2"&gt;GetMemberProperties&lt;/font&gt;&lt;font color="#800080" size="2"&gt; method which is never used by JScript. Rather, it's used by the script debugger so that the debugger can tell you whether a given field is a method, property, etc. &lt;/p&gt; &lt;p&gt;So there you go -- a whole lot of new features that were difficult to shoehorn into &lt;/font&gt;&lt;font color="#000080" size="2"&gt;IDispatch&lt;/font&gt;&lt;font color="#800080" size="2"&gt;, so we implemented a new interface.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;/font&gt;&lt;/font&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=239289" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/JScript/default.aspx">JScript</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Scripting/default.aspx">Scripting</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/COM+Programming/default.aspx">COM Programming</category></item><item><title>Use vs. Mention in JScript Doesn't Come For Free</title><link>http://blogs.msdn.com/ericlippert/archive/2004/09/20/231852.aspx</link><pubDate>Mon, 20 Sep 2004 17:16:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:231852</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>18</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/231852.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=231852</wfw:commentRss><description>&lt;font face="Lucida Sans Unicode" color="#800080" size="2"&gt;&lt;font color="#800080" size="2"&gt; &lt;p&gt;Before today's entry, a quick note. Work has just gotten &lt;strong&gt;insanely&lt;/strong&gt; busy as we push towards getting VSTO ready for the Whidbey release. I likely won't have much time to blog over the next couple weeks, so the blog refresh rate is going to go down for a while. I have a collection of pre-written articles&amp;nbsp;-- such as this one -- that I'll dip into every now and then when I have a few spare minutes, but I likely won't be very topical or responsive for a bit.&lt;/p&gt; &lt;p&gt;OK, onward; a while back a reader asked what the difference was between&lt;/p&gt;&lt;/font&gt;&lt;font face="Lucida Console" color="#000080" size="2"&gt; &lt;p&gt;document.write("hello");&lt;/p&gt;&lt;/font&gt;&lt;font color="#800080" size="2"&gt; &lt;p&gt;and&lt;/p&gt;&lt;/font&gt;&lt;font face="Lucida Console" color="#000080" size="2"&gt; &lt;p&gt;foo = document.write;&lt;br /&gt;foo("hello");&lt;/p&gt;&lt;/font&gt;&lt;font color="#800080" size="2"&gt; &lt;p&gt;from the point of view of what actually happens "behind the scenes" in the &lt;font color="#000080"&gt;IDispatch&lt;/font&gt; calls.&amp;nbsp; The reader noted in particular that though this trick works in IE, it &lt;strong&gt;doesn't&lt;/strong&gt; work in WSH:&lt;/p&gt;&lt;/font&gt;&lt;font face="Lucida Console" color="#000080" size="2"&gt; &lt;p&gt;foo = WScript.Echo; // Nope, sorry.&lt;br /&gt;foo("hello"); &lt;/p&gt;&lt;/font&gt;&lt;font color="#800080" size="2"&gt; &lt;p&gt;Here's the deal.&amp;nbsp; The IE object model has been specially designed with JScript in mind.&amp;nbsp; Unlike VBScript, JScript makes a distinction between &lt;b&gt;naming&lt;/b&gt; a function and &lt;b&gt;calling&lt;/b&gt; a function.&amp;nbsp; When you say&lt;/p&gt;&lt;/font&gt;&lt;font face="Lucida Console" color="#000080" size="2"&gt; &lt;p&gt;abc = blah.baz();&lt;/p&gt;&lt;/font&gt;&lt;font color="#800080" size="2"&gt; &lt;p&gt;that calls the baz function and results in whatever it returns.&amp;nbsp; But&lt;/p&gt;&lt;/font&gt;&lt;font face="Lucida Console" color="#000080" size="2"&gt; &lt;p&gt;abc = blah.baz;&lt;/p&gt;&lt;/font&gt;&lt;font color="#800080" size="2"&gt; &lt;p&gt;assigns the baz &lt;strong&gt;function object&lt;/strong&gt;&amp;nbsp;itself to abc; it essentially makes an &lt;strong&gt;alias&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;The &lt;font color="#000080"&gt;IDispatch&lt;/font&gt; interface takes flags which determine whether the caller wants to fetch the named property or call the named function. Many object models do not honour those flags though, because no language before JScript really took advantage of the distinction.&amp;nbsp; In fact, object models designed to be called from VB or VBScript often don't even check the flag -- if it says "fetch the property" or "call the method", well, it just calls the method either way.&lt;/p&gt; &lt;p&gt;So here's what happens when you say &lt;/font&gt;&lt;font face="Lucida Console" color="#000080" size="2"&gt;foo = document.write; &lt;/font&gt;&lt;font color="#800080" size="2"&gt;&amp;nbsp;First, JScript attempts to resolve "&lt;font color="#000080"&gt;document&lt;/font&gt;".&amp;nbsp; It can't find a local or global variable called that, so it asks the global window object for the &lt;font color="#000080"&gt;document&lt;/font&gt; property.&amp;nbsp; IE gives back the document object.&amp;nbsp; JScript then asks the document object to give back the value of the &lt;font color="#000080"&gt;write&lt;/font&gt; property.&amp;nbsp; &lt;strong&gt;IE creates an object which has a default method&lt;/strong&gt;.&amp;nbsp; The default method calls the &lt;font color="#000080"&gt;write&lt;/font&gt; function, but no one calls the method yet -- we just have an object which, when invoked, will call the mehtod.&amp;nbsp; JScript assigns the object to &lt;font color="#000080"&gt;foo&lt;/font&gt;.&amp;nbsp; Then when you call &lt;/font&gt;&lt;font face="Lucida Console" color="#000080" size="2"&gt;foo("hello"); &lt;/font&gt;&lt;font color="#800080" size="2"&gt;JScript invokes the default method on the object, which calls the &lt;font color="#000080"&gt;write&lt;/font&gt; method.&lt;/p&gt; &lt;p&gt;The WSH object model was not designed with this in mind.&amp;nbsp; It does not make a distinction between naming a function and calling it, so you can't use this trick.&amp;nbsp; &lt;font color="#000080"&gt;WScript.Echo;&lt;/font&gt; does not give back a function object that can be invoked later.&lt;/p&gt;&lt;/font&gt;&lt;/font&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=231852" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/JScript/default.aspx">JScript</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Scripting/default.aspx">Scripting</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/COM+Programming/default.aspx">COM Programming</category></item></channel></rss>