Home arrow C# arrow Page 3 - Using Late Bound COM Objects
C#

Using Late Bound COM Objects


There are different methods available for invoking COM objects at runtime in .NET, including late binding. In this article Beth from the Wrox team will walk us through them, providing examples for each.

Author Info:
By: Wrox Team
Rating: 5 stars5 stars5 stars5 stars5 stars / 35
November 18, 2002
TABLE OF CONTENTS:
  1. · Using Late Bound COM Objects
  2. · Introductory Concepts
  3. · Late Binding in .NET: The Basic Invocation
  4. · Late Binding in .NET: With a Runtime Callable Wrapper Available
  5. · Late Binding in .NET: Monitoring Performance of the Various Invocation Methods
  6. · Conclusion

print this article
SEARCH DEVARTICLES

Using Late Bound COM Objects - Late Binding in .NET: The Basic Invocation
(Page 3 of 6 )

Conceptual Overview
At a basic level, late binding in .NET is similar to the pre-.NET era. A generic variable is declared, a call to create the target component is made, and its methods are invoked. The concepts are the same, it is the implementation specifics that differ.

Late binding in C# requires a familiarity with the System.Reflection namespace. In particular, we are interested in the Activator, Assembly, and Type classes, as well as the InvokeMember method.
  • Type is the root of all reflection operations. All objects support the GetType method, which returns a Type object representing the instance's type. Once we have a COM object's type definition, we are able to create an instance of that object and invoke its methods.
  • Activator is a static class used to create an object instance once we have its Type or assembly name. Activator returns either an object or ObjectHandle. In the case of the ObjectHandle we immediately unwrap it to retrieve the underlying object.
  • Assembly can be used if you have an RCW for the object and know its name. Assembly objects can be instantiated by file name, which allows you to bypass using the Activator object. I will show example code of to do this, though I personally prefer to use Activator (I hate to remember more than one syntax for an action if I don't have to, and in this case I have yet to find a technical reason to prefer Assembly over Activator.)
  • InvokeMember is a method of the Type object. We use it to forward our method calls to the instantiated object.
A Simple COM Invocation
For the purposes of this article, we will use a COM object named "TestObject " created in Visual Basic 6. To emulate bad COM practices, the Project | Properties | Component setting has been set to No Compatibility. This will cause the GUID to change every time the component is compiled - wreaking havoc with early-bound applications. The figure below shows that TestObject contains one class, "TestClass," with the two methods "Echo1 " and "Echo2". The component is available in the download.



We will call the two methods of this (rather simplistic) COM object from a C# Windows Forms application and display the returned text in textbox controls.



Here is the full code for the button_click routine (note that error handling should be added). The routine is found in the file Form1.cs in the download's LateCOMTester project.

private void btnBasic_Click(object sender, System.EventArgs e)
{
// overloaded method, can pass the server name as second
// parameter if necessary.
Type myType = Type.GetTypeFromProgID("TestObject.TestClass");

// heavily overloaded method call. Can also be used with
// assembly file names if you have them.
object myObject = Activator.CreateInstance(myType);

// method parameters are passed in an object array.
// Must set these up before invocation
object [] oParms = new Object[]{"Echo This"};

// Invoke the method and cast the result to the correct
// object type.
string myString = (string) myType.InvokeMember("Echo1",
BindingFlags.InvokeMethod,null,myObject,oParms);

txtEcho1.Text = myString;

// Reset for the second method call, to pass in 2 parameters
oParms = null;
oParms = new Object[] {"Echo Two", "with this"};
myString = (string) myType.InvokeMember("Echo2",BindingFlags.InvokeMethod, null,
myObject, oParms);

txtEcho2.Text = myString;

}


Loading the Type
The GetTypeFromProgID method allows you to load the Type object for a given registered COM component. This method of type location is best used when there is no pre-generated RCW or if you don't know the RCW's file name. For example, a RCW generated by Beta2 of the Visual Studio IDE will have the version number appended to the file name, while the Release Candidate bits for Visual Studio do not append version information in the file's name. A later example will show how to get the Type object when the RCW's name is known.

// overloaded method, can pass the server name as second
// parameter if necessary.
Type myType = Type.GetTypeFromProgID("TestObject.TestClass");


Creating the Object
CreateInstance is a heavily overloaded method of the static class Activator. In this usage we pass it Type and receive an object in return. The overloads for this method that accept a Type object always return back an object. Those overloads that accept the name of an assembly return an ObjectHandle object, which must then be unwound to retrieve the base object. A later example will show how to unwind the ObjectHandle.

// heavily overloaded method call. Can also be used with
// assembly file names if you have them.
object myObject = Activator.CreateInstance(myType);


Invoking the Method
Invoking the COM object's methods is a bit less intuitive. For starters, the parameters must be passed as an array of objects. In this case the method Echo1 takes a single string parameter, while Echo2 requires two string parameters. The code example shows setting up the parameter array for each method call.

As the code illustrates, the method invocation is performed via the Type object. In its simplest form InvokeMember accepts five parameters:
  • name: the name of the method to call.
  • invokeAttr: A bitmask comprised of one or more BindingFlags that specify how the method search is conducted. The usual flag is BindingFlags.InvokeMethod. The flag is technically not required to be specified. However, as BindingFlags.Public | BindingFlags.Instance is the default (and is not what we desire here) you will want to make a point of providing the BindingFlags.InvokeMethod value for this flag.
  • binder: A binder object is used to define specific properties for binding. A binder parameter is not required for this scenario.
  • target: The object on which to invoke the specified method
  • args(): The object array of parameters required for the method.
// method parameters are passed in an object array.
// Must set these up before invocation
object [] oParms = new Object[]{"Echo This"};

// Invoke the method and cast the result to the correct
// object type.
string myString = (string) myType.InvokeMember("Echo1",
BindingFlags.InvokeMethod,null,myObject,oParms);
txtEcho1.Text = myString;

// Reset for the second method call, to pass in 2 parameters
oParms = null;
oParms = new Object[] {"Echo Two", "with this"};
myString = (string) myType.InvokeMember("Echo2",BindingFlags.InvokeMethod, null,
myObject, oParms);
txtEcho2.Text = myString;


The general concepts introduced thus far will get you where you need to go, 90% of the time. This section deals with some of the less likely, yet potentially more painful scenarios that can occur in the real world.
blog comments powered by Disqus
C# ARTICLES

- Introduction to Objects and Classes in C#, P...
- Visual C#.NET, Part 1: Introduction to Progr...
- C# - An Introduction
- Hotmail Exposed: Access Hotmail using C#
- Razor Sharp C#
- Introduction to Objects and Classes in C#
- Making Your Code CLS Compliant
- Programming with MySQL and .NET Technologies
- Socket Programming in C# - Part II
- Socket Programming in C# - Part I
- Creational Patterns in C#
- Type Conversions
- Creating Custom Delegates and Events in C#
- Inheritance and Polymorphism
- Understanding Properties in C#

Watch our Tech Videos 
Dev Articles Forums 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Contact Us 
Site Map 
Privacy Policy 
Support 

Developer Shed Affiliates

 




© 2003-2017 by Developer Shed. All rights reserved. DS Cluster - Follow our Sitemap
Popular Web Development Topics
All Web Development Tutorials