Why does WScript.ConnectObject not always work?

Why does WScript.ConnectObject not always work?

  • Comments 6

I've had a tiny handful of entries in my VBScript quiz. I know from my logs that 2600+ people have read it. Come on people, there are fabulous prizes at stake here!  Go for it!

I'm going to keep the contest open until Friday morning, at which point I'll start posting answers and analysis.

****************************************************

Earlier today someone asked me why it is that sometimes WScript.ConnectObject does not connect an object to an event sink even if the object sources events. That reminded me that back in June I said that I'd explain this at some point, and I never did.

WScript.ConnectObject only works if the object implements IProvideClassInfo or IProvideMultipleClassInfo. Not all objects do.

Why?

An object can implement multiple interfaces both incoming and outgoing. Incoming interfaces are the interfaces you call an object on. Outgoing interfaces are interfaces that they call you 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.

Each interface supported by an object, whether incoming or outgoing, can have its own interface typeinfo describing it.  For a given object all these interfaces are "summarized" by one "parent" type info called the "coclass type info".  Once you have the coclass type info, you can figure out everything about the object's incoming and outgoing interfaces.

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.

The flaw in the design of the automation interfaces is this: given an IDispatch object, there is no way to discover what its coclass typeinfo is!  You can get a type info for the dispatch interface -- that is, the incoming call interface -- by calling GetTypeInfo. 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.

When that omission was realized, IProvideClassInfo was invented.  (And for aggregate objects, which may have aggregated multiple coclasses, IProvideMultipleClassInfo was invented.) IProvideClassInfo returns the coclass type info. That's why WScript.ConnectObject requires IProvideClassInfo -- it just has the object and knows nothing about its class.

You may then wonder how it is that WScript.CreateObject does event binding on objects that do not implement IProvideClassInfo.  That's easy -- WScript.CreateObject is given enough information to find the coclass type infoWScript.CreateInstance is passed the progid.  It uses that to look up the class id in the registry.  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.

This also explains how it is that Visual Basic can do event binding on objects which do not implement IProvideClassInfo.  VB has compile-time information about the progid of the object and can look up the outgoing interface in the same way.

We considered creating another version of WScript.ConnectObject which took a classid or progid, but we decided that it wouldn't be useful in very many situations, and would be confusing and hard to document well.

 

  • The differences in the way various hosts handle event hookup makes it a real pain. Syntax is different (WScript.ConnectObject, SCRIPT..FOR..EVENT, no support whatsoever, etc.) so the hookup code isn't even portable.

    If I'm writing my own COM object, what is the downside of using callbacks for notification? I should be able to have the script pass in an IDispatch representing a script function to be called, then the object Invokes it whenever the condition occurred. I can't seem to find any examples though, and I suspect there are threading issues I haven't considered.
  • I agree that it is a real pain. I just developed the language -- how the different hosts expose language features is nothing we had any control over, and each host chose a different way to expose events.

    > If I'm writing my own COM object, what is the downside of using callbacks for notification?

    I can think of several down sides.

    First off, it's nonstandard. So what if your ASP, IE and WSH callers are now consistent with each other? Your object is inconsistent with every other object in the world. Developers who know how to bind events in WSH will have to learn a new, different way for your object.

    Second, you are describing a single cast delegate event model -- like IE has. How are you going to handle the situation where two sinks want to listen to the same source? (Look for my article "Multicast Delegates The Evil Way" for more details.)

    > I suspect there are threading issues I haven't considered.

    The binding code should pass you a sink that can be called on the current apartment, and the source should call the sink on the current apartment -- no different from any other event binding model. If you try to make cross-apartment calls, either the marshaler will get involved to ensure thread safety, or, if you haven't aggregated the marshaler, the code will be plagued by race conditions and eventually die horribly, so don't do that!


  • Hopefully I know how to subscribe for a CLR event in JScript.NET (but I wish there was a language spec stating that in MSDN, mostly it's written here and there "you can only listen to the events, you cannot source them", but no idea given on how to do this listening).

    But well, is JS.NET capable of subscribing to COM events? Directly, I mean, not using the sink as AxHost does.

    Also, what about firing the .NET events? I can fire an event if I extend a class that has them defined (by implementing the add_ and remove_ functions), but can I introduce my own ones from a scratch some way?
  • Good questions. I'll write a blog entry on that some time.

  • Back in February I posted a bit about how script hosts such as Windows Script Host dynamically hook...
  • Would it be possible for Microsoft to actually update the product documentation such as http://msdn.microsoft.com/library/default.asp?url=/library/en-us/script56/html/bbd53502-bcf9-4bcd-a8bc-ae723a46534d.asp to reflect the fact that the software does not work as expected????

    That's be nice - documentation that's accurate.
Page 1 of 1 (6 items)