2016-06-15 10 views
0

私はソースコードを持たないサードパーティのC++ DLLを読み込むVS 2015 MVC C#Webアプリケーションで作業しています。 DLLには入力パラメータが必要です。新しい仕様では、2つの配列メンバーが必要です。 1つはintアレイであり、もう1つはcharアレイです。C#:安全でない構造体のメンバ配列を設定する方法

私のC#の構造体は、8ビットのC++文字に一致するようにbyteとして意図char配列を定義しています

[StructLayout(LayoutKind.Sequential)] 
public unsafe struct MyDLLInput 
{ 
    public fixed int SomeList[288]; 
    public fixed byte PathToData[256]; 
}; 

構造体は、私には正しいようだが、今、私は値を設定する必要があると私は持っていませんよ任意の成功。 - 脇ローカルIを使用して値を設定する適切な方法から

Fixed size buffers can only be accessed through locals or fields.

ここで起こって物事のカップルは、少なくともあります。私は、次のエラーを取得しています両方のメンバーアレイの

MyDLLInput dllInput = new MyDLLInput() 
{ 
    SomeList = new int[] {0,12,33,67,93}, 
    PathToData = "C:\\some\\path\\to\\data" 
} 

// Call 3rd Party DLL 
MyDLLOutput = MyDLL.EntryPoint(MyDLLInput); 

stringからbyte[]へのエンコーディング変換も行わなければなりません。

誰かに、これらの値を設定するためのきれいな方法のコード例を私に提供することはできますか?

+0

安全でないブロックで固定フィールドをインスタンス化する必要があります。 – igorushi

+1

Encoding.GetBytesは、2番目の問題を解決します。https://msdn.microsoft.com/en-us/library/ds4kkd55(v=vs.110).aspx – igorushi

答えて

3

安全でない構造体を使用している理由はありますか?マーシャル属性を使用できませんか? https://msdn.microsoft.com/en-us/library/eshywdt7(v=vs.110).aspx

どのようにC#文字列からバイト配列に変換するのかを知る必要があります。また、C++ DLLがその文字列がどのようなエンコーディングになっているかによって異なります。たとえば、Windowsの場合、しばしば "ANSIコードページ"ですが、Linux/Unixでは "現在のロケール"または明示的な "UTF-8"のいずれかになります。あなたは文字列としてPathToDataを宣言しようとすることができ、また

[StructLayout(LayoutKind.Sequential)] 
    public struct MyDllInput 
    { 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 288)] 
     public int[] SomeList; 

     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] 
     public byte[] PathToData; 
    } 
    public static void Main() 
    { 
     MyDllInput dllInput = new MyDllInput() 
     { 
      SomeList = new int[288], 
      PathToData = new byte[256] 
     }; 

     var listData = new int[] { 0, 12, 33, 67, 93 }; 
     Array.Copy(listData, dllInput.SomeList, listData.Length); 

     var pathToDataBytes = Encoding.UTF8.GetBytes("C:\\some\\path\\to\\data"); 
     Array.Copy(pathToDataBytes, dllInput.PathToData, pathToDataBytes.Length); 
    } 

、代わりの直接エンコーディング変換を行う:

ので、エンコーディング上であなたに最もコントロールを与える一つの選択肢は以下のようにsomethiing行うことであろう次にマーシャリング属性を使用してC#で変換します。 https://msdn.microsoft.com/en-us/library/s9ts558h(v=vs.110).aspxを参照してください。

[StructLayout(LayoutKind.Sequential)] 
    public struct MyDllInput 
    { 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 288)] 
     public int[] SomeList; 

     [MarshalAs(UnmanagedType.ByValTStr, SizeConst =256)] 
     public String PathToData; 
    } 
    public static void Main() 
    { 
     MyDllInput dllInput = new MyDllInput() 
     { 
      SomeList = new int[288], 
      PathToData = "C:\\some\\path\\to\\data" 
     };    

     var listData = new int[] { 0, 12, 33, 67, 93 }; 
     Array.Copy(listData, dllInput.SomeList, listData.Length); 
    } 

後者の場合、それはあなたがエントリーポイントを宣言するとき、あなたが望むように発生する文字列変換を得るためにDllImportAttributeのCharsetプロパティを設定することが重要です。あなたの場合、はDLLがchar *をとり、wchar_t *を取っていないのでCharSet.Ansiが必要です。たとえば、

[DllImport("MyDll.dll", CharSet = CharSet.Ansi)] 
    private static extern void EntryPoint(ref MyDllInput input); 
+0

例は優れており、私にとってはうまくいくと思います。私はこの時点でそれを試すことはできませんが、少し遅れて私の机に着いていきます。マーシャリング属性を使用する場合は、別のオプションです。設定方法がわからず、プロジェクトの期限が近づいていました。私はそれがすべて働いた後、私は締め切りを満たすためにそれを残しました。私はあなたの提案をお試しになり、今晩遅く更新を提供します。時間を割いていただきありがとうございます。私は本当にあなたの助けに感謝します。 – rwkiii

+0

私はあなたの最初の例を試していますが、埋め込み配列インスタンスの長さがレイアウト内の宣言された長さと一致しないため、 '型をマーシャリングできませんでした。'これは、私の' int [] SomeList'が配列中に288個の要素を含んでいないか、または 'byte [] PathToData'が正確に256バイトではないためですか? SomeListは常に288要素で初期化されるわけではなく、時には1要素だけであり、もちろんPathToDataは256バイト長ではありません。これが私がエラーを得ているのかどうか疑問に思っています。もしそうなら、どうすればこの問題を解決できますか? – rwkiii

+1

私はあなたが正しいと思う - 私はC#が配列をゼロ拡張すると仮定していたが、私はそれが自動的に行われないだろうと思う。手動で配列を正しいサイズに拡張することができます。たとえば、正しいサイズの配列を割り当てて、Array.Copy()を使用して、サイズの小さい配列から正しいサイズの配列にコピーすることができます。 – Steven

関連する問題