最近想練習用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裏面的返回內容:
Marshal.PtrToStringUni(i, 1024)的結果:
真的複製了1024個字符,裏面有很多我們不需要的字符,就需要分片後才能拿到我們真正需要的東西。