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[];
Related
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.
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
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);
I am trying to return an array from c# to classic asp using com. This post helped me lot, but I still have problems:
I have the following method in c#:
public object[] returnStuff () {
return new object[] {'1','2','3'};
}
My classic ASP:
dim responseArray1
responseArray1 = RegusSoapComponent.returnStuff()
response.write("Type of Array one is " & VarType(responseArray1))
response.write("Type of Array one is " & responseArray1(1))
My output is:
response is Type of Array one is 8204
Microsoft VBScript runtime error '800a01ca'
Variable uses an Automation type not supported in VBScript
No matter what I do, I don't seem to be able to access this variable.
VBScript likes to receive a variant containing a safearray of variants. So you need to return an object wrapping your array of objects. eg:
public object returnStuff() {
return new object[] {'1','2','3'};
}
which should get marshalled the right way. See a previous answer for the detailed version.
I do C# excel interop. I call macros from C#, and I expect arrays of objects. I'm able to get 2-dimensional arrays of objects from the macros which returns 2-dimensional arrays.
However, an other (third party) macro is supposed to return a one-dimensional array. I can't get the (object[])xlApp.Run(...) working (it throws an exception), and the type info in the debugger says the result is of type Object[*]. The actual message from the exception is
Unable to cast object of type 'System.Object[*]' to type 'System.Object[]'.
What is this Object[*] type and how do I retrieve a one-dimensional array from this ?
EDIT: It occurred to me that this could mean a SAFEARRAY of VARIANTS. But then, two questions arise: why is everything ok with 2-dimensional arrays ? How do I convert a SAFEARRAY to a C# array ?
I foulnd various articles about your problem :
OPCFondation : Basically instead of declaring it as an array of objects, you can just declare it as an Array without providing any element type. So do not cast in Object[] but Array, and use a foreach loop to use the subarray.
foreach(object subobject in (Array)myarrayitem)
{
//do stuff with the subobject, even browse further
}
This solution seems to work since you can find it again here.
On StackOverflow : they speak about arrays with lower bound > 0, which gives you the Object[*] type, with some links that can be interesting about the subject, but I think the first idea is the good one.
Use
System.Array a = (System.Array)((object) returnedObject );
This was such a PITA. I had this code in two projects:
Workbook wb = null;
try
{
wb = excel.Workbooks.Open(filePath, false, true, 5, null, "WrongPAssword");
}
catch
{
return false;
}
try
{
Array links = (Array)wb.LinkSources(XlLink.xlExcelLinks);
if (links != null)
{
One worked the other did not. The Difference. Working one was targeting .Net 2.0 and other one was .Net 4.0 that was giving the error:
Unable to cast object of type 'System.Object[*]' to type
'System.Object[]'.
Turns out if you change the Visual Studio version of this article from VS2005 to VS2010 the LinkSources datatype changes.
MSDN Workbook.LinkSources Method
VS2010:
Object LinkSources(
Object Type
)
VS2005:
public virtual Object LinkSources (
[OptionalAttribute] Object Type
)