Using ctypes in python to access a C# dll's methods

15,317

Solution 1

The tips you'll find regarding calling DLL from Python using ctypes rely most of the time to the DLL being written in C or C++, not C#. With C# you pull in the whole machinery of the CLR, and the symbols are most likely mangled and not what ctypes expect, and you'll get all sorts of troubles from the garbage collection of your output array.

I've had very good success when interfacing python and C# code by using python for dot net (http://pythonnet.sf.net), you may want to try this.

On the other hand if you are in for pure performance, consider rewriting your code as a native C extension for Python using the Python/C API (http://docs.python.org/c-api/).

Solution 2

It is actually pretty easy. Just use NuGet to add the "UnmanagedExports" package to your .Net project. See https://sites.google.com/site/robertgiesecke/Home/uploads/unmanagedexports for details.

You can then export directly, without having to do a COM layer. Here is the sample C# code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using RGiesecke.DllExport;

class Test
{
    [DllExport("add", CallingConvention = CallingConvention.Cdecl)]
    public static int TestExport(int left, int right)
    {
        return left + right;
    }
}

You can then load the dll and call the exposed methods in Python (works for 2.7)

import ctypes
a = ctypes.cdll.LoadLibrary(source)
a.add(3, 5)

Solution 3

Others have pointed out that a C# DLL cannot be treated the same way as a native DLL.

One option you have is to export your C# functionality as a COM object which can be readily consumed by Python.

Personally I'd consider a native code solution but you may well be too committed to C# to change course at this stage.

Solution 4

ctypes is for loading shared libraries written in C (or at least shared libraries that are directly executable by the CPU and export their symbols and function arguments following the standard C conventions.) C# DLLs are not "normal" DLLs, but rather intended to run in a .NET environment.

Your options are:

  1. Use some sort of Python to .NET bridge.
  2. Write the DLL in C and use ctypes to call the function and handle the data conversions.
  3. Use the Python/C API and create a loadable Python module.

I can't speak to option #1, I have not done it. Option #2 is typically easier than option #3 in that you write pure C code and glue it in with ctypes. Option #3 will offer the best performance of all three options in that it has the lowest call overhead and is running native code on the processor.

Solution 5

A C# DLL is really referred to as an Assembly so it is quite different. Unless there is a very important reason I suggest you use C++

Share:
15,317
Daniel Torramilans
Author by

Daniel Torramilans

Updated on June 18, 2022

Comments

  • Daniel Torramilans
    Daniel Torramilans almost 2 years

    I would like to implement C# code in a critical part of my python program to make it faster. It says (on Python documentation and this site) that you can load a Dynamic Link Library (and so say the PyDocs) as follows:

    cdll.LoadLibrary("your-dll-goes-here.dll")

    This is the part of my code that takes care of this feature:

    from ctypes import *
    z = [0.0,0.0]
    c = [LEFT+x*(RIGHT-LEFT)/self.size, UP+y*(DOWN-UP)/self.size]
    M = 2.0
    
    iterator = cdll.LoadLibrary("RECERCATOOLS.dll")
    
    array_result = iterator.Program.ITERATE(z[0],z[1],c[0],c[1],self.iterations,M)
    
    z = complex(array_result[0],array_result[1])
    c = complex(array_result[2],array_result[3])
    last_iteration = int(round(array_result[4]))
    

    And the RECERCATOOLS.dll that I use is this (C# code, not C or C++):

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using KarlsTools;
    
    public class Program
    {
        public static Array ITERATE(double z_r,double z_i,double c_r,
                            double c_i, int iterations, 
                            double limit)
        {
            Complex z = new Complex(z_r, z_i);
            Complex c = new Complex(c_r, c_i);
    
            for (double i = 1; Math.Round(i) <= iterations; i++)
            {
                z = Complex.Pow(z, 2) + c;
                if (Complex.Abs(z) < limit)
                {
                    double[] numbers = new double[] { Complex.Real(z),
                                                      Complex.Imag(z),
                                                      Complex.Real(c),
                                                      Complex.Imag(c),
                                                      i};
                    return numbers;
                }
            }
            double iter = iterations;
            double[] result = new double[]        { Complex.Real(z),
                                                      Complex.Imag(z),
                                                      Complex.Real(c),
                                                      Complex.Imag(c),
                                                      iter};
            return result;
        }
    }
    

    To build this DLL I use "Build" command over the Visual Studio 2010 project, which only contains this file and a reference to "Karlstools", a module that allows me to use complex numbers.

    I don't know why but when I try to run my Python code, it just throws an exception:

        [...]
        array_result = iterator.Program.ITERATE(z[0],z[1],c[0],c[1],self.iterations,M)
      File "C:\Python32\lib\ctypes\__init__.py", line 353, in __getattr__
        func = self.__getitem__(name)
      File "C:\Python32\lib\ctypes\__init__.py", line 358, in __getitem__
        func = self._FuncPtr((name_or_ordinal, self))
    AttributeError: function 'Program' not found
    

    I need help with this, since it keeps throwing me exceptions even with everything is set to public and the function as static, or even when if I try to access the function directly without specifying the "Program" class... I have no clue where the problem could be.

  • Ostap Elyashevskyy
    Ostap Elyashevskyy almost 9 years
    In case when library can not be executed from Python - small hint - "You have to set your platform target to either x86, ia64 or x64. AnyCPU assemblies cannot export functions."