How to query interface of a COM object in C#, dynamically? - c#

I love using dynamic variables for accessing COM objects. However I have a problem with one object. See the following code working in VBS:
WScript.Echo "Nazwa firmy: " & itg.FirmaInfo.Nazwa
itg is a specific object that works basically equally well in vbscript and in c# using dynamic variables. Until I try to use the member FirmaInfo. Seems like it is a very special member which requires QueryInterface call. When I was accessing it through Jacob it was in this way:
static final String sIFirmaInfo = "{3F707848-DC7D-4B37-A4C8-7270644020F7}";
ActiveXComponent fi0 = itg.getPropertyAsComponent("firmainfo");
fi = new ActiveXComponent(fi0.QueryInterface(sIFirmaInfo));
fi0.safeRelease();
// now I am able access Nazwa member of fi
I can't find a way to do this in c#. When I do a simple approach:
Console.WriteLine(itg.FirmaInfo.Nazwa)
I get an error:
Unhandled Exception: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'System.__ComObject' does not contain a definition for 'Nazwa'
at CallSite.Target(Closure , CallSite , ComObject )
at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
at CallSite.Target(Closure , CallSite , Object )
at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
at Itg.open(String sKatFirmy, String sUser, String sPass) in w:\introl\prozapbi\Itg.cs:line 100
I know I could try a static client to COM object, but I am not familiar with this technique. Maybe I can stay with my dynamic approach, but need just a 3 suitable lines of code? Something that would turn my FirmaInfo object to one that exposes the IFirmaInfo interface.

I wasn't able to accomplish the task using dynamic. I present a workaround.
Switching myself to a static way of accessing a COM object turned out to be very easy and fast. It took a couple of minutes. Here's what I did:
set tlbimp="C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\TlbImp.exe"
%tlbimp% "C:\path_to_type_library\Mxfk2015_c.dll"
These commands produce a DLL. I analyzed the DLL using ilspy, but ildasm would do too. I needed exact names to use in code. Finally after adding a reference to the dll created by tlbimp, I could change the only invocation that was failing to a static cast.
dynamic itg = ...
var fi = (MXDokFK.FirmaInfo)itg.FirmaInfo;
So the thing started working and I could move on. I don't use GUI. All from command line.

Related

Cannot get PSVariable from Powershell Invoke method

I'm running C# PowerShell code on a remote system and need to get the value of a local variable. PowerShell has a cmdlet named Get-Variable which I'm trying to use. This is my code for trying to fetch the relevant collection of PSVariables (which obviously should contain just one):
psShell.AddScript($"$text = 'someValue'");
psShell.Invoke();
psShell.Commands.Clear();
psShell.AddCommand("Get-Variable")
.AddParameter("Name", "text");
var v = psShell.Invoke<PSVariable>();
Problem is on the last line, I get the following exception:
Cannot convert the "System.Management.Automation.PSVariable" value of type "Deserialized.System.Management.Automation.PSVariable" to type "System.Management.Automation.PSVariable".
Anyone know how to solve this ?
Also, I know of the SessionStateProxy method mentioned on StackOverflow, but as this post of mine shows, it doesn't work for my scenario for some reason.
When PowerShell remoting is involved, only a handful of well-known types deserialize with type fidelity, System.Management.Automation.PSVariable not being among them.
Instances of all other types deserialize as method-less emulations of the original objects, as [psobject] instances with properties containing static copies of the original property values.
In PowerShell, these instances report their type name as the original type name prefixed with Deserialized.
See this answer for background information.
The simplest way to handle such objects is via the DLR:
dynamic v = psShell.Invoke();
Then you can access properties as usual (albeit with runtime binding), e.g., v.Name.

Can't create object from string C#

I've scanned many topics on this site, searched the internet, and experimented with code and nothing has worked. Most people are using separate projects or assemblies which I am not, it's a custom class that exists in the same project and same namespace. If I build the object manually by hard coding it in it works fine but I don't want to do that.
It's a C# ASPX project and I am debugging on IIS from Visual Studio (so maybe that's the issue?).
Type type = Type.GetType("<namespace>."+classname);
Object obj = Activator.CreateInstance(type);
MethodInfo methodInfo = type.GetMethod(function);
response = (<cast object>)(methodInfo.Invoke(obj, null));
I am aiming for variable code where I can write plugins that will be dynamically instantiated. Type.GetType always returns null.
In almost all cases type returns null or when I switch it up with other code I'll get other errors thrown about not finding file or assembly and other errors like this class just doesn't exist...
What do I have to do to be able to build an object dynamically off a string? Let's say I have a class called "Foobar" and I want to do this,
string classname = "Foobar";
Object foobar = new classname(); //easy in PHP, nightmare in C#
Any help would be great, thanks. And before you tell me just to reference another post, I have referenced many and still have no success so if it's not the code than maybe it's how I'm debugging in a browser on IIS?
Type.GetType(String) accepts assembly-qualified type name.
See Type.AssemblyQualifiedName Property
You need to get the type from the assembly is was defined in:
typeof(SomeTypeInAssembly).Assembly.GetType("Namespace.Type")
If it is in the same namespace and assembly as the current object as you say, you should just be able to do the following to get hold of the Type you require:
Type type = Type.GetType(this.GetType().Namespace + "." + classname);
The rest should work as you have it.
Thanks for the suggestions, final code I ended up with below from the suggestions and other post I found on this site.
string fullname = string.Format("{0}.{1}", this.GetType().Namespace, classname);
Type type = Type.GetType(fullname,true);
Baseclass class = (BaseClass)Activator.CreateInstance(type,<parameter1>,...);
MethodInfo methodInfo = type.GetMethod("<method>");
methodInfo.Invoke(class, null);
You can store the return (may need casting) if you want to deal with the return type. Hope this helps someone if they're having issues like me.
Thanks to Rhumborl post, I guess it was an issue in just how I was originally trying to call the Type.GetType function.
String is a native type , witch is automatically inherited from object , since every type (aka class) is an object, so there is no need to do such a thing

How to use a COM-Wrapper?

Question:
I have to work (in VB.NET) with an application (Aperture)'s OLE automation via COM-Wrapper.
Currently, I switch off option strict, and do it like this (using late-binding):
Dim m_Aperture As Object = CreateObject("Aperture.Application")
Dim m_Project As Object = m_Aperture.Project
You see the problem, everything is an object, no intellisense, etc.
Very bad.
Since I want to get intellisense and and compile-time checking to work, I tried to automatically create a COM-wrapper like this:
"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\TlbImp.exe" OEAPP.TLB /out:Aperture.dll
So far worked splendidly, it created the wrapper, I can use intellisense on it (return types are all of type dynamic though).
So I tried to rewrite just the above sample code (now in C#):
First attempt was:
Aperture.OEAppClass app = new Aperture.OEAppClass();
But I got this compiler error:
Interop-Type Aperture.OEAppClass cannot be embedded. Use interface instead.
So i tried to do it via interface:
Aperture.OEApp Ap = (Aperture.OEApp)Microsoft.VisualBasic.Interaction.CreateObject("Aperture.Application");
That got me an exception at runtime
InvalidCastException
"System.__ComObject" cannot be converted into interface type "Aperture.OEApp".
0x80010105 (RPC_E_SERVERFAULT)).
So I tried to figure out the interface type using
dynamic Ap2 = Microsoft.VisualBasic.Interaction.CreateObject("Aperture.Application");
and object-inspector.
I found out the interface is actually of type Aperture._IOEApp.
So I used
Aperture._IOEApp Ap = (Aperture._IOEApp)Microsoft.VisualBasic.Interaction.CreateObject("Aperture.Application");
But now I get
InvalidCastException
"System.__ComObject" cannot be converted into interface type "Aperture._IOEApp".
0x80010105 (RPC_E_SERVERFAULT)).
Now I don't know what the problem could be anymore.
Can anybody tell me what I do wrong ?
Or how this is supposed to work ?

Calling method from COM Object using Reflection

In order to allow compatibility with another project that is written in .Net 2.0, we have had to come up with a COM interop (the newer application is in .Net 4.0). This would work because the 2.0 process would be able to use SxS execution with .Net 4.0. In order to have a COM interop from what I understand I have to do something like this:
Type myClass = Type.GetTypeFromProgID("Net4Assembly.Assembly4");
object myInstance = Activator.CreateInstance(myClass);
IAssembly4 assembly4Interface = (IAssembly4)myInstance;
assembly4Interface.CallMethod();
I have already created the COM component and registered it and this works fine. But the problem is that since the project written in 2.0 is outside our department, I want to find a way of doing the casting in line 3 above using reflection. So far I have found a suggestion in Invoke method using Reflection on COM Object
But this doesn't work for me since when I get all the methods of the object in "myInstance" which is of type COMObject, I can only see the methods that are mentioned in that link. I get this error:
Unknown name. (Exception from HRESULT: 0x80020006 (DISP_E_UNKNOWNNAME))
I think I should somehow cast the COMObject to the interface and then I would have access to the methods? Shouldn't I be able to extract the interface from the COMObject, then call the method using reflection? I tried GetInterfaces() from the COMObject but nothing is returned.
I am not sure if this will work but assuming you have No Misspelled Assembly Name try something like this
Type myClass = Type.GetTypeFromProgID("Net4Assembly.Assembly4");
object myInstance = Activator.CreateInstance(myClass );
//object[] arguments = new object[] //add parameters if youre assembly expects them here
object result = myClass .InvokeMember("SubtractTwoNumbers", BindingFlags.InvokeMethod,
null, myInstance, arguments);

How to use pointer from COM object on C#?

All.
I'm trying to use my old dll file on .net project.
So I converted this unmanaged COM object to managed one by using [tlbimp.exe] util from Windows SDK.
However, one method returns a Object as a return value, but whenever I try to use it,
my program generates an error.
The weird thing is below:
//Object[] item = s.GetObjects(); //this generates an type error
Object item = s.GetObjects(); //this works okay
System.WriteLine(items); //prints System.Object[] rather than System.Object.
It seems like it returns a pointer which contains an object array. Isn't it ?
Please anyone tell me how to handle this, and is there any documentation for this issue ?
Can you try with this ?
Object[] item = s.GetObjects() as Object[];

Categories

Resources