3

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

我必须导出 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();

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

PS 建议使用单独的函数包装 SysGetLibInfo,该函数使用 PtrToStringUni 将结果转换为字符串不是一种选择;)

4

2 回答 2

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();
于 2013-05-30T10:30:55.373 回答
1

我认为,问题在于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;
}

然后[return: MarshalAs(UnmanagedType.LPWStr)]也会工作。

于 2013-05-30T10:27:18.667 回答