TDLR
After researching and testing this problem more (see the update below), I reached this answer:
What I need is to actually pass an object by reference to a DLL created with Matlab using the type-safe API, but this does not seem to be possible. Correct?
I suspect that this is the direct result of them using WCF to facilitate interprocess behind the scenes as mentioned here. The fact that it is a DLL (which essentially handles the communication) confused me very much.
So is there a quick way to achieve this (e.g. COM objects come to mind, but I have not worked with them before)?
/TDLR
I am trying to figure out how to pass a .Net object to a Matlab method and then call a method on that object. In my Matlab Code I have something like this:
DOTNET_object = DOTNET_classFactory.GetStage();
CallDOTNET_class_method_DoSomething(DOTNET_object);
Where DOTNET_classFactory and DOTNET_object are both instances of .Net classes and CallDOTNET_class_method_DoSomething would be a Matlab function defined like this:
function CallDOTNET_class_method_DoSomething(DOTNET_object)
DOTNET_object.DoSomething();
end
I now need to perform the same two lines above in from within C#, after creating a DLL with the function CallDOTNET_class_method_DoSomething. However I am unable to figure out how to pass DOTNET_object to my function in the C# code. Here is what I have:
Class1 = new Class1();
Class1.CallDOTNET_class_method_DoSomething((MWArray) DOTNET_object);
I have found this answer , but I am not sure if this is the correct way to go. Would I have to package all the .Net objects (I will need to pass a total of 3 objects) I want to pass to my Matlab function inside an object-array and that unpack the within or is there a more elegant way, where I can pass the three objects separately and explicitely?
Update:
As explained here here I have now tried using the type-safe API in Matlab and by creating an interface to define the arguments of function CallDOTNET_class_method_DoSomething(DOTNET_object). I have been able to compile it in Visual Studio. Unfortunately, when I run the it I get the following exception:
Result StackTrace:
at MathWorks.MATLAB.NET.Arrays.MWArray.ConvertObjectToMWArray(Object objIn)
at MathWorks.MATLAB.NET.Utility.MWMCR.UnpackArgArray(Object[] argArray, Object[] varArgArray)
at MathWorks.MATLAB.NET.Utility.MWMCR.EvaluateFunctionForTypeSafeCall(String functionName, Int32 numArgsOut, Object[]& argsOut, Object[] argsIn, Object[] varArgsIn)
...
... removed, because it is confidential
...
Result Message: System.IO.InvalidDataException : Input data type unsupported by MATLAB .NET Assembly
From the message I deduce, that my endeavor is in vain and that you cannot pass anything other than primitive/value types (by that I mean, int, double, bool, etc.) to a Matlab DLL as written here here?
Result Message: System.IO.InvalidDataException : Input data type unsupported by MATLAB .NET Assembly
Am I correct in that assumption or is there any workaround?! In other words/another aspect: What I need is to actually pass an object by reference to the DLL created with Matlab and this does not seem to be possible. Correct?
Related
I'm working with one application that that has and C# API. This program has different versions of it. But the api stays the same through its versions.
So i have written a managed code to one of its versions, and now i want to run the same code at different version of the application at runtime where i exactly know witch version of the app is running.
Question is:
Is it possible to replace assembly version and dll location at run time without writing unmanaged code using reflections?
Yes, you can use Assembly.LoadFrom to load an assembly. You can then use reflection to go thru the types of said assembly and call methods.
To avoid needing to use reflection for everything there should be a shared interface-assembly that define your api. There should also be a single entry point to the API. So you can use reflection find the class that implements the entry-interface, create an instance of this class and cast it to the interface. That lets the rest of the code use actual types.
You still need to be careful however, if there is any miss match between the interface and the actual types, you will get an runtime exception. You will not get an exception when the interface method is called (as might be expected), but when the method that calls the interface method is called. This due to the jitter resolving types when a method is compiled, and this is done the first time it is called.
I built a very simple .dll in C# to call from a simple ColdFusion page. Everything works fine if I pass in literal values but as soon as I try and pass in a variable (#rollYear#) I get a message stating it can't find the method anymore.
The coldfusion page sets up my .dll like this:
<cfobject type="dotnet" name="getParcelData"
class="soapDLL.GetSecuredParcelByAPN"
assembly="{path}\soapdll.dll">
I then call it like this:
<cfset output = getParcelData.getData("46546504654","cy","#rollYear#")>
If I use the code above I get an error, "The getData method was not found.". If I replace the #rollYear# variable with a value (2017 for instance) then it works fine. In my tests I've set the #rollYear# variable via the CFSET function before I call the .dll.
I've been banging my head on this all day. Has anyone had similar experience? The .dll is very simple. It just takes 3 variables and based on those sets up what SOAP service to call to pull back some data. For reasons that are too complicated to explain I can't do the SOAP call from within ColdFusion, it has to go through a .net dll.
Any help would be appreciated, I don't have much hair left. :)
Whenever you work with Java or .NET components, you need to pay extra attention when passing ColdFusion variables/values to those methods. If the data types to not match exactly, you will encounter an error message telling you that the method does not exist or does not match the method signature.
ColdFusion offers javaCast() to explicitly cast to the required data type. Cast your arguments accordingly and it should work out in most cases.
Basic example:
A method that expects an integer will throw an error when you pass methodThatExpectsInt(123), because the 123 literal is internally stored as a string (or Double) by ColdFusion. By passing it via methodThatExpectsInt( javaCast("int", 123) ), the data type will be properly casted and match up.
I created a C# COM accessible dll that I want to consume in VB6
I was able to consume in VB6 my COM object with a hard reference to the TLB.
What I am trying to do now is to remove this reference and load it dynamically
I am creating it as follows:
Dim keylok As Object
Set keylok = CreateObject("MyClassLib.MyObject")
I get the Run-time error 424 "Object Required" once I hit the second line.
But when I create it as follows:
Dim keylok As MyObject
Set keylok = CreateObject("MyClassLib.MyObject")
It works fine.
I am not sure why would that make a difference. Anyway I cannot use the second one because I would still need to have the physical reference.
I tried also as a sort of debugging to write to file in my COM object constructor to if it really gets called. And yes it does, I'm even able to call other methods in my COM object sucessfully inside the constructor.
I was even able to load dynamically and consume it from another C# app using:
dynamic myObj = Activator.CreateInstance(Type.GetTypeFromProgID("MyClassLib.MyObject"));
Did any one encounter something like that before?
I found the solution with the help of #rskar input. So, I thought I'm gonna answer my question, in case any one faces the same problem.
My object didn't impelement IDsipatch. So all I had to do it to decorate my C# COM interface with InterfaceType(ComInterfaceType.InterfaceIsDual) So it implements both IUnknown and IDispatch.
Originally it was decorated with InterfaceType(ComInterfaceType.InterfaceIsIUnknown)
I think you are going to require the .tlb anyway. COM objects need to be capable of being marshalled as the .Net hosting runs on a different thread to the VB6 runtime. The default marshalling uses information from the typelibrary to do this. IDIspatch has 4 methods and 2 of these are to do with accessing type information. So possibly if you removed the .tlb, when you create the IDispatch COM attempts to call up the ITypeInfo from this and dies failing to load the registered typelibrary. If you eliminate the .tlb you will become unable to be marshalled and likely you would have to provide a custom marshaller for your interface.
I don't know much about Com Plus Interop services in .NET - I let .NET do all the dirty work and I cross my fingers it'll work. Well, now I'm stuck.
I've got a reference to a COM DLL compiled with VB6 in my VS 2010 C# program. This is an invoice I'm creating.
I instantiate an object:
UIInvoice Invoice = new CUIInvoice();
And then I set some invoice header properties:
Invoice.set_InvoiceType("VO");
Invoice.set_InvoiceTypeID(2);
And now, I want to create some invoice detail lines, which I do by calling the add method of a child object of the invoice:
Invoice.InvoiceDetails.Add("StringParam1", "StringParam2", Invoice);
The third parameter of the function call is defined in my VB6 Add function as:
ByRef Parent As Object
When I run my .NET program, I get a "type mismatch" error when I hit the Add line.
Can anyone suggest, in simplistic terms, a way I can get this to work?
My recommendation would be to not fool around with COM, but migrate the VB6 code to Visual Basic.NET. You'll have much less problems marshalling objects back and forth with C#. If this object is shared with other legacy applications, you may be able to create a COM wrapper that maintains your legacy compatibility as well. Obviously you need to weigh this against your business requirements.
If you own the VB6 source then I suggest changing the definition of Add to be ByVal instead of ByRef. There is almost never a reason to use ByRef object references in VB6, and from the tiny bit I am gleaning from your code, you don't need to to associate paranet/child relationships in your domain objects.
The API documents describe the method as such:
boolean MethodName(VARIANT* par)
The parameter is a ref type which returns an error code.
How do I call this method using c# 4.0's new features?
Just use the old way, there's nothing in 4.0 that makes this method any easier to use. Add a reference to the COM type library, usually the DLL itself, and you should get a class with the method bool MethodName(ref object). What you are supposed to do with the object is completely unclear from your question. Check the API manual, get help from the component vendor.