2016-07-28 5 views
4

私は私の構造体は、Cに次のようになりますthis questionのPInvoke - ポインタ

で答えを追跡しようとしてるから、構造体の配列をマーシャリングMy機能は、C

で次のようになります

typedef struct drive_info_t { 
    unsigned char drive_alias[32]; 
} drive_info_t; 

unsigned int get_drive_info_list(drive_info_t **list, unsigned int *item_count) { 
    //fill list in native C 

    //print out in native C 
    printf("list.alias - %s\r\n",list[i]->drive_alias); 
} 

私のC#の構造体は、この

[StructLayout(LayoutKind.Sequential)] 
public struct drive_info_t 
{ 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] 
    public byte[] drive_alias; 
} 
のように見えます210

私のC#の関数宣言は、私が印刷この

nAlloc = ptr_cnt.ToInt32(); 

int szStruct = Marshal.SizeOf(typeof(api.drive_info_t)); 
api.drive_info_t[] localStructs = new api.drive_info_t[nAlloc]; 

for (int i = 0; i < nAlloc; i++) 
{ 
    localStructs[i] = (api.drive_info_t)Marshal.PtrToStructure(ptr_list_info, typeof(api.drive_info_t)); 
    ptr_list_info = new IntPtr(ptr_list_info.ToInt32() + (szStruct)); 
} 

のように返されたポインタをマーシャリングしています。この

IntPtr ptr_list_info = IntPtr.Zero; 
IntPtr ptr_cnt = IntPtr.Zero; 

ret = api.GetDriveInfoList(out ptr_list_info, out ptr_cnt); 

のようなこの

[DllImport("mydll.dll", EntryPoint = "get_drive_info_list", CallingConvention = CallingConvention.Cdecl)] 
public static extern uint GetDriveInfoList(out System.IntPtr ptr_list_info, out System.IntPtr ptr_count); 

私が呼んでいるC#関数のように見えますこのような構造体エイリアス

for (uint i = 0; i < localStructs.Length; i++) 
{  
    Console.WriteLine("list.alias - {0}", System.Text.Encoding.Default.GetString(localStructs[i].drive_alias)); 
} 

私と一緒にお越しいただきありがとうございます。

これは私の出力がC#のコンソールアプリケーションのようです。あなたはそれが価値のコンソールにネイティブのCのDLLの印刷を見ることができますが、私のマーシャリングは、どこかにめちゃくちゃにされています

======================== C values ============================ 
list.alias - drv1 
list.alias - drv2 
list.alias - drv3 
list.alias - drv4 
======================== C# values ============================ 
list.alias - drv1 
list.alias - o£Q95drv2 
list.alias -   o£Q95drv3 
list.alias -     o£Q95drv4 

私はこのゴミのテキストおよびオフセットから来ているか見当もつかない。

私は、必要に応じて他のチームメンバーがネイティブCを変更できますが、ネイティブCの変更はクロスプラットフォームのOSX/Windows/Linuxである必要があります。

ありがとうございます。

+0

'[StructLayout(LayoutKind.Sequential)]'を '[StructLayout(LayoutKind.Sequential、Pack = 5)]'に変更するとどうなりますか? – itsme86

+0

Pack = 5は有効な値ではありません。また、変更なしで1,2,4,8の値を調べてみました。 – ScottN

+0

私は、IntPtrをUIntPtrに変更し、ToInt32のすべての参照をUInt32に変更すると思います。私はときどきそれが重要ではないように見えるかもしれないことを知っていますが... –

答えて

1

これは、引数の型がインターフェイスを定義しない理由の完全な例です。検討する

drive_info_t **list 

これは構造体の配列へのポインタです。おそらく配列は呼び出し先によって割り当てられていると考えられます。アレイに対するポインタが配列とは対照的に使用されるのはこのためです。

または、構造体へのポインタの配列である可能性があります。配列は呼び出し元によって割り当てられ、構造体は呼び出し先または呼び出し元のいずれかによって割り当てられます。私たちが教えてくれる方法はありません。

あなたのインタフェースがstructへのポインタの配列を受け入れることが分かります。このコードを見てください:

list[i]->drive_alias 

はっきりlistは、構造体へのポインタの配列です。

これは、コードが間違っていることを示しています。セマンティクスを誤って識別したため、間違ったテンプレートに従っています。次のステップでは、インタフェースのドキュメンテーションに戻り、セマンティクスが何であるかを正確に知るためにコードを呼び出します。誰が何を割り当て、割り当てを解除したのか。

ほとんど確かにIntPtr[]を使用して配列をマーシャリングしますが、それ以上に何が起こるかはわかりません。私は、呼び出し側が構造体を割り当てるが、推測に頼らないと推測するだろう。ドキュメンテーションとコード例を読んでください。

2番目の引数は、機能のセマンティクスに応じて、ref uintまたはおそらくout uintにする必要があります。繰り返しますが、これはうまくいかないことです。

+0

'IntPtr []を使って配列をマーシャリングすることはほぼ間違いないでしょう。はい、宣言を' [In、Out] System.IntPtr [] ptr_list_info'に変更し、2番目のパラメータをuintに変更しました。ありがとう! – ScottN

関連する問題