如何在C ++中调用一个从C#返回字符串的函数?

时间:2015-06-10 11:59:52

标签: c# c++ .net

我在C ++中有以下函数,我想用C#调用:

loadError

我如何做到这一点(使用Pinvoke)?

我是否正确假设从C ++到C#的返回分配内存有问题,并且在C#中分配大字符串然后将其传递给C ++以进行写入会更好(更容易)?

在这种情况下,我想我应该用C?包装C ++函数:

std::string getString();

2 个答案:

答案 0 :(得分:4)

这样做的经典方法是:

__declspec(dllexport) void get_string(int size, char *buffer)
{
    std::string str = getString();
    strncpy(buffer, str.c_str(), size);
    buffer[size - 1] = '\0';
} 

C#方:

[DllImport("NativeLibrary", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern void get_string(int len, [Out] StringBuilder sb);

然后(非常重要!你必须预先调整StringBuilder

var sb = new StringBuilder(100);
get_string(sb.Capacity, sb);
string str = sb.ToString();

您可以使用char[],但它更复杂,因为您必须手动“修剪”\0

使用更少的内存副本有一种更复杂的方法...但它有点复杂:

C ++方面:

__declspec(dllexport) void get_string(void (*func)(const char*))
{
    std::string str = getString();
    func(str.c_str());
}

C#方:

[DllImport("NativeLibrary", CallingConvention = CallingConvention.Cdecl)]
public static extern void get_string(StringFromIntPtr.FromIntPtrDelegate func);

public class StringFromIntPtr
{
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void FromIntPtrDelegate(IntPtr ptr);

    public string Value { get; protected set; }

    public void FromIntPtr(IntPtr ptr)
    {
        Value = Marshal.PtrToStringAnsi(ptr);
    }
}

然后你这样使用:

var sfip = new StringFromIntPtr();
get_string(sfip.FromIntPtr);
string str = sfip.Value;

关键是你向C ++代码传递一个C#方法的委托,该方法知道如何处理一个字符串的原始指针(例如,通过使用Marshal.PtrToStringAnsi),而C ++代码使用它。请注意,在C ++ / CLI中执行此操作要容易得多(因为您不需要委托,C ++ / CLI可以同时使用std::stringSystem.String^

答案 1 :(得分:3)

如果您使用的是C ++ / CLI,则也可以返回System :: String。您可以从getString()。c_str()

构造System :: String