In part two of the series Creating a instance of a Mapinfo COM object in .NET, I’m going to be talking about creating an instance of Mapinfo’s COM object using reflection and Activator.CreateInstace. This approach unlike the approach outlined in part one, will allow for your application to be Mapinfo version independent.
Step 1: Creating a COM instance of Mapinfo.
Unlike part one where the first step was to create a reference to the Mapinfo COM object, we won’t be needing to do that here as we are using reflection to create an instance straight away.
The first function that we need to call is called Type.GetTypeFromProgID, this will return a type using the program ID of an application. Where do we get this program ID from? A listing in HKEY_CLASSES_ROOT is created when a application registers itself as a COM server, this listing includes things like the GUID of the application, the applications program ID and the path to the application to use as the COM server. Lets have a quick look at how mapinfo is registered in the registry.
If you have read part one of this series you will notice that the GUID above is for Mapinfo 9.5, we don’t need to use this GUID anywhere in this post so I have only marked it in the above picture just as a note.
You will notice two other things in the picture above, one is the key ProgID and the other is the key VersionIndependentProgID , these keys contain the program ID that can be used by Type.GetTypeFromProgID to create an instance of Mapinfo.
Enough about the registry lets see some code.
First lets get the type associated to Mapinfo using the program ID that’s in the registry, like so:
Type mapinfotype = Type.GetTypeFromProgID("Mapinfo.Application");
The above code will now search the regisrty for a application with the program ID equaling “Mapinfo.Application” and return the type for that application or as the documentation in the .NET framework says.
Gets the type associated with the specified program identifier (ProgID),
returning null if an error is encountered while loading the System.Type.
Moving on. Now that we have the type that is associated to Mapinfo’s COM object we can now go and create an instance of Mapinfo from this type, for this we will need a static method in the Activator class. The code that we will need to call is like this:
object instance = Activator.CreateInstance(mapinfotype);
Passing the type that we got returned from Type.GetTypeFromProgID into the CreateInstance method will create an instance of Mapinfo for us and return it as a object. If we join the above code together we should have something like this:
Type mapinfotype = Type.GetTypeFromProgID("Mapinfo.Application"); object instance = Activator.CreateInstance(mapinfotype);
Now that we have created an instance of Mapinfo we can go ahead and start using it.
Step 2: Using the object.
The biggest problem with doing things this way is that because we only have the instance of Mapinfo as a object type we have to use reflection to get access to the Do and Eval methods that Mapinfo provides.
So what we will do first is create a our own Do method that wraps up the reflection process, so we don’t have to see it every time we need to call Do
public void Do(string command) {}
Now lets go on and fill out the reflection bit.
public void Do(string command) { parameter[0] = command; mapinfoType.InvokeMember("Do", BindingFlags.InvokeMethod, null, instance, parameter); }
The above code will invoke the Do method in Mapinfo using reflection and pass in the command string that we supplied.
A note about the above code because we are using a COM object we have very limited use of reflection and have to use the InvokeMember method, which is slow compared to the optimized reflection methods that we can use on .NET objects. I won’t go into details here but if you do a quick google search on InvokeMemeber vs Methodinfo.Invoke speed you will find what I’m talking about. Moving on. See speed test section form notes.
Now that we have to Do method out of the way lets move on to eval. Pretty much the same process but it will return a string insteed of a void type.
public string Eval(string command) { parameter[0] = command; return (string)mapinfoType.InvokeMember("Eval", BindingFlags.InvokeMethod, null,instance,parameter); }
Done, now lets put that all together in a nice class with a static CreateInstance method.
public class Mapinfo { private object mapinfoinstance; public Mapinfo(object mapinfo) { this. mapinfoinstance = mapinfo; } public static Mapinfo CreateInstance() { Type mapinfotype = Type.GetTypeFromProgID("Mapinfo.Application"); object instance = Activator.CreateInstance(mapinfotype); return new Mapinfo(instance); } public void Do(string command) { parameter[0] = command; mapinfoType.InvokeMember("Do", BindingFlags.InvokeMethod, null, instance, parameter); } public string Eval(string command) { parameter[0] = command; return (string)mapinfoType.InvokeMember("Eval", BindingFlags.InvokeMethod, null,instance,parameter); } }
Now that we have it wrapped up in a nice class we can go ahead and use it in our application, something like this:
public static void Main() { Mapinfo mymapinfo = Mapinfo.CreateInstance(); mymapinfo.Do(//Run some command); }
Summing up: Pros and Cons
In summng up, lets have a look at some of the pros and cons of this approch. Pros
- Allows Mapinfo version independence.
Cons
- Not strongly typed
- Is late bound using reflection = no complier support + slower speed See Speed test section
- Using reflection has speed issues due to it having to get type information everytime Do or Eval methods are called. See Speed test section
- You have to write wrapper methods around the reflection process.
- Can’t easily get to methods that Mapinfo provides, with out wrapping them up first.
This approach has a lot more cons then pros as you can see, some of them are pretty big ones, the real only advantage it gives you is the ability to work with any version Mapinfo. My next post will outline a method that allows both version independence and strong typed access and no late binding.