C#獲取C/C++返回值爲wchar_t*的內容

最近想練習用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個字符,裏面有很多我們不需要的字符,就需要分片後才能拿到我們真正需要的東西。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章