Is there in C# connect to COM-object and use contents of com-object such as in the Builder c++:
CreateOleObject("some.someClass");
(OLE C # seems to be not supported, except OLEDb, but it is not the current case in my opinion)
I know I can add a link -> COM -> Seeking a registered com-object.
But it does not fit.
Normally, if you need to use a COM object in C#, you would add it as a Reference, and select the registered type library. That will generate an Interop Assembly, after which you can use the COM object just like any other C# class.
Alternatively, you can run the .NET utility tlbimp by hand, which has roughly the same effect but gives you slightly more control.
If you really need to create the object dynamically, without knowing anything about the type ahead of time, you can use the dynamic keyword and the Activator class to create a dynamic instance of a type. The code would look like:
var comType = Type.GetTypeFromProgID("some.someClass");
dynamic obj = Activator.CreateInstance(comType);
This will defer all type checking on obj until run-time, behaving much like VBA would.
Related
First, I realize that there are many posts here that discuss this topic. I must have read 20+ of them, easily. But none of them give the answer that I seek.
I have written a tiny C# test COM DLL with a single method in it that prints "I am alive!" in a message box. Using VStudio as admin, I can build and register the COM object. I have successfully called the object from VBA and run the method. And I can see the name of the COM Interface in the VStudio Add Reference / COM dialog box. This all makes me think the object is properly constructed, registered, and usable.
Now I'm trying to call it from a console C# app. Like many others, I'm trying to figure out the equivalent of the VBA "CreateObject("DLLName.ClassName")" code to get hold of the object in C#.
One way is to just add a reference to the DLL to my console app project. I point to the assembly through the Projects section of the Add Reference dialog, not through the COM section of the dialog. Then I can simply say var o = new MyComImplementationClass(); and treat it like any other class. That works, but it means my console app is cheating and not using the COM object through the usual COM GAC interface.
Another way (that doesn't work, but I wish it did), is to add the reference through the COM tab on the Add Reference dialog. I can see it but VS protests that "the XXX.tlb file was exported from a .NET assembly. Add a reference to the assembly instead." Which brings me back to the solution above, which I think means that my app is cheating. (I didn't have to add references to my VBA test app, for example.)
Another way is to use Type.GetTypeFromProgId as shown by this code fragment below. But I can't get that to work either. I must be passing in the incorrect ProgID string - I get the sense it has something to do with registry info and is not the same "DLLName.ClassName" string that I feed CreateObject() in VBA.
public static dynamic ComObjectGet () {
const string progID = "ComExampleDLLName.ComImplementationClassName";
Type foo = Type.GetTypeFromProgID (progID);
dynamic COMobject = Activator.CreateInstance (foo);
return COMobject;
}
Worse yet, on this MSDN example page it says "This method is provided for COM support. Program IDs are not used in Microsoft .NET Framework because they have been superseded by the concept of namespace." So probably I should not be using the GetTypeFromProgID at all.
If it helps any, I can use VSTO in C# to call the MSOffice primary interop assemblies. But they load from the COM tab of the add reference dialogs (which is where I want my COM library to load from).
For clarity, my COM DLL name is ComExampleLibrary.dll. The default namespace is ComExampleNamespace. The interface name is IComInterface, and the implementation classname is ComImplementation. The internal method name is Run.
Could someone give me instructions or a code snippet that does the "right, approved" thing for calling COM objects (not just the ones I write) from C#? Thank you.
Thanks to the people who helped me out, here is the answer. Both GetTypeFromProgID and GetTypeFromCLSID work as shown below. My problem was that I was using "AssemblyName.ClassName" instead of "Namespace.ClassName" in the call to GetTypeFromProgID.
public static dynamic ComObjectGet () {
const string progID = "ComExampleNamespace.ComImplementation";
Type foo = Type.GetTypeFromProgID (progID);
//var bar = Guid.Parse ("99929AA7-0334-4B2D-AC74-5E282A12D06C");
//Type foo = Type.GetTypeFromCLSID (bar);
dynamic COMobject = Activator.CreateInstance (foo);
return COMobject;
}
So my original code was correct, but I was passing in the wrong argument. This snippet is the equivalent of the VBA CreateObject("Namespace.ClassName") call.
I still don't know why I cannot add a reference to the COM item in the COM tab of the Add Reference dialog like I would for any other COM object. I suppose that's a different question.
I'm experimenting with COM objects and created a simple COM service that acts as a calculator with add, subtract, multiply, divide (details not important).
I then wrote some code to register it dynamically with a C# application
Assembly asm = Assembly.LoadFile("C:\\...COMCalc.dll");
RegistrationServices regAsm = new RegistrationServices();
bool bResult = regAsm.RegisterAssembly(asm, AssemblyRegistrationFlags.SetCodeBase);
After registering it I've been able to use the service from an IE browser in javascript.
var num1 = 2
var num2 = 2
var objTest = new ActiveXObject("COMCalc.COMCalc")
alert(num1 + " - " + num2 + " = " + objTest.Subtract(num1,num2))
I'd like to now be able to test it from my C# Application so I can have a register, unregister, and test method for my COM object. I've struggled to find the documentation for how to do this. Any Ideas?
Bonus: I also would like to access it with the GUID defined in the COM object as opposed to the COMCalc.
regAsm.RegisterAssembly(asm, AssemblyRegistrationFlags.SetCodeBase)
By writing your own custom registration method, you are missing out on the normal way that COM client programs or unit testers will exercise your code. They'll use the type library of your COM component, a machine-readable file that describes the types that you expose from your component. It is the COM equivalent of .NET metadata.
You get a type library by using the normal way to register, either by using your project's "Register for COM Interop" setting or by running Regasm.exe with the /tlb option. Or by running Tlbexp.exe to generate it manually.
This however does not let you test your component with a C# unit test, you'd normally use Project > Add Reference > Browse and pick the .tlb file. But the IDE refuses to accept it, it can see that the type library was created from a .NET assembly. It insists that you use a normal assembly reference instead, picking the DLL instead.
There's a very good reason for that. You can fool the IDE by using late binding but that does not fool the CLR. In other words, you are not actually testing the COM interop at all. You might as well use the normal way to add a .NET assembly reference. Truly testing the component requires using a COM client written in a non-.NET language. Not that many practical ones around anymore, you could use a scripting language like Javascript or VBScript. The closer it is to the actual language and runtime environment that is going to use your component, the better. If you are going to use it in a browser then something like Selenium or HtmlAgilityPack would be wise choice.
Nobody ever likes to hear advice like that. You fool the IDE by late binding, very similar to what you did in the browser:
Type type = Type.GetTypeFromProgID("COMCalc.COMCalc");
dynamic obj = Activator.CreateInstance(type);
dynamic result = obj.Subtract(2, 1);
I am trying to make a sort of proxy, and I am wondering whether COM methods and properties are static or dynamic. In other words, does .NET call the com object and tell it which method it wants executed, and then lets the com object pretend it has executed it (the way DynamicObject lets you do in .NET, just return true for TryInvokeMember without doing anything), or does .NET actually go and call the COM method directly (static)?
It sounds like you're asking the difference between early binding (static) and late binding (dynamic). C# supports both.
Early binding requires you create an Interop assembly using a tool like TlbImp.exe to generate a proxy to the COM object, which calls the interface methods directly.
To use late binding you can use either reflection (messy) or the dynamic keyword to bind the method calls at run-time.
However, the COM object will not "pretend" it executed a method you ask for - if the method does not exist, you will get a run-time exception.
I'm reading this book on C# and .NET and I'm learning a bunch of cool stuff. I've read the part where the author talks about dynamically loading an assembly and creating an instance of a type in that assembly.
In AS3, it's possible to do the same kind of stuff, except for one thing : you can ask the compiler to not compile a set of class, but to check for type safety. Here's an example :
//Defined in an external library
public class A {...}
//In my application, I tell the compiler to type check A, but not compile it
var a:A = new A();
a.whatever();
At runtime in my application code, I can dynamically load my external library containing the definition of class A, load those definitions into my application's ApplicationDomain and everything will run fine. No needs of reflection!
Is this possible in C#?
In other words, can I instruct the C# compiler to typecheck against a bunch of class (let's say, in a library) but exclude them from compilation?
I'm not 100% clear on what the as3 code is doing - but it sounds like you want to define a common interface (in a separate dll) that your external assembly can implement - and simply cast it when you create the object:
Type type = loadedAssembly.GetType(fullyQualifiedName);
IMyInterface obj = (IMyInterface)Activator.CreateInstance(type):
now you can use methods defined on obj easily.
Alternatively, in C# 4.0 the dynamic keyword provides duck-typing.
I just read this
Action Script is a dynamic language, it offers as a "special bonus" a type check feature, it helps you catch bugs at compile time, just like static typed languages do.
C# is a static-typed language, it does all its type checking at compile time. The type check is not an "added bonus" it's an integral feature. C# has always had the ability to late-bind using reflection and the feature is getting better with the new upcoming dynamic keyword.
However, if you use any of the late-binding features that C# has, you get no type checking.
I need to pass a Scripting.Dictionary between my C# app and another app. I would like to be able to create instances of and modify the dictionary in my C# app.
I know little about Scripting.Dictionary and ActiveX in general. Various forums suggest that I should use functions like System.Type.GetTypeFromProgID() and System.Activator.CreateInstance() to create an instance. Unfortunately this means that it's an opaque object to the rest of my code.
Is this really how it's supposed to be done or is there a better way? Ideally I'd like to import a compile-time type and just use it like any other type. Is this possible?
This article suggests I obtain a "metadata assembly" from the vendor - does anyone know if such an assembly exists for Scripting.Dictionary?
I've just tried the easiest approach, and it seems to work:
Add a COM reference to the scrrun.dll in Visual Studio (it should show up in the COM tab of the Add References dialog), and Visual Studio will automatically create the interop files for you. You can then write code like this:
Scripting.Dictionary d = new Scripting.DictionaryClass();
d.Add( ref myKey, ref myValue );
MyComType.Method( d );
If you have any trouble with that, I can post some more examples, or perhaps a clarification.
Create a wrapper dictionary class which implements IDictionary and which uses the Scripting.Dictionary as its internal storage implementation. Use the wrapper in your .NET code and pass the inner Scripting.Dictionary via COM to the other app.