2009-07-23 21 views
2

VB.netで構造体の配列の配列を作成する必要があります。このエラーをマーシャリングしている間にエラーが発生しています。私はこの構造体の配列をDll関数に渡す必要があります。VB.netマーシャリングエラー

コード: 構造宣言:initiallizationとマーシャリングの

<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _ 
    Public Structure dx_entry 
     <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=10)> _ 
     Public dx As String 
     <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=3)> _ 
     Public type As String 
     <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=1)> _ 
     Public narray As String 
     <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=1)> _ 
     Public ctier As String 
     <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=1)> _ 
     Public poa As String 
     <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=1)> _ 
     Public poa_rsvd As String 
     <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=81)> _ 
     Public filler As String 
    End Structure 

コード:

Dim stpDx(2) As dx_entry 
stpDx(1).dx = "5939" & Space(6) 
     stpDx(1).type = "BK" & Space(1) 
     stpDx(1).narray = Space(1) 
     stpDx(1).ctier = Space(1) 
     stpDx(1).poa = "Y" 
     stpDx(1).poa_rsvd = Space(1) 
     stpDx(1).filler = Space(81) 
     stpDx(2).dx = "1231" & Space(6) 
     stpDx(2).type = "BF" & Space(1) 
     stpDx(2).narray = Space(1) 
     stpDx(2).ctier = Space(1) 
     stpDx(2).poa = "Y" 
     stpDx(2).poa_rsvd = Space(1) 
     stpDx(2).filler = Space(81) 
     Dim pDxBuf As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(stpDx)) 
     Marshal.StructureToPtr(stpDx, pDxBuf, False) 
     ezg_Block.pDx = pDxBuf 

私は、次のエラーを取得しています:

An unhandled exception of type 'System.ArgumentException' occurred in Audit_Demo_2307.exe 

追加情報:タイプdx_entryを[ ]をアンマネージ構造としてマーシャリングすることはできません。意味のあるサイズまたはオフセットを計算することはできません。

答えて

2

これを少し調べましたが、最初の問題はMarshal.SizeOfメソッドに配列を渡すように見えます(この呼び出しは例外をスローします)。構造体のメンバはすべて固定サイズなので、その型のインスタンスはすべて同じサイズになります。だから、あなたの代わりにそのようなインスタンスのサイズを返すようにMarshal.SizeOfを依頼することができます。

Dim structSize As Integer = Marshal.SizeOf(GetType(dx_entry)) 

次のものがあることMarshal.StructureToPtrコピーする構造からのデータではなく、構造体の配列。したがって、構造体配列を割り当てられたメモリにコピーする他の方法が必要になります。 1回の呼び出しでこれを行う方法はありませんが、配列内の各構造体インスタンスをバイト配列にコピーして(Marshal.Copyメソッドを使用して)、そのバイト配列をメモリにコピーしますポインタがポイントします。

これは2ステップロケットとして最も簡単です。まずは、バイト配列に構造体の配列を変換する方法作成してみましょう:

Dim data As Byte() = GetByteArray(stpDx) 
Dim pDxBuf As IntPtr = Marshal.AllocHGlobal(data.Length) 
Marshal.Copy(data, 0, pDxBuf, data.Length) 
ezg_Block.pDx = pDxBuf 

Private Shared Function GetByteArray(ByVal array As dx_entry()) As Byte() 
    Dim structSize As Integer = Marshal.SizeOf(GetType(dx_entry)) 
    Dim size As Integer = structSize * array.Length 
    Dim dataBuffer As Byte() = New Byte(size - 1) {} 
    For i As Integer = 0 To array.Length - 1 
     Dim pTemp As IntPtr = Marshal.AllocHGlobal(structSize) 
     Marshal.StructureToPtr(array(i), pTemp, True) 
     Marshal.Copy(pTemp, dataBuffer, 0 + (i * structSize), structSize) 
     Marshal.FreeHGlobal(pTemp) 
    Next 
    Return dataBuffer 
End Function 

第二に、GetByteArrayメソッドを使用してメモリに返されるバイト配列をコピーするには、ポインタで指さ

私はあなたが探していることを願っています...

サイドノートとして。構造体の中に各フィールドの固定サイズが指定されているため、コード内に値をスペースで埋め込む必要はありません。これは、データを整列する際にフレームワークによって処理されます。

更新

データのリードバックに、あなたは基本的に同じことを行うが、逆方向にする必要があります。

そのように呼ばれ
Private Shared Function GetStructArray(ByVal dataBuffer() As Byte) As dx_entry() 
    Dim structSize As Integer = Marshal.SizeOf(GetType(dx_entry)) 
    If dataBuffer.Length Mod structSize <> 0 Then 
     Throw New ArgumentException("Argument is of wrong length", "dataBuffer") 
    End If 
    Dim elementCount As Integer = Convert.ToInt32(dataBuffer.Length/structSize) 
    Dim size As Integer = structSize * elementCount 
    Dim result() As dx_entry = New dx_entry(elementCount - 1) {} 
    For i As Integer = 0 To elementCount - 1 
     Dim pTemp As IntPtr = Marshal.AllocHGlobal(structSize) 
     Marshal.Copy(dataBuffer, 0 + (i * structSize), pTemp, structSize) 
     result(i) = DirectCast(Marshal.PtrToStructure(pTemp, GetType(dx_entry)), dx_entry) 
     Marshal.FreeHGlobal(pTemp) 
    Next 
    Return result 
End Function 

を:

Dim structSize As Integer = Marshal.SizeOf(GetType(dx_entry))   
Dim newdata() As Byte = New Byte(structSize * numberOfElements -1) {} 
Marshal.Copy(ezg_Block.pDx, newdata, 0, newdata.Length) 
Dim newstruct() As dx_entry = GetStructArray(data) 

:これをすべて正しく動作させるには、構造を少し微調整する必要があります。 SizeConstを1増加します。これは、文字列がnull終端であるためであるので、同様にNULLバイトのための位置があることが必要です。私は、DLLの後に、データを盗んしなければならない場合フレドリック、 たくさん

<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _ 
Public Structure dx_entry 
    <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=11)> _ 
    Public dx As String 
    <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=4)> _ 
    Public type As String 
    <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=2)> _ 
    Public narray As String 
    <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=2)> _ 
    Public ctier As String 
    <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=2)> _ 
    Public poa As String 
    <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=2)> _ 
    Public poa_rsvd As String 
    <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=82)> _ 
    Public filler As String 
End Structure 
+0

おかげで、私に知らせてくださいどのように私はこれを行うに行く必要があります。 実際には、この構造体には関数呼び出しの後に更新される値があります。 – Yogi

+0

フレドリックに心から感謝します。このソリューションは私のために働いています。私はあなたの助けを借りて、私はC言語で構造体型の変数を含む連合を持っています。私はVB.net でそれをマーシャリングするために、以下の方法を使用するパブリック構造grpr_output_block1 コードに使用drg_grpr_block1 末端構造などの公共DRG - 機能 にポインタとして渡しますIntPtr = Marshal.AllocHGlobal(偽stpGob1、pGob1Buf、)(Marshal.SizeOfstpGob1) Marshal.StructureToPtr Ezg_Block.pGob1 = pGob1Bufとしてgrpr_output_block1 薄暗いpGob1Bufとして暗いstpGob1 はそれが右のマーシャルのですか? – Yogi