Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic cast of System.__ComObject

Is is possible to cast System.__ComObject to some type, which is known only at runtime? I have following code

Type ComClassType = SomeDLLAssembly.GetType("ClassName");
dynamic comClassInstance = icf2.CreateInstanceLic(null, null, ComClassType.GUID, "License string");
//This will throw exception, because comClassInstance type is __ComObject and it does not contains ComClassMethod
comClassInstance.ComClassMethod();

When I will use code bellow, it works fine, but unfortunately I cannot use InvokeMember in my code, because it would be very complicated.

ComClassType.InvokeMember("ComClassMethod", BindingFlags.InvokeMethod, null, comClassInstance, null);

So I would like to ask, if it is possible to cast "comClassInstance" to "ComClassType" in order to be able to call methods this way comClassInstance.ComClassMethod();

like image 333
Michal Kalous Avatar asked Oct 06 '14 11:10

Michal Kalous


2 Answers

which is known only at runtime?

That at least part of the problem. You can only use a cast when you know the type at compile time. You don't know so you can't write the cast expression. But it is deeper than that, you don't know the type at runtime either. __ComObject is the low-level wrapper for the RCW, it stores the IDispatch interface pointer. It says nothing about what methods you can call and what properties you can use.

This is a lower level of typing, it is dynamic typing. The general term for this is late binding. Which is a try-to-call-it-and-see-what-happens way of interfacing to code that another programmer wrote. The C# team resisted it for a very long time, static typing is core in the language, forcing programmers to use Reflection. But no more, by popular demand they added the dynamic keyword in v4, giving C# parity with Visual Basic which always supported it. Instead of passing strings to the Reflection methods you can now use symbols and the DLR automatically uses reflection to make the calls. Otherwise the exact same programming effort, you have to know the string.

The major advantage of late binding is that it is resilient to versioning, basic reason why 3rd party apis favor it. But also its major disadvantage, if you don't have a good manual or the version changed too much then you'll get a nasty runtime exception that doesn't tell you anything more than "it didn't work". The compiler cannot help you get it right, it doesn't know the type. IntelliSense cannot help you, it can't offer any auto-completion. Just a bang at runtime and the only way to figure out what went wrong is to plow through the (missing) manual or to talk to the programmer.

Many COM components support both early and late binding. You need a type library to use early binding, it is a machine-readable description of the interfaces and coclasses supported by the component. It is the exact equivalent of metadata in a .NET assembly. And performs the same role, with a type library the compiler can now check your code and IntelliSense can provide auto-completion.

Type libraries are usually embedded in the executable file (.dll or .exe), sometimes it is delivered as a separate file, .tlb and .olb are common extensions. You can use Visual Studio's File > Open > File to have a look inside the executable file, you'd see the TYPELIB node if the type library is embedded. You then can use OleView.exe, File > View Typelib command to have a look at its content. And run Tlbimp.exe to generate the interop library.

If you can't find the type library and don't have a decent up-to-date programming manual then only a telephone can help you. Call the owner or author of the component to get help.

like image 167
2 revs Avatar answered Oct 01 '22 08:10

2 revs


Casting is not required to call Method of COM Object.

C# dynamic can be used as (Writing a cast expression is not required before calling)

dynamic comClassInstance = Activator.CreateInstance(Type.GetTypeFromProgID("ClassName"));
comClassInstance.ComClassMethod();
var result = comClassInstance.ComClassFMethod(param);

OR

Create a Library project in vb.net (Option strict should be Off, Project properties). Do all COM related stuff in vb.net and add reference to this in your C# project.

Declare the instance type as Object.

Do a CreateObject call for COM component and call the methods as comClassInstance.ComClassMethod()

Public Class Abc
    Private _comClassInstance As Object

    Public Sub New()
        _comClassInstance = CreateObject("ClassName")
    End Sub

    Public Sub ComClassMethod()
        _comClassInstance.ComClassMethod()
    End Sub

    Public Function ComClassFMethod(param As String) As Integer
        Return _comClassInstance.ComClassFMethod(param)
    End Function 
End Class
like image 21
Sarvesh Mishra Avatar answered Oct 01 '22 09:10

Sarvesh Mishra