How to import a C# dll to python - c#

i've got a third party c# dll which has been created in dot net 4.5 and has a platform target of x86. I would like to import this into a python script and I've started off with Rob Deary's answer here. However I can't get his example to work. I'm using python version 2.7.6 and I get an AttributeError as shown below.
File "C:\Python27\Lib\ctypes\__init__.py", line 378, in __getattr__
func = self.__getitem__(name)
File "C:\Python27\Lib\ctypes\__init__.py", line 383, in __getitem__
func = self._FuncPtr((name_or_ordinal, self))
AttributeError: function 'add' not found
Please note that I am aware of Ironpython and Python for dot net but I need to get this working specifically with C python. Here's my sample code which generates the custom c# library: ClassLibrary1.dll
using System;
using System.Runtime.InteropServices;
using RGiesecke.DllExport;
class Test
{
[DllExport("add", CallingConvention = CallingConvention.Cdecl)]
public static int TestExport(int a, int b)
{
return a + b;
}
}
And here's the python script that generates the error
import ctypes
lib = ctypes.cdll.LoadLibrary('ClassLibrary1.dll')
lib.add(3,5)
When I use the line below, this is the output i get. So at least I know that it is loading the dll, but i'm not sure why the function can't be found.
>>> lib.__dict__
{'_FuncPtr': <class 'ctypes._FuncPtr'>, '_handle': 254476288, '_name': 'ClassLibrary1.dll'}
>>>
Any help will be appreciated. Thanks

As the RGiesecke.DllExport documentation states, you need to target a specific architecture (x86 or x64) when building your code. Leaving it set to Any CPU (the default) will not work.

Related

DllImport for Dotnet core returning DLLNotFoundException for present DLL

Over the past few days I have been trying to interface with a C library (built for an ARM platform) on linux, in dotnet core. All I am trying to do is call a simple function which (essentially) returns a string.
However, I have no experience of using DLLImport or interop on the whole in C# and I am struggling.
The C code looks like (with substitute names as I am using a work platform):
int version(int argc, char *argv[])
{
return READ_DATA(0,
version, //callbackfunction
"version: 0x%04x\n"); //formatting string
}
public class Board
{
private Interop_Commands _commands = new Interop_Commands();
public string GetVersion()
{
return _commands.GetVersion();
}
}
internal class Interop_Commands
{
public const string LIBRARYPATH = "libname";
[DllImport(LIBRARYPATH,CharSet=CharSet.Unicode, CallingConvention =CallingConvention.Cdecl)]
public static extern int version(int argc, StringBuilder argv);
public string GetVersion()
{
var sb = new StringBuilder();
Console.WriteLine($"Calling {nameof(version)}");
version(0, sb);
Console.WriteLine($"Called {nameof(version)}, got: {sb.ToString()}");
return sb.ToString();
}
}
with the calling class (main for this very simple proof of concept/trial code):
static void Main(string[] args)
{
Console.WriteLine("Getting Version from board..");
var board = new Board();
Console.WriteLine(board.GetVersion());
Console.WriteLine("done");
Console.ReadLine();
}
The folder structure is (simplified):
folder
|--> Dll/runtime
|--> libname (note no .so here, just libname)
Any help would be appreciated, I am finding examples of C imports/usages limited, and also finding examples limited for how to use custom libraries in dotnet core.
EDIT 1:
Following help from #Sohaib Jundi, I have added the extern so the signature is now: (it wouldnt compile with extern "C")
extern int version(int argc, char *argv[])
I am unsure what to try next.
but dotnet core wont publish with x86 and target runtime set to linux-arm, just throws an unknown exception, with the log file not being very helpful..
If i use the compiled library with the previous code (AnyCPU + linux-arm), then the DllNotFoundException is still thrown
* EDIT 2: *
As it turns out, the original no extension file i was using appears to be an executable referencing a static library (which ends up compiled into the executable). rebuilding I have managed to get the static library separate, but still get the same DllNotFoundException. Does anyone know what the search procedure is for the DllImport on dotnet core?
The interop/import code now looks like:
[DllImport("libname",
CallingConvention =CallingConvention.Cdecl,
EntryPoint= "version")]
public static extern int version(ref uint val);
where the static lib code looks like:
extern int version(uint32_t *);
After some playing around, I managed to get an example to work.
Follow these steps:
1. export your function from the dll, i.e: add extern "C" __declspec(dllexport) to the function signature
2. Make sure that both the dll and your dotnet core application have the same architecture. don't keep the dotnet core as "Any CPU", force it to the same architecture as the dll. (project properties -> build -> platform target = x86 or x64)
I have found the solution.. the library was being compiled as a .la (statically linked library) rather than a .so (shared object) library. The DllImport doesnt work with statically linked libraries so.. a recompilation of the library into a shared object library has meant it will now find the dll (I also exported LD_LIBRARY_PATH as pwd to make sure it was in the search path..).
Once this was in, the rest of the code fell into place. The matching dll import declaration for the version above was correct (from *EDIT 2 *) - using ref uint. So now I have to extend the methods supported in my interop class to fully support the library.
Thanks for your help #Sohaib Jundi

How to create a C# functions DLL and then use this functions in C?

I'm trying to create a DLL exposing some static functions to use then in C.
Recently I read an article of Microsoft named "An Overview of Managed/Unmanaged Code Interoperability" and in this there is no a clear explanation on how to "Exposing a Managed API as a Flat API".
I installed this plugin to Visual Studio (https://www.nuget.org/packages/UnmanagedExports) but I still can't compile a project in C.
My C# project exposes a function like this:
using RGiesecke.DllExport;
using System.Runtime.InteropServices;
namespace libcallcstest
{
public class Class1
{
[DllExport("add", CallingConvention = CallingConvention.Cdecl)]
public static int add(int a, int b)
{
return a + b;
}
}
}
After building project, result these three files:
libcallcstest.dll
libcallcstest.pdb
libcallcstest.tlb
My C code is:
#include <stdio.h>
#include <stdlib.h>
int add(int, int);
int main(int argc, char** argv) {
int z = add(2,5);
printf("%d\n", z);
return (EXIT_SUCCESS);
}
And finally when I try to compile this file with:
gcc -o main.exe main.c -lcallcstest
Not work properly, files created by building the C# project are in the same folder as the main.c file.
Pleas any help!!!
One way to go: you may want to host CLR in your process. I would recommend against it though, because hosting is not the easiest procedure out there.
Also it's often not really needed or you can use some slower methods to communicate with .Net code from unmanaged environment (for example, present your library as a local server and access it through network interfaces. As I see it that way you'll have ten times less work to do).
Or you could go with your original variant using utilities to help you like mentioned here.

Java JNI call to C# COM fails, when COM is registered without codebase option of regasm

Function calls from Java to C# through JNI-C++/CLI are failing when the C# COM is not registered using regasm with the codebase option. I've built a sample following the instructions in P2: Calling C# from Java with some changes.
Numero uno: C#
Change the C# dll into a COM by creating an interface, IRunner, and making the library assembly COM-visible.
namespace RunnerCOM
{
public interface IRunner
{
String ping();
}
public class Runner:IRunner
{
static void Main(string[] args)
{
}
public Runner() { }
public String ping()
{
return "Alive (C#)";
}
}
}
Numero due: Java
No changes made to the Java section.
Numero tre: C++
This part was changed to create a new instance of the RunnerCOM.Runner class and use that result. Here is a good tutorial on how to call managed code from unmanaged code: http://support.microsoft.com/kb/828736
#include "stdafx.h"
#include "Runner.h"
#pragma once
#using <mscorlib.dll>
#import "RunnerCOM.tlb"
JNIEXPORT jstring JNICALL Java_Runner_ping(JNIEnv *env, jobject obj){
RunnerCOM::IRunnerPtr t = RunnerCOM::IRunnerPtr("RunnerCOM.Runner");
BSTR ping = t->ping();
_bstr_t temp(ping, true);
char cap[128];
for(unsigned int i=0;i<temp.length();i++){
cap[i] = (char)ping[i];
}
return env->NewStringUTF(cap);
}
Now to my questions,
The code above fails with a _com_error exception, Class not registered (0x80040154) unless the codebase option is enabled during regsitration of RunnerCOM.dll, with regasm.exe. Why is this? If the code is not ran from JNI, I tested it as an exe, it works fine. The RunnerCOM.dll is simply found in the working directory.
Type casting _bstr_t temp to char* fails. For example, char *out = (char*) temp; Similar to the issue above, it works fine when it's built and executed as an exe but crashes the JVM when it's a JNI call.
By the way this is what I used to run it as an executable:
int main(){
RunnerCOM::IRunnerPtr t = RunnerCOM::IRunnerPtr("RunnerCOM.Runner");
BSTR ping = t->ping();
_bstr_t temp(ping, false);
printf(temp);
return 0;
}
Codebase creates a Codebase entry in the registry. The Codebase entry specifies the file path for an assembly that is not installed in the global assembly cache, so when you specify the codebase, the system will find the DLL based on the path. If not, it will try to locate the dll in the GAC and current working directory. In JNI, I think the current working directory is not the folder where the DLL is. You can use process explorer to find what is the current working directory, also, you can use process monitor to find out which directories the exe is looking into to find the dll.
The code converting _bstr_t to char*, the char* string cap is not ended with '\0', I think this might cause problem in JNI. Uses the _bstr_t operator (char *), you can obtain a null terminated string from the _bstr_t object. Please check the msdn example for details.
You mentioned C++/CLI, C++/Cli and COM warpper are two different ways to interop with C# code. If you're using C++/CLI as a bridge, you doesn't need to register C# DLL as COM, please see this: Calling .Net Dlls from Java code without using regasm.
If you're using COM, you should call CoInitialize() to init COM first in your code.

How Call the function from .dll using c# program

I tried to call the function from .dll file using java native interface ,its successfully working, But I don't know how to call function from .dll using C# ,please advice me on this.
Look at DLLImport attribute in MSDN
http://msdn.microsoft.com/en-us/library/aa664436(v=vs.71).aspx
using System;
using System.Runtime.InteropServices;
class Example
{
[DllImport("your_dll_here.dll")]
static extern int SomeFuncion1(int parm);
static void Main()
{
int result = SomeFunction1(10);
}
}
If it's a native DLL, you need to add a DLLImport statement, importing the function you want.
The documentation is here.
The attribute looks like this, typically:
[DllImport("YourDllNameHere.dll")]
public static extern int YourFunction(int input);
This will import a function called YourFunction (which takes an int input, and returns an int) from YourDllNameHere.dll.
Let's say your DLL name is MyLibrary and MyFunction is the function contain in your DLL .
First right click on your Reference , browse and add your DLL .
Declare your DLL as a namespace using MyLibrary;
And you can call MyFunction !
Or
Another way ,
you can use this msdn reference !
Add that dll into your project as a referenced dll into reference folder(right click on references ,add reference then "Browse" to you DLL).then it should be available for to use as you want and just use that dll as follows in the code level.
using System;
using YourDllName;
class ExampleClass
{
//you can use your dll functions
}
I like the link provided by Baldrick for DllImport attribute.
This is what I recommend.
Download Dependency Walker (small application exe, no need to install).
Open your DLL in the Dependecy Walker to view the exposed entry points of DLL.
Declare external call to native function in C# like this.
C#:
[DllImport("Your_DLL.DLL", EntryPoint="Function_Entry_Point",CallingConvention=CallingConvention.StdCall)]
static extern IntPtr Function1();
Note:
If entry point is not specified the function name is considered as the entry point.
When you run the application make sure the native DLL is in the
same folder.

How to invoke C#/.NET namespace in IronPython?

I'm looking to replicate the following in IronPython and searching has so far been fruitless and/or disappointing.
namespace Groceries
{
public class ChocolateMilk : Milk
{
// Other stuff here
}
}
The idea would be that the compiled Python DLL will be loaded into a C# program through System.Reflection.Assembly.Load and a GetType("Groceries.ChocolateMilk") on the loaded DLL would not return null.
The most recent answer I was able to find was in 2008 and said that it was impossible without using the Hosting API - http://lists.ironpython.com/pipermail/users-ironpython.com/2008-October/008684.html.
Any suggestions on how to accomplish this would be greatly appreciated. Any conclusions that this is currently impossible to do via IronPython will also be appreciated, but less so.
I'm a bit confused on what you're asking here. Are you trying to instantiate that C# code in your IronPython modules? Or do you have the equivalent classes written in IronPython and you want to instantiate them in your C# code?
Based on the link you posted, I suppose you're going for the latter and have IronPython classes that you want instantiated in your C# code. The answer is, you cannot directly instantiate them. When you compile IronPython code to an assembly, you cannot use the types defined there with your regular .NET code since there is not a one-to-one mapping between IronPython classes and .NET classes. You would have to host the assembly in your C# project and instantiate it that way.
Consider this module, Groceries.py compiled to Groceries.dll residing in the working directory:
class Milk(object):
def __repr__(self):
return 'Milk()'
class ChocolateMilk(Milk):
def __repr__(self):
return 'ChocolateMilk()'
To host the module in your C# code:
using System;
using IronPython.Hosting;
using System.IO;
using System.Reflection;
class Program
{
static void Main(string[] args)
{
var engine = Python.CreateEngine();
var groceriesPath = Path.GetFullPath(#"Groceries.dll");
var groceriesAsm = Assembly.LoadFile(groceriesPath);
engine.Runtime.LoadAssembly(groceriesAsm);
dynamic groceries = engine.ImportModule("Groceries");
dynamic milk = groceries.ChocolateMilk();
Console.WriteLine(milk.__repr__()); // "ChocolateMilk()"
}
}
Otherwise to go the other way and create an instance of your .NET type in your IronPython code (as your title suggests). You'd need to add the path to your assembly, reference it, then you could instantiate it as needed.
# add to path
import sys
sys.path.append(r'C:\path\to\assembly\dir')
# reference the assembly
import clr
clr.AddReferenceToFile(r'Groceries.dll')
from Groceries import *
chocolate = ChocolateMilk()
print(chocolate)

Categories

Resources