views:

101

answers:

5

I think this is a factory / provider type story but I'm not sure how to describe my problem. It goes like this.

InstallShield has a COM Automation Interface that they change the name of it with each release. If it was VBScript I'd say

set project = CreateObject("ISWiAuto15.ISWiProject) ' InstallShield 2009
set project = CreateObject("ISWiAuto16.ISWiProject) ' InstallShield 2010

once I have a project object I can do things like

project.OpenProject( filePath, readOnly )

In C# .NET 3.5 I add my COM reference and do the same things except now I'm tightly coupled to that class. I want to be able to do something like

var project = CreateProjectObject( typeof ISWiAutoXX.ISWiProject )

But I can't figure out how to do this as there doesn't seem to be any shared interface to cast with.

Am I out of luck or is there a way to handle this type of a problem?

A: 

Thinking round the issue I think I see a possible solution done a different way but its a bit esoteric.

References are part of the the msbuild (project) file in an ItemGroup. You can externalise this by having this particular reference in another msbuild file in the project included in the proj file.

Finally you can make this external MSBUILD file T4 generated based on some logic that looks up the COM interface and determines what the reference contains.

Preet Sangha
+4  A: 

If you're only using .NET 3.5, the best option would probably be to write your own interfaces that expose the exact functionality you require, and then implement the interfaces using IS 2009 and IS 2010. This allows you to use any implementation internally, and create a factory method (or use DI) to construct the objects.

Unfortunately, this does require a fair amount of simple pass through (wrapper methods that just call the COM object). However, it's a very robust, future proof way of operating, and lets you work with a simple, typesafe API.

Reed Copsey
That's probably a good choice for my experience level. Do you know any ways to generate an interface based on the types found in the COM wrapper? I could then create my two classes and implement the interface and start wiring up the members that I care about.
Christopher Painter
@Christopher: I, personally, would hand write it - It's a bit more work than an automated solution, but has some advantages. Just implement the methods and properties you actually are going to use, and wrap them as appropriate. (Another nice advantage is you can name things more in line with your usage, which is often help, especially when working with COM...)
Reed Copsey
I'm going to give the answer to you because after coding several interfaces and subclasses I was getting further and further into my code. But wow, that's alot of work because of the complexity of the API I'm wrapping.I have to admit, it was a good excercise but I gave up. I broke out some ducktape: A cloned my class file that interoped with InstallShield and did a search and replace to make one Class15 and one Class16. In the parent class I then wrapped it inside of a big switch statement so that only one of the classes gets constructed and called.
Christopher Painter
I will admit, it's ugly, and I now have to know to always make fixes to the one class and then copy and transform over to the other class but this code hasn't changed in 6 months anyways so hopefully that's my best ROI despite how much duck tape is involved.
Christopher Painter
+1  A: 

If you are so inclined you could customize the run time callable wrapper so the type names are constant

Conrad Frix
+1  A: 

If you're happy to give up type safety, dynamic would be helpful, but you say it's not available to you.

But you can get pretty close to dynamic in older versions of the language, by using a simple helper class to hide the noise of reflection. It doesn't do everything that the dynamic keyword can do, but it still might work for you.

Daniel Earwicker
A: 

Use VB.NET to create a strongly typed wrapper. Then you can call that wrapper from your C# application.

Jonathan Allen