调用c ++ dll函数从c#返回char *。不能使用DllImport()

时间:2013-02-19 08:44:03

标签: c# c++ dll character-encoding

我有一个带有2个函数的c ++ dll

const char* getVersionText1(void);
void        getVersionText2(const char** res);

两个函数都返回一个描述产品版本的字符串。第一个函数将它返回为const char *(这意味着它在内部分配和处理它),第二个函数获取一个指向char *的指针,并将其设置为指向描述版本的char *。

我想从C#中调用这些函数并显示文本。 我不能使用[dllimport ...]样式,因为调用函数的顺序很重要。我首先调用构造函数而不是getVersion,最后是析构函数。所以必须先将dll加载到内存中。

请您发布打印两种功能文本的几行代码。 我是C#的新手,很抱歉如果你发现我的代码有问题 我试过了

static class NativeMethods{
    [DllImport("kernel32.dll")]
    public static extern IntPtr LoadLibrary(string dllToLoad);
    [DllImport("kernel32.dll")]
    public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
    [DllImport("kernel32.dll")]
    public static extern bool FreeLibrary(IntPtr hModule);
}
class Program{
    // Define function pointers to entires in DLL
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate IntPtr getVersionText1();
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate void getVersionText2(IntPtr );
    static void Main(string[] args){
        // Pointers to functions of DLL.
        getVersionText1 f1;
        getVersionText2 f2;
        IntPtr pDll = NativeMethods.LoadLibrary("p:\\my.dll");
        IntPtr pAddressOfFunctionToCall;
        pAddressOfFunctionToCall = NativeMethods.GetProcAddress(pDll, "getVersionText1 ");
        f1 = (getVersionText1)Marshal.GetDelegateForFunctionPointer(pAddressOfFunctionToCall, typeof(getVersionText1));
        pAddressOfFunctionToCall = NativeMethods.GetProcAddress(pDll, "getVersionText2 ");
        f2 = (getVersionText2)Marshal.GetDelegateForFunctionPointer(pAddressOfFunctionToCall, typeof(getVersionText2));

        // Here I don't know what to do. It doesn't work ????
        IntPtr verText = f1();
        String s = Marshal.PtrToStringAuto(verText);
        Console.WriteLine(s);   // Doesnt work
        // And how to use the second function. How do I sent a pointer to char* ???
    }
}

3 个答案:

答案 0 :(得分:8)

如果C ++库函数返回char*,C#代码会将其视为IntPtrMarshal.PtrToStringAnsi()会将其转换为C#string

IntPtr verText = f1();
string s = Marshal.PtrToStringAnsi(verText);
Console.WriteLine(s);

答案 1 :(得分:7)

这是一种拨打电话的方式。可能有更短的替代品自动执行utf8 /字符串转换。

[DllImport("mydll.dll")]
public static extern IntPtr getVersionText1(void);
public string getVersionTextConst()
{
    IntPtr ptr = getVersionText1();
    // assume returned string is utf-8 encoded
    return PtrToStringUtf8(ptr);
}

[DllImport("mydll.dll")]
public static extern void getVersionText2(out IntPtr res);
public string getVersionTextConst()
{
    IntPtr ptr;
    getVersionText2(ptr);
    // assume returned string is utf-8 encoded
    String str = PtrToStringUtf8(ptr);
    // call native DLL function to free ptr
    // if no function exists, pinvoke C runtime's free()
    return str;
}

private static string PtrToStringUtf8(IntPtr ptr) // aPtr is nul-terminated
{
    if (ptr == IntPtr.Zero)
        return "";
    int len = 0;
    while (System.Runtime.InteropServices.Marshal.ReadByte(ptr, len) != 0)
        len++;
    if (len == 0)
        return "";
    byte[] array = new byte[len];
    System.Runtime.InteropServices.Marshal.Copy(ptr, array, 0, len);
    return System.Text.Encoding.UTF8.GetString(array);
}

答案 2 :(得分:0)

如果您需要更快的速度,还可以进行不安全的阅读

unsafe string GetString(IntPtr ptr) => new string((char*)ptr); // local function

IntPtr charPtr = f1();
var s = GetString(charPtr);

当您添加unsafe方法时,VS会询问您是否要在项目中允许使用不安全的代码:是。或手动“项目属性/构建/允许不安全代码”。