Pythonnet passing arguments to c# dll - c#

I'm using Pythonnet 2.4.0 to access a C# dll. I have a Windows 10 machine with Python 3.7.6.
I'm trying to use a method that only takes a path string as argument, but I don't manage to make it work.
import clr
sys.path.append(os.getcwd)
clr.AddReference('C#Wrapper')
path = "C:\\Users\\Username\\Folder"
c#class.method(string path)
If I use the overloads attribute from pythonnet, it tells me that the argument should be of type System.String, however doing something like below didn't help either:
path = System.String("C:\\Users\\Username\\Folder")
I keep getting a TypeError: No Method matches given arguments.
Do I need to encode the string or make a char array in order for c# to be able to understand it?
Edit:
I've just found a test function in the dll that only takes an Int32 argument and I have the same problem! I tried things like:
import ctypes
c#class.testmethod(ctypes.c_int32(1))
from System import Int32
c#class.testmethod(Int32(1))
but nothing worked. How can I pass arguments to the c# dll?
[Solved]:
I figured it out myself. In the second case I simply forgot to instantiate a class object. I should have done:
classobj = c#class()
classobj.testmethod(1)
This made me realize that in the first case I had basically the same issue. I followed a Visual Basic manual to write my Python program where it said something like this:
classobj = c#class
However in Python you need to write:
classobj = c#class()
So the missing parenthesis was causing the TypeError: No Method matches given arguments, which was very misleading. The type conversion and passing of arguments is perfectly handled thanks to the amazing developers of phythonnet! I won't delete this question in case other people experience the same issue.

The answer above is correct: Pythonnet passing arguments to c# dll.
I'd just like clarify what it means.
The error occurred because a method from a class was accessed without instantiating the object.
The solution is one of the two:
create an instance of the class
mark the .net method as static
The problem was that the error message is misleading, it says "No method matches given arguments". Which made me try to find the right argument.
By me this occurred when I forgot to add the static modifier to the .net method I called.

Related

Activator.CreateInstance alternative overloads in .Net Standard

I think I should be able to find something about this, but it seems I cannot.
I need to port a snippet of code that uses a missing overload of Activator.CreateInstance to .Net Standard 2.0.
string assembly = "My.Assembly";
string typeName = "My.Assembly.Something.MyType";
object newInstance = Activator.CreateInstance(assembly, typeName).Unwrap();
How could I replace this single line of code?
Please keep in mind that the assembly is not guaranteed to be loaded when the code is called.
Thanks!

Pass a callback function from Visual Basic to C#

I have a .dll written in C# and I use it in Visual Basic for making a Com object. I call C# functions from my Visual Basic code. I'm quite new to this technology and I encountered with such a problem. In C# code I have a method, that receives a callback function as a parameter, gets data from server then calls that callback function. Now I need to to call that function from my Visual Basic code and pass to it a callback.
I think it should look something like this
// C# dll
public bool GetDataFromServer(int someData1, Action<MyCustomType> callback, int someData2)
{
// request to server, get data, create an object of MyCustomType
// call callback and pass MyCustomType object to it as a parameter
}
// Visual Basic part
Public Sub DisplayData(ByRef resp As My_Dll.MyCustomType)
' do something with resp
End Sub
// call Dll method
My_Dll.GetDataFromServer(1, DisplayData, 2) ' I get a compile error
But I can't get it work, it event does not compile. I get a compilation error saying "Argument not optional". I've also tried to pass callback function with AddressOf, but I get an error again saying - "Invalid use of AddressOf operator".
Now my question is - what am I doing wrong? What is the correct way of passing a callback function from Visual Basic to C# and then get it invoked.
Thank you for your time!
Anything containing generics is not visible to COM, so your GetDataFromServer with Action<MyCustomType> is not COM visible. You must define a method on a non-generic class without generic type arguments of itself and without generic parameter or return types.
The usual way of passing a callback in COM is to pass an interface pointer with a method to be called. Avoid the AddressOf approach, however feasible, it's really bad practice once you want the callback to work out-of-process.
A common trick with IDispatch objects is to define a class with a default method with DispId 0 (DISPID_VALUE), which may be invoked by the COM server through IDispatch::Invoke. In some languages, such as JScript, objects may be callable through this technique.
To see how you can do this in VB6/VBA, search for VB_UserMemId. Essentially, you must edit the class file in its raw format (in VBA, you must export it) and add an attribute, such as:
Sub Call()
Attribute Call.VB_UserMemId = 0
End Sub
In VBA, you'd delete the class and import from the edited file. The effect is that the Call method now has DispId 0. You may call it whatever you want, but remember to edit both the Sub name and the Attribute.
In C#, I believe the only ways to achieve such call is with a dynamic variable with:
obj[0]
or through Type.InvokeMember or similar IDispatch::Invoke approaches:
obj.GetType().InvokeMember("", BindingFlags.InvokeMethod, null, obj, null);
The latter is more reliable and you pass the arguments you want, while the former uses a misleading syntax and forces you to pass an argument.
In general, if you control the whole situation and you don't need callable objects, just go for a plain method.
Regarding the AddressOf error, this operator works on module procedures and functions, so the error you see is probably because DisplayOptionQuotes is a method.

Invalid Procedure Call or Argument when passing Excel.Range from VBA to C# Library

I have a C# Class Library project in Visual Studio that I am using to extend the functionality of a VBA project.
I have made a COM accessible class that creates a TLB file on build; my VBA project references this TLB file.
I want to be able to pass an Excel.Range object from VBA to my C# class; however I keep receiving the 'Invalid Procedure Call or Argument' error and I don't understand why.
C# Method:
public void SetMetrics(Excel.Range MetricRange)
{
//Implementation
}
VBA Code:
ObjectName.SetMetrics (SheetName.Range("RangeName"))
Test Outcomes:
If I create an alternative method with no parameters or alternative types such as int, bool etc - it works fine. The error only seems to occur when I try to pass a Range.
If I make the VBA return a value form the method (see below), it works - even though the method is explicitly defined with void.
FunctionName = ClassName.SetMetrics (SheetName.Range("RangeName"))
If I have more than one Excel.Range parameter - VBA forces me to return a value even if I do not want too; but this also works.
I don't understand why I have these limitations - why do I have to return a value when passing objects to my library?
Thank you Rory - it was a VBA Syntax error:
Answer: "Remove the parentheses in the VBA, or use Call: Call"
Thank you for resolving this so quickly!
Best

Rewrite a method of a .Net DLL

I have an old .NET DLL which I have lost the source code to and I wanted to see if I could change its behavior.
It has a method that takes in a string and returns a string.
I would want to rewrite this method such that I can return
startStr + " test";
I tried .NET reflector but the project it produced has a bunch of strange errors so I cannot recompile it.
I then tried Reflexil, but it only offers assembly level changes.
Is there any way I could rewrite the method in C# and have the DLL use my method instead?
Reflexil should be able to handle this for you - you need to switch to IL view in Reflector and then you can go to the method that you want to change, pull up Reflexil and make your changes. This avoids the problems with decompiling the assembly to source code (which never worked for me without errors in Reflector).
If all you want to do is append a string to a string variable, you can just do something like:
// assuming your original string is already on the stack
ldstr " test"
call System.String System.String::Concat ( System.String, System.String )
This will create a new string on the stack with test appended to it. Once you're done with the editing, you can save the assembly back to disk.
If you need something more complicated (like appending a string returned by a function call), you simply need to call the right method and then call Concat() on the two strings on the stack.
If your original method returns a string then wrapping it in a new function in a new assembly may be a better solution, though. I'd only edit the IL if you really need the original assembly to change because - for example - the string returned from the particular method is used within that same assembly and you need other functions in that assembly to see the changed return value.
Note: I used Reflector 6.8.2.5 and Reflexil 1.0 for this - current Reflector / Reflexil may be different. Let me know if you need these files for your changes.
Have you tried extension methods? Simply add another method to an existing class.
You do this by:
public static class Foo {
public static String SomeMethod (this Bar bar) {
return bar.OriginalMethod()+" test";
}
}
If the original class was Bar.
I've never used .NET reflector, but you can try using the free decompiler offered by JetBrains, the makers of ReSharper, it has never failed me. http://www.jetbrains.com/decompiler/
On a side note, since you say that the dll is very old, couldn't the compilation errors in the Reflector generated project be produced by different versions of references or targeted framework?

Javascript error calling overloaded methods of a C# class

I'm writing a C# class library, and calling it from some Javascript code (technically Jscript.NET). I recently added some overloaded methods, and Javascript has trouble deciding which one to call, because it doesn't always know the types of its variables. I understand why this is happening in most cases, but I've got one example where I don't understand it.
Here are the overloaded method declarations in the C# class.
public virtual DeviceMessage RequestInUnits(
Command command,
int value,
UnitOfMeasure unit)
public virtual DeviceMessage RequestInUnits(
Command command,
Measurement measurement)
My application has a scripting feature that uses Jscript.NET. Here's some Javascript code that tries to call one of those methods on the C# class.
c.RequestInUnits(Command.MoveAbsolute, 0);
That's not a legal call, because the only method with two parameters expects a Measurement object as the second parameter. However, I would expect a type mismatch error. Instead, here's the compilation error I get.
More than one method or property matches this argument list at line 3 column 1
If I replace the 0 with "", then I get a type mismatch error. Why does Javascript think it can convert a number to an object? Why does it think it can coerce the types to more than one of those methods? Only one method takes two parameters.
This isn't a critical problem, but I don't like it when my library causes confusing error messages in calling code. I'd prefer to avoid that if I can.

Categories

Resources