10

This may be a red herring, but my non-array version looks like this:

C#

using RGiesecke.DllExport;
using System.Runtime.InteropServices;

namespace Blah
{
    public static class Program
    {
        [DllExport("printstring", CallingConvention = CallingConvention.Cdecl)]
        [return: MarshalAs(UnmanagedType.AnsiBStr)]
        public static string PrintString()
        {
            return "Hello world";
        }
    }
}

Python

import ctypes
dll = ctypes.cdll.LoadLibrary(“test.dll")
dll.printstring.restype = ctypes.c_char_p
dll.printstring()

I am looking for a printstrings, which would fetch a List<string> of variable size. If that's not possible, I will settle for a fixed-length string[].

3
  • You certainly can't return a List<string>. You could use an array of strings parameter as demonstrated here: stackoverflow.com/questions/26277322/… (but it's more difficult with strings as they are of variable size and need to be allocated on .net side and freed on python side). Otherwise, you could use COM with automation types (instead of DllExport) which could probably be easier (it would be wrapped more automatically). Commented Jan 25, 2018 at 7:31
  • For the bounty, I would like to have the code handed to me on a plate ;) Commented Jan 27, 2018 at 1:20
  • @DimitriShvorob pythonnet has partial support for .NET collections, including List Commented Jan 28, 2018 at 2:03

1 Answer 1

9
+50

.NET is capable of transforming the object type into COM Automation's VARIANT and the reverse, when going through the p/invoke layer.

VARIANT is declared in python's automation.py that comes with comtypes.

What's cool with the VARIANT is it's a wrapper that can hold many things, including arrays of many things.

With that in mind, you can declare you .NET C# code like this:

[DllExport("printstrings", CallingConvention = CallingConvention.Cdecl)]
public static void PrintStrings(ref object obj)
{
    obj = new string[] { "hello", "world" };
}

And use it like this in python:

import ctypes
from ctypes import *
from comtypes.automation import VARIANT

dll = ctypes.cdll.LoadLibrary("test")
dll.printstrings.argtypes = [POINTER(VARIANT)]
v = VARIANT()
dll.printstrings(v)
for x in v.value:
  print(x)
Sign up to request clarification or add additional context in comments.

4 Comments

Thank you. How about a printStrings that takes an argument? Say printStrings(string separator, ref object obj)?
@DimitriShvorob - yep, just add an argument to C# and an argument to argtypes (this is just a regular python array, enclosed in [ ])
How to substitute comtypes in Linux? In the example I have an error because comtypes is not supported on Linux. I tried use this on Linux, but VARIANT exists only in comtypes.
@ÊnioRodrigues - comtypes and VARIANT are Windows only. On non-Windows platform, you cannot marshal object like that, see: learn.microsoft.com/en-us/dotnet/standard/native-interop/… and learn.microsoft.com/en-us/dotnet/standard/native-interop/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.