2009-04-30 6 views
4

私はUnicode文字列をサポートしていないマルチバイトANSI文字列をサポートしているライブラリ用のPInvokeラッパーを開発中です。ライブラリのFxCopレポートを調べているうちに、使用されている文字列マーシャリングには面白い副作用があることに気付きました。 PInvokeメソッドは、「最適な」マッピングを使用してシングルバイトのANSI文字列を作成していました。非ASCII文字を含む文字列で、この関数を呼び出した結果は、Windowsがそれが終わるように、一般的にこれが見え、「クローズ」の文字を見つけたということですマルチバイトのANSI文字列を入力するにはどうすればよいですか?

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

:説明のため、これは一つの方法は次のように見えたものですであること "???"。 '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は1バイトの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はこれをサポートしていますが、システム全体のANSIコードページとしてUTF-8を採用することはできないため、P/Invokeとは違います。この時点で、文字列をIntPtrとして渡すことを検討していますが、これを行う場合はWideCharToMultiByteではなく、変換されたEncodingクラスを使用することもできます。

+0

あなたが正しいと思います。私は現在のコードページの外で文字の方法でテストしていて、コードページで実際に動作するマルチバイト文字を考えることができませんでした。私はいくつかの自信を得るために関数に投げることのできるコードページと文字の組み合わせを見つけようとしていますが、あなたが正しいと思います。 – OwenP

+0

私はそれをテストする方法を理解しました:私は持っている日本語ローカライズされたXP用のイメージを使用し、多くの日本語文字で構成された名前でリソースを設定しました。これは日本のマシンではうまくいったが、英語マシンでは悲惨に失敗した。 私はUnicodeを使用しているかのように動作するようにしたいと思いますが、あなたの説明と実験から、これは不可能であるとわかります。私は、ライブラリのメンテナーがUnicodeサポートを実装するのを待たなければなりません。 – OwenP

1

これを達成するために私が見つけた最良の方法があります。文字列としてマーシャリングする代わりに、バイトとしてマーシャリングします。 pinvoke関数APIの呼び出し側に責任を負わせて、最も適切な方法でバイト配列に変換します。 Text.Encodingクラスの1つを使用している可能性が最も高い

0

手動でWideCharToMultiByteを呼び出す必要が生じた場合は、p/invokeを取り除き、C++/CLIラッパー関数でWideCharToMultiByteを使用してこれを手動でマーシャリングします。 Managed C++は、C#よりもこれらの相互運用シナリオではるかに優れています。

これが唯一のp/invokeであれば、おそらくそれは価値がありません。

+0

C#で解決策があるときに別の言語を使用することを提案するのはなぜですか? – NineBerry

関連する問題