マルチバイトANSI文字列をPInvokeするにはどうすればよいですか?
質問
Unicode文字列をサポートしていないが、マルチバイトANSI文字列をサポートしているライブラリのPInvokeラッパーに取り組んでいます。ライブラリに関するFxCopレポートの調査中に、使用されている文字列マーシャリングには興味深い副作用があることに気付きました。 PInvokeメソッドは「ベストフィット」を使用していました。シングルバイトANSI文字列を作成するマッピング。説明のために、これは1つのメソッドがどのように見えるかです:
[DllImport("thedll.dll", CharSet=CharSet.Ansi)]
public static extern int CreateNewResource(string resourceName);
非ASCII文字を含む文字列を使用してこの関数を呼び出すと、Windowsは" close"を検出します。文字、一般的にこれは「???」で終わるように見えます。 '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はシステムに応じてUnicodeまたはANSIになり、LPWStrはライブラリが期待するものではありません。
文字列をマルチバイト文字列としてマーシャリングするようにPInvokeに指示するにはどうすればよいですか?
をアンマネージメモリで作成する文字列に変更するように署名を変更できますか?これには、現在の実装にある問題の多くがまだあるようです(まだ文字をドロップまたは置換する必要があるかもしれません)。不足しているマーシャリングの別の方法はありますか? WideCharToMultiByte()
API関数がありますが、IntPtr
解決
ANSI はマルチバイトであり、ANSI文字列は現在システムで有効になっているコードページに従ってエンコードされます。 WideCharToMultiByte
はP / Invokeと同じように機能します。
おそらく、あなたが望んでいるのはUTF-8への変換でしょう。 WideCharToMultiByte
はこれをサポートしますが、システム全体のANSIコードページとしてUTF-8を採用することはできないため、P / Invokeがサポートするとは思いません。この時点では、代わりに IntPtr
として文字列を渡すことになりますが、そうする場合は、マネージ Encoding
クラスを使用して行うこともできます WideCharToMultiByte
ではなく、変換。
他のヒント
これを達成するために私が見つけた最良の方法は次のとおりです。文字列としてマーシャリングする代わりに、byte []としてマーシャリングします。 pinvoke関数APIの呼び出し元に責任を負わせ、最も適切な方法でバイト配列に変換します。ほとんどの場合、Text.Encodingクラスのいずれかを使用します。
WideCharToMultiByteを手動で呼び出す必要がある場合、p / invokeを取り除き、C ++ / CLIラッパー関数でWideCharToMultiByteを使用してこれを手動でマーシャリングします。これらの相互運用シナリオでは、マネージC ++はC#よりもはるかに優れています。
ただし、これがあなたが持っている唯一のp / invokeである場合、おそらく価値はありません。