2009-04-30 38 views
4

我正在爲不支持Unicode字符串但支持多字節ANSI字符串的庫的PInvoke包裝器。在調查圖書館的FxCop報告時,我注意到正在使用的字符串編組有一些有趣的副作用。 PInvoke方法使用「最佳擬合」映射來創建單字節ANSI字符串。爲了說明,這是一個方法,看起來像:如何PInvoke多字節ANSI字符串?

[DllImport("thedll.dll", CharSet=CharSet.Ansi)] 
public static extern int CreateNewResource(string resourceName); 

調用與包含非ASCII字符是Windows找到「關閉」字符的字符串這個函數的結果,通常這看起來像它結束存在 」???」。如果我們假裝'a'是非ASCII字符,那麼傳遞「cat」作爲參數將創建一個名爲「c?t」的資源。

如果我遵循的FxCop規則的指引,我結束了這樣的事情:

[DllImport("thedll.dll", CharSet=CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true)] 
public static extern int CreateNewResource([MarshalAs(UnmanagedType.LPStr)] string resourceName); 

這引入了行爲的改變;現在當一個字符不能被映射時拋出一個異常。這關係到我,因爲這是一個突破性的改變,所以我想嘗試將字符串編組爲多字節ANSI,但是我看不到這樣做的方法。 UnmanagedType.LPStr被指定爲單字節ANSI字符串LPTStr will be Unicode or ANSI depending on the system, and LPWStr is not what the library expects.

How would I tell PInvoke to marshal the string as a multibyte string? I see there's a WideCharToMultiByte() API函數,我是否可以更改簽名以期望IntPtr爲我在非託管內存中創建的字符串?看起來,這仍然存在許多當前實現的問題(它仍然可能需要刪除或替換字符),所以我不確定這是否有所改進。我錯過了另一種編組方法嗎?

回答

6

ANSI 多字節,ANSI字符串根據系統當前啓用的代碼頁編碼。 WideCharToMultiByte的工作方式與P/Invoke相同。

也許你正在轉換爲UTF-8。雖然WideCharToMultiByte支持這一點,但我不認爲P/Invoke會這樣做,因爲無法採用UTF-8作爲系統範圍的ANSI代碼頁。此時,您會考慮將字符串作爲IntPtr來代替,但如果您這樣做,則不妨使用受管理的Encoding類來執行轉換,而不是WideCharToMultiByte

+0

我看你是對的;我在當前代碼頁之外進行了字符測試,並且無法想象任何實際上可以在我的代碼頁中工作的多字節字符。我在摸索着試着找到一個代碼頁/字符組合,我可以把它放到函數中來獲得一些信心,但我認爲你是對的。 – OwenP 2009-04-30 19:13:30

+0

我想出瞭如何測試它:我使用了一個用於日文本地化的XP的映像,並設置了一些名稱由大量日文字符組成的資源。這在日本機器上效果很好,但是在英文機器上失敗了。 我會*喜歡*的行爲就好像我使用Unicode一樣,但從您的解釋和實驗中我發現這是不可能的,而且我已經越來越接近它了。我只需等待庫的維護者實現Unicode支持。 – OwenP 2009-04-30 22:10:47

1

這是我找到的最好的方法來實現這一點。而不是作爲一個字符串編組,編組爲字符[]。將責任置於pinvoke函數API的調用者上,以最合適的方式轉換爲字節數組。很可能通過使用Text.Encoding類之一。

0

如果你最終不得不手動調用WideCharToMultiByte,我會擺脫p/invoke,並在C++/CLI包裝函數中使用WideCharToMultiByte手動編組。與C#相比,託管C++在這些互操作場景中要好得多。

雖然,如果這是您唯一的p/invoke,它可能不值得。

相關問題