参照文字列アレイによるC#Marshallingの管理されていないCコード!
-
28-09-2019 - |
質問
私はこのマーシャルを倒すのに本当に苦労しています。
私は次のように見えるウーマネージコードを持っています:
WORD HLP_GetDeviceNames (LPSTR *DevNames, WORD Max_Len, WORD Max_Num)
ちょうど参照私はこの管理されていないコードを書いていませんでしたが、それを使用する必要があります。
返品:エラーを示す単語。
devnames:char配列の配列へのポインタ。基本的に、変更されて私に戻ってくる一連の文字列!
max_len:各文字列の長さ(これは256でなければならないと言われています)
max_num:配列の長さ。私は機能している別の呼び出しコールを使用しています。これは私に数のデバイスを教えてくれるので、送信する文字列の数を正確に知っています。
P/Interop Interop SignatureToolkitを使用して、これをたくさん把握しましたが、さらに進むために束を読んでいます。私が今ここにいる場所:
[DllImport("UsbMeasLib.dll")]
public static extern ushort HLP_GetDeviceNames([MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPStr)] ref StringBuilder[] DevNames, ushort Max_Len, ushort Max_Num);
私は自分のコードをこのように呼びます:
StringBuilder[] DevNames = new StringBuilder[deviceCount];
for(int i = 0; i< deviceCount; i++)
{
DevNames[i] = new StringBuilder().Append(' ', 256);
}
HachUsbMeasLib.HLP_GetDeviceNames(ref DevNames, 256, Convert.ToUInt16(DevNames.Count()));
String Builder Arrayを使用しています。なぜなら、文字列がマイートできないため、新しい文字列を返すことができるように、文字列ビルダーを変更するために管理されていないコードが必要だからです。
コードを実行すると、配列が変更されていません!
何が起こっているのか本当にわかりませんが、CLRが配列を設置しないように管理していないコードを伝えることと関係があると思いますが、代わりに新しいリファレンス(Pointer)を作成します。たとえそうであっても、私はそれを修正する方法を知りません。
誰でも提供できる洞察をありがとう!
解決 2
私はこれを理解しました。答えてくれた人に感謝します。
私はそれがどのように機能するかを知りました。私は単にメモリスペースを供給するだけですが、このオブジェクトに内外に出入りすることをマーシャリングに知らせなければなりません。そうすれば、管理されていないコードが割り当てられたスペースを変更できるようにします。
私はこのようにやった:
[DllImport("UsbMeasLib.dll")]
private static extern ushort HLP_GetDeviceNames([In, Out, MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPStr)] string[] DevNames, ushort Max_Len, ushort Max_Num);
管理されていないコードは、問題のない文字列を単純に置き換えるため、文字列ビルダーの代わりに文字列を使用します。変更された文字列ではなく、配列ポインターを取り戻しています。管理されたコードは、新しい文字列オブジェクトを指すようにポインターの配列を変更するだけです(私は思う)。
int numDev = HLP_GetNumDevices();
string[] names = new string[numDev];
for (int i = 0; i < names.Length; i++)
{
names[i] = new StringBuilder().Append(' ', 256).ToString();
}
ushort errorCode = HLP_GetDeviceNames(names, 256, Convert.ToUInt16(numDev));
未amangのコードにメモリを割り当て、管理されていないコードに文字列をそこに追いかけます。
これは機能しますが、潜在的なメモリリークやその他の潜在的な問題があるかどうかはわかりません。
他のヒント
低レベルで作業してみてください。 devNamesパラメーターをintptr []として宣言します。次の方法で準備してください。
IntPtr[] devNames = new IntPtr[deviceCount]; for(int i = 0; i < deviceCount; i++) { devNames[i] = Marshal.AllocHGlobal[256]; }
この配列をhlp_getdevicenamesに渡します。出力データを処理するには、Marshal.PtrtoStringansiをすべてのDevNamesメンバーに適用します。最終的にMarshal.FreehglobalでDevNames [i]をリリースすることを忘れないでください。