NGWS SDK Documentation  

This is preliminary documentation and subject to change.
To comment on this topic, please send us email at ngwssdk@microsoft.com. Thanks!

Activating COM classes

Early Bound Activation

Instantiating an instance of an object in NGWS is simply a matter of creating the object in whatever syntax is appropriate for your language. The same is true for COM objects being used from the NGWS runtime. Here are some examples of how to create an instance of the AcmeLib.Slingshot object in various languages:

In Visual Basic:

Dim ss as AcmeLib.Slingshot
set ss = new AcmeLib.Slingshot.  

In Managed C++:

AcmeLib.Slingshot ss;
ss = new AcmeLib.Slingshot();  

In C#:

AcmeLib.Slingshot ss;
ss = new AcmeLib.Slingshot();  
   

At compile time, a metadata definition of the AcmeLib.Slingshot object must be available. Again, the technique used to do this depends on your language. In Visual Basic, adding a reference to the metadata DLL makes the type available. In Managed C++, you import the metadata DLL with the #import statement.

At runtime, when a managed application tries to instantiate the class, the runtime again needs to locate the metadata for the class. The situation is the same regardless of whether the class is a NGWS class or a COM class. This metadata must be available at runtime in order to activate a class. Since the metadata for COM classes is always packaged in a module other than the module containing the COM code, activating a COM class usually requires two separate modules.

Once the metadata for the class is located, the runtime loads the metadata assembly and begins to activate the class. The metadata contains various flags to indicate how the class should be constructed. See the Interop Metadata Spec for details on the specific metadata used. If the runtime recognizes that the class is a COM class (metadata for COM classes has the tdImport flag set), it fabricates an RCW for the class and delegates the actual construction to COM’s CoCreateInstance API using the CLSID specified in the metadata. If the metadata was generated with the TlbImp tool, the CLSID was carried forward from the original type library.

The underlying COM class must be co-creatable in order to activate the class in this manner. If the COM class is not creatable the construction will fail. However, RCW’s can be created in other ways. For example, a creatable object may return an instance of another object or interface from a method call. Upon return from the call, an RCW for the returned object would be created. Objects created in this way do not have to be co-creatable but they are required to have metadata.

The next section describes another technique for creating COM objects using reflection. Reflection is very useful for creating COM objects that have no metadata however, it can still be used on objects that do have metadata. Keep that in mind when reading the following section. All the techniques described below also apply to object created in an early bound fashion.

Late Bound Activation Thru Reflection

Another method of instantiating a classic COM server is through reflection. The process is the same regardless of whether the class is a COM class or a NGWS class. Using Reflection to create COM objects is particularly useful when an object does not have accompanying metadata.

A Type object for a specific class can be obtained through the static method Type.GetTypeFromProgID that returns a System.Type object that represents the type specified by a specific ProgID. With the type object you can create an instance of the COM class by passing the type to one of the CreateInstance methods of the Activator class.

You can also inspect the COM type by calling method of the type object. If the COM type has accompanying metadata (produced by importing the type library with TlbImp) , complete information is available about the type through the Type object. If the COM type does not have accompanying metadata, the Type object will provide relatively little information. COM types that have no metadata are wrapped with a generic RCW with the name __ComObject. __ComObject is a private type that is used solely for wrapping COM objects that don’t have associated metadata.

You can pass the object instance to one of the InvokeMember functions on the Type object to actually call methods and access properties of the object through the objects IDispatch interface (if the object supports IDispatch). Arguments are packed into an object array, which is then passed to InvokeMember along with the method name, a set of binding flags, a Binder, and the object instance. When using InvokeMember with a COM object, the following rules apply:

The following code samples show how to use InvokeMember on COM types without metadata:

In Managed C++:

#using <mscorlib.dll>

using namespace System;
using namespace Reflection;

Type typ;
Object obj;

typ = Type::GetTypeFromProgID(“Acme.Slingshot”);  
obj = Activator.CreateInstance(typ);  
typ.InvokeMember("Aim", BindingFlags::InvokeMethod, NULL, obj, NULL);  

In C#:

using System;
using System.Reflection;

Type typ;
Object obj;
Object[] prms = new Object[2];
      
typ = Type.GetTypeFromProgID("Acme.Slingshot");
obj = Activator.CreateInstance(typ);
   
prms[0] = 10;      
prms[1] = 150;      

typ.InvokeMember("aim", BindingFlags.InvokeMethod, null, obj, prms);
typ.InvokeMember("SHOOT", BindingFlags.InvokeMethod, null, obj, null);

If you do have metadata for the type, you can use reflection to create a late bound object reference by passing the name of the type to the static method Type.GetType().

The following code sample shows how this can be done:

In C#:

using System;
using System.Reflection;

Type typ;
AcmeLib.Slingshot ss;
Object[] prms = new Object[2];
      
typ = Type.GetTypeFromProgID("Acme.Slingshot");
ss = (AcmeLib.Slingshot)Activator.CreateInstance(typ);   
prms[0] = 10;      
prms[1] = 150;      

typ.InvokeMember("aim", BindingFlags.InvokeMethod, null, ss, prms);
typ.InvokeMember("SHOOT", BindingFlags.InvokeMethod, null, ss, null);

To invoke a method on a COM object by DISPID rather than by name, you can pass the name “[DISPID=n]” to Type.InvokeMember where n is the DispId of the member. For example, the following code can be used to invoke the method with a DispId of 5 without knowing the name of the method

typ.InvokeMember ("[DISPID=5]", BindingFlags.InvokeMethod, nothing, obj, Params)

It’s important to note that the __ComObject type is a private type used exclusively to wrap COM types that have no metadata. Consequently, reflecting on this type does not reveal information about the underlying COM object. Instead it reveals information about the __ComObject type. For example, the FullName property of an __ComObject type is always “System.__ComObject” as opposed to having the name of the underlying COM object. Other members of the Type object return similar information. Type.GetMembers() for example, returns the members of __ComObject rather than the members of the underlying COM object that you might expect.

For more details on the use of the Type object or the InvokeMember method, see the class library documentation for each.