How to create an instance of an ActiveX control in C# at runtime?
August 24, 2006 3:41 PM   Subscribe

In C#, how can I at runtime create an instance of an ActiveX control and then use its methods, properties and events?

I have about 30 ActiveX controls which I'm writing an automated testing environment for. My program will read in an XML file which specifies, for example, that creating an instance of MyActiveXControl and calling the Foo() method will cause a Bar event to be fired. To do this, I need to be able to dynamically create an instance of MyActiveXControl* and call an arbitrary method on it and assign an event handler to an arbitrary event. How?

The difficulty in creating an instance of the control dynamically is that my C# program is managed code whereas the ActiveX control is unmanaged. There isn't an easy equivalent of VB's CreateObject() (that I know of).

* all of the ActiveX controls will be registered on the system, and I'll know where on the hard disk the .ocx is, if that helps.
posted by matthewr to Computers & Internet (22 answers total) 1 user marked this as a favorite
 
"I need to be able to dynamically create an instance of MyActiveXControl*"

Canonical answer: Factory Pattern.


"and call an arbitrary method on it and assign an event handler to an arbitrary event."

Canonical answer: Command Pattern.
(And possibly Interpreter pattern, since you're already dealing with XML).
posted by orthogonality at 3:51 PM on August 24, 2006


I think matthewr is asking more for something that allows him to create an instance of a class who's name he only has as a string and doesn't necessarily know at compile time. You know, kinda like ClassLoader's loadClass in java.
posted by rbs at 5:44 PM on August 24, 2006


Response by poster: Thanks, orthogonality, the Command Pattern link helped me think about the architecture of the program.

But that's not really my question (apologies if it was a bit unclear). What I want to know is the details of how I should actually create the ActiveX control instance. In other words, what is the C# equivalent of VB's CreateObject function?

I realise there probably won't be a single, simple C# function to do this because of the whole managed vs. unmanaged thing, but it must be possible somehow...

Previous Googling has found me this, but I haven't got it to work.
posted by matthewr at 5:51 PM on August 24, 2006


Response by poster: After posting: Yes, rbs, that's right.
posted by matthewr at 5:52 PM on August 24, 2006


Patterns are great. They help you talk about work without doing much! (I tease because I love (patterns).)

I'm not sure specifically how this will differ from instantiating a standard assembly at runtime. You might need to generate a COM interop assembly for your activex controls prior to doing this. However, once you've answered the question: how to create an instance of an activex control, you should be pretty set. You can create a dynamic instance of an object using Activator.CreateInstance and then invoke methods on it using System.Reflection.MethodInfo and associated classes.
posted by feloniousmonk at 5:54 PM on August 24, 2006


That was really inarticulate. Replace that However... etc sentence with "Once you've figured out the specifics of how you create an instance of an activex object...etc"
posted by feloniousmonk at 5:55 PM on August 24, 2006


As to the specifics of creating the object, you should take a look at Aximp.exe, but my suspicion is that your best bet will be creating an interop assembly. Google is your friend for both of those.
posted by feloniousmonk at 5:56 PM on August 24, 2006


Best answer: rbs writes "I think matthewr is asking more for something that allows him to create an instance of a class who's name he only has as a string and doesn't necessarily know at compile time."

Yes, that's what the factory pattern is for (among other things).


"You know, kinda like ClassLoader's loadClass in java."

Oh, as part of the language? But that would make your code un-portable and fragile, and dependent on a language mis-feature. Far batter to take the opportunity to add to your experience and learn to write a Factory.



Oh, ok. Class Activator and its overloaded method CreateInstance in the C# reflection API. You can access it conveniently through the system object:

// first get a an appropriate Reflection Class type, so you don't have to down-cast:
System.Type oType = System.Type.GetTypeFromProgID("SomeClass");

// Now invoke that type default ctor to return an instance of that type:
object o = System.Activator.CreateInstance(oType);

// Now call methods via reflection:
oType.InvokeMember("SomeMethod", System.Reflection.BindingFlags.InvokeMethod, null, o, new object[] {arg1, arg2});
object r = oType.InvokeMember("SomeFunction", System.Reflection.BindingFlags.InvokeMethod, null, o, new object[] {arg1, arg2});
r = oType.InvokeMember("SomeGet", System.Reflection.BindingFlags.GetProperty, null, o, null);
oType.InvokeMember("SomeSet", System.Reflection.BindingFlags.SetProperty, null, o, new object[] {w});

See here, here (from which I copied the above code but not the comments), and here for a comparison with the Factory Pattern.
posted by orthogonality at 6:09 PM on August 24, 2006


Oh, as part of the language? But that would make your code un-portable and fragile, and dependent on a language mis-feature.

Not to derail, but you've got to be joking.
posted by feloniousmonk at 6:13 PM on August 24, 2006 [1 favorite]


Response by poster: As to the specifics of creating the object, you should take a look at Aximp.exe, but my suspicion is that your best bet will be creating an interop assembly

Would this mean that every time one of the ActiveX controls changed (e.g. a new method was added to one of them) I'd have to run Aximp.exe again or recreate an interop assembly?

I was very much hoping to avoid that. The 30-odd ActiveX controls I'm creating a testing system for are under constant development. The ideal workflow would be something like:
1. Programmer adds new method to ActiveX control, builds it and registers it on the system (this stage is nothing to do with me, we can assume it all happens successfully).
2. Programmer adds a few tests to an XML test script.
3. Programmer opens up my automated testing program, points it to the latest build of the ActiveX control and the test script, and off it goes.

Having to recompile my program or run aximp.exe etc etc every time something changes in one of the ActiveX controls is a major no-no.

orthogonality: Thanks for the code sample, that looks very helpful. I'll try it in the morning at work (it's 2:20 AM in GMT here) and report back.
posted by matthewr at 6:20 PM on August 24, 2006


How does your build process work? If you're already working with a continuously integrated environment, you could modify your build scripts so that these assemblies are generated every time the build is compiled.

I don't think you'll be able to invoke your methods in the way you describe without a fair amount of complexity. Are you sure that this is the best way to write these tests? Are these controls ultimately consumed by managed code? Why not write the tests in the same environment?
posted by feloniousmonk at 6:25 PM on August 24, 2006


I didn't answer your question directly: Yes, you'd need to regenerate your interop assemblies to test new methods as they are developed.
posted by feloniousmonk at 6:25 PM on August 24, 2006


feloniousmonk writes "you've got to be joking."

Somewhat. For what matthewr wants to do, CreateInstance() probably suffices. But check out the timings on my first link, and you'll see why you wouldn't want to do this on, say, a busy website or a transaction-heavy banking app.

But more important that speed is code correctness. RTTI and Reflection intentionally through away the type-checking and type safety you want in a language (presumably, you want it, or else you's be using a non-type safe language, right?).

Also, consider what happens if I need to create Foo class instances, and Foo doesn't have a default ctor. Now I can't use Activator.CreateInstance(oType). I have to use Activator.CreateInstance( Type, Object[] ), which means I have to know what to put in the object array that's the second argument.

That's non-trivial, and in the general case forces me to do my own implementation of Koenig lookup (a massive task which would almost inevitably be worse than the compiler's own Koenig lookup).

With a Factory, I get compile-time binding, type-checking and type safety, better error checking (because I have greater context), a programmer rather than an algorithm making the subtle Koenig choices, and greater speed.

So for a large scale project, or a project that can't afford Reflection overhead, or a mission-critical project, or a project that may affect human safety (much les one that effects human safety) , or a low-level library (imagine your windowing system or graphic sub-system being slowed down by reflection), I'm definitely not joking.

Besides, Factory pattern is trivially easy to write, and seriously, is portable, so you might spend less time writing that than learning how Reflection APIs work in a particular language.
posted by orthogonality at 6:29 PM on August 24, 2006


orthogonality writes "through away the type-checking "

Er, throw away.
posted by orthogonality at 6:30 PM on August 24, 2006


Sure, in a general sense in which the problem space is not constrained by requirements, you're absolutely right. Fortunately for us, we have requirements. That's not really what irked me though, it's the portability comment. As if that is an issue when we're talking about C# and ActiveX.
posted by feloniousmonk at 6:34 PM on August 24, 2006


Response by poster: To end any potential derail, I'd better point out that I'm constrained to using C# to develop my project — C++ may be a better tool for this particular part of the program (admittedly rather an important part), but I simply don't have time to learn C++ to get this done.

Portability is also a non-issue for me (although I accept what orthogonality's saying in general). My program will never be ported to another language or platform.
posted by matthewr at 6:42 PM on August 24, 2006


I think you're going to have to live with the regeneration of these interop assemblies on a periodic basis. You can do that pretty easily using nant tasks.

Once that's done, you could probably take advantage of an inversion of control container like Castle Windsor to manage the dynamic invocation of the methods, but to be honest, you shouldn't rely on this, you should just suck up the tedium and write your tests individually.

All that said, make sure that testing these classes in a non-production environment like this will really meet your needs. If they aren't going to be invoked from managed code, testing them from managed code doesn't necessarily prove anything.
posted by feloniousmonk at 6:52 PM on August 24, 2006


matthewr writes "My program will never be ported to another language or platform."


It may however be ported to a future version of C#, in which reflection semantics may have changes. But to be clear, using CreateInstance I think suffices for what you're doing.

My aim in introducing the patterns was two-fold: first, because it's the correct answer regardless of programming language, something that you can use in the future whatever programming in, and that anyone else reading this askMefi can use, whatever language she is using.

Second, because (as you've gratifyingly already noted) examining these patterns gives a programmer insight on the problem to be solved by formalizing the problem in terms of language-neutral motivations, relations, and goals, and so helps you to understand the essence any particular solution shares.

matthewr writes "++ may be a better tool for this particular part of the program"

Well, it may be, but I haven't been arguing that. A Design Pattern is a Pattern because it's language-neutral. (A language-dependent "Pattern" is properly called an Idiom. see Coplien, et al.) And Reflection can be useful; I've certainly used it.
posted by orthogonality at 7:00 PM on August 24, 2006


Response by poster: feloniousmonk: make sure that testing these classes in a non-production environment like this will really meet your needs

My question concealed the exact purpose of my program for simplicity's sake. The ActiveX controls are a layer above what I'm actually testing. A simplified and somewhat obfuscated explanation of what I'm doing is as follows:
Each ActiveX control is responsible for controlling and communicating with a physical device attached to the computer, for example a WidgetDispenser. If I call the WidgetDispense() method of the WidgetDispenser ActiveX control, the control tells the device to dispense a new widget. The device should then tell the ActiveX control that the widget has been dispensed successfully. The control then fires a WidgetDispensed event. When I say my program tests that the ActiveX control fires a WidgetDispensed event at the right time, what I'm really doing is testing that the device tells the ActiveX control that it's dispensed the widget. I'm confident that the ActiveX control itself works OK; the device is the thing I'm testing.

orthogonality: "Well, it may be, but I haven't been arguing that."

Yes, I understand. I was mentioning that I'm stuck with C# in case anyone was planning on suggesting that I should use something else.

posted by matthewr at 7:26 PM on August 24, 2006


Ah, okay, that changes things then. Do you have access to debug symbols for these controls? If you do, you can just fire up whatever process sits there and listens for these events, attach the debugger, and then watch what happens.
posted by feloniousmonk at 7:33 PM on August 24, 2006


Response by poster: Hmm, feloniousmonk, not sure I understand your last comment. I'm pretty confident that creating instances of the ActiveX controls and using their methods and events is what I want to do.
posted by matthewr at 3:53 AM on August 25, 2006


Response by poster: orthogonality: Thanks, the code you supplied did exactly what I wanted.
posted by matthewr at 4:06 AM on August 25, 2006


« Older Gotta get me some immaculate contraception   |   Famous childless people Newer »
This thread is closed to new comments.