C#获取C/C++返回值为wchar_t*的内容

来源:互联网 发布:veket linux最新版本 编辑:程序博客网 时间:2024/05/29 16:58
最近想练习用WPF写界面,调用API的时候发现太麻烦,每个参数要自己声明类型,于是准备写一个DLL,在DLL里面调用API,将结果返回(字符串)。

先上DLL函数,

wchar_t* GetErrorCodeStr(DWORD dwError){    static wchar_t buff[1024] = L"No text found for this error number.";    DWORD systemLocale = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);    HLOCAL hlocal = NULL;    BOOL fOk = FormatMessage(        FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |        FORMAT_MESSAGE_ALLOCATE_BUFFER,        NULL, dwError, systemLocale,        (PTSTR)&hlocal, 0, NULL);    if (!fOk)     {        // Is it a network-related error?        HMODULE hDll = LoadLibraryEx(TEXT("netmsg.dll"), NULL,            DONT_RESOLVE_DLL_REFERENCES);        if (hDll != NULL)        {            fOk = FormatMessage(                FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS |                FORMAT_MESSAGE_ALLOCATE_BUFFER,                hDll, dwError, systemLocale,                (PTSTR)&hlocal, 0, NULL);            FreeLibrary(hDll);        }    }    if (fOk && (hlocal != NULL))    {        wcscpy_s(buff, (wchar_t*)hlocal);        LocalFree(hlocal);    }    return buff;}

就是一个简单的把GetLastError的返回值转换为字符串的函数。

然后C#中声明:

[DllImport("Control.dll", EntryPoint = "GetErrorCodeStr", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Winapi)]public static extern IntPtr GetErrorCodeStr(int errorCode);

为什么这里函数返回值就写IntPtr而不是string呢,我刚开始也是这么认为的,但是调用的时候会提示堆栈损坏。。。

在翻了很多博客后,了解到对于C/C++的指针,都要用IntPrt。

然后就是调用函数:

IntPtr i = GetErrorCodeStr(errorCode);string temp = Marshal.PtrToStringUni(i, 1024).Split('\r')[0];

然后temp里面就是返回的结果了。
能看到我在获得字符串后,将字符串分片,然后选择了第一个字符串。
因为Marshal.PtrToStringUni函数是从非托管内存复制指定数量的字符,我这里设置1024(DLL里面分配的wchar_t数组也是1024),就导致结果变成了这样:

DLL里面的返回内容:
DLL里面的返回内容

Marshal.PtrToStringUni(i, 1024)的结果:
Marshal.PtrToStringUni(i, 1024)的结果

真的复制了1024个字符,里面有很多我们不需要的字符,就需要分片后才能拿到我们真正需要的东西。

原创粉丝点击