如何将常量wchar_t*从C DLL自动转换为C#字符串

How convert const wchar_t* from C DLL to C# string automatically

本文关键字:DLL 转换 字符串 常量 wchar      更新时间:2023-10-16

这只是一种好奇。也许这个世界上有一个人做过这样的事:

我必须导出C函数,并通过DllImport 从C#代码加载它

const wchar_t * SysGetLibInfo() {
    return dllmanager.SysGetLibInfo();
}

最好的方法是声明IntPtr,然后使用一些函数将其转换为字符串,这是广泛推荐的。换句话说,类似的东西

[DllImport(dll, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr SysGetLibInfo(); 
// ...
Marshal.PtrToStringUni(SysGetLibInfo());

这种方法行之有效。但是有没有办法自动做到这一点?要使SysGetLibInfo返回字符串?我发现了一些这样的建议:

[DllImport(dll, CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.LPWStr)]
private static extern string SysGetLibInfo();

但它不起作用,根据各种各样的例子和很少的报道,它不应该起作用。

有没有一种方法可以像MarshalAs一样编写我自己的属性,将IntPtr转换为字符串?类似的东西:

[DllImport(dll, CallingConvention = CallingConvention.Cdecl)]
[return: MyOwnMarshalPtrToStringUni]
private static extern string SysGetLibInfo();

提前感谢您提供任何信息或有用的链接、示例、书籍。再说一遍,这只是一种好奇。

p.S.建议用一个单独的函数包装SysGetLibInfo,该函数使用PtrToStringUni将结果转换为字符串,这不是一个选项;(

您不能覆盖MarshalAs,但可以使用自定义编组代替

http://msdn.microsoft.com/en-us/library/w22x2hw6.aspx

  [DllImport(dll, CallingConvention = CallingConvention.Cdecl)]
  [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(MyMarshaller))]
  private static extern string SysGetLibInfo();

我认为问题出在LPWStr:上

不能将LPWStr值与非托管字符串一起使用,除非字符串是使用非托管CoTaskMemAlloc函数创建的

这很好用。本机代码:

// header
extern "C" __declspec(dllexport) wchar_t* SysGetLibInfo(void);
// implementation
extern "C" __declspec(dllexport) wchar_t* SysGetLibInfo(void)
{
    return TEXT("Hello from unmanaged world!");
}

托管代码:

    [DllImport("NativeLibrary.dll", CallingConvention = CallingConvention.Cdecl)]
    [return: MarshalAs(UnmanagedType.LPTStr)]
    static extern string SysGetLibInfo();

如果您将以这种方式更改本机功能:

extern "C" __declspec(dllexport) wchar_t* SysGetLibInfo(void)
{
    wchar_t* pStr = (wchar_t*)CoTaskMemAlloc(100);
    ZeroMemory(pStr, 100);
    wcscpy(pStr, TEXT("Hello from unmanaged world!"));
    return pStr;
}

则CCD_ 2也将工作。