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

时间:2013-05-30 10:02:15

标签: c# c++ dll wchar-t interopservices

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

我必须导出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。使用PtrToStringUni将结果转换为字符串的单独函数包装SysGetLibInfo的建议不是一个选项;)

2 个答案:

答案 0 :(得分:1)

我认为问题在于PLWStr

  

您不能将LPWStr值与非托管字符串一起使用,除非   string是使用非托管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;
}

然后[return: MarshalAs(UnmanagedType.LPWStr)]也可以。

答案 1 :(得分:1)

您无法覆盖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();