非托管导出,将字符串数组从C ++传递到C#

时间:2015-09-03 09:47:39

标签: c# c++ c c#-4.0 interop

我正在使用Robert Giesecke's Unmanaged Exports包来从C ++调用C#。 这必须使用C ++中的C接口。我已经设法通过搜索网络并在这里和那里拾取数据来使大多数工作正常工作....

extern "C"
{
    //  Simple
    __declspec(dllimport) int IntTest(int input);
    __declspec(dllimport) double DoubleTest(double input);

    //  Array of simple types in
    __declspec(dllimport) int passArray(int t[], int i, int xx);

    //  String in and out
    __declspec(dllimport) int PassStringIn(wchar_t* str);
    __declspec(dllimport) int PassStringOut(wchar_t** str);
    __declspec(dllimport) wchar_t* PassStringInOut(wchar_t* str);

    //  Array of strings types in
    //__declspec(dllimport) int passArrayStrings(char** t, int i);
}

...

//  Int in and out
int aa = IntTest(4);

//  Double in and out
double bb = DoubleTest(4.3);

//  Pass array in
int arr[4] = { 1,2,3,4 };
int cc = passArray(arr, 4, 0);

//  String in
wchar_t* a_str = L"input string from C++";
int dd = PassStringIn(a_str);

//  String out
wchar_t* b_str = L"not used";
int ee = PassStringOut(&b_str);

//  String in & out
wchar_t* d_str = L"bob";
wchar_t* result = PassStringInOut(d_str);

相应的C#

    [DllExport( CallingConvention = CallingConvention.Cdecl)]
    static int IntTest(int input)
    {
        return input + 1;
    }

    [DllExport(CallingConvention = CallingConvention.Cdecl)]
    static double DoubleTest(double input)
    {
        return input + 1;
    }

    [DllExport(CallingConvention = CallingConvention.Cdecl)]
    public static int passArray([In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]  int[] tab, int i, int x)
    {
        return tab[x];
    }

    [DllExport(CallingConvention = CallingConvention.Cdecl)]
    public static int PassStringIn( [MarshalAs(UnmanagedType.LPWStr)] string inputString)
    {
        Console.WriteLine("Hi, the string passed in was :" + inputString);
        return 1;
    }

    [DllExport(CallingConvention = CallingConvention.Cdecl)]
    static int PassStringOut([MarshalAs(UnmanagedType.BStr)] out string outputString)
    {
        Console.WriteLine("Hi, I will return the time from c#");
        outputString = DateTime.Now.ToLongTimeString();
        return 0; // indicates success
    }

    [DllExport(CallingConvention = CallingConvention.Cdecl)]
    [return: MarshalAs(UnmanagedType.LPTStr)]
    public static string PassStringInOut([MarshalAs(UnmanagedType.LPTStr)]string name)
    {
        return string.Format("Hello from .NET assembly, {0}!", name);
    }

Which was nice!无论如何,任何人都可以帮助传入和传出字符串数组。我很确定C#部分应该是这样的:

    [DllExport(CallingConvention = CallingConvention.Cdecl)]
    public static int passArrayStrings( [In, Out, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr, SizeParamIndex = 1)]  string[] tab, int i)
    {

        return 1;
    }

我需要在C ++(C)方面提供一些关于如何构造字符串数组的帮助,以便它们可以正确编组。创建的混合模式程序集同时具有C#和C接口。因为它是C而不是C ++,所以暴露函数的参数类型是不可见的。

Dependency Walker

由于

2 个答案:

答案 0 :(得分:3)

您可以使用IntPtr参数。

您必须分配非托管内存并将数组复制到该blob中。否则GC会在某个时刻吃掉你的阵列。

Unmanaged Exports with Arrays

答案 1 :(得分:2)

好的,所以在经历了很多混乱之后,我找到了一个解决方案:

//  Array of strings types in
__declspec(dllimport) int passArrayStrings(BSTR* bstrArray, int i);

BSTR bstrArray[10] = { 0 };
for (int i = 0; i < 10; i++)
{
    bstrArray[i] = ::SysAllocString(L"My String.");
}
int ff = passArrayStrings(bstrArray, 10);
for (int i = 0; i < 10; i++)
{
    ::SysFreeString(bstrArray[i]);
}

并在c#侧:

    [DllExport(CallingConvention = CallingConvention.Cdecl)]
    public static int passArrayStrings([In, Out, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.BStr, SizeParamIndex = 1)]  string[] tab, int iSize)
    {
        return 1;
    }