2

VB.netで構造体タイプの配列を作成する必要があります。しかし、このエラーをマーシャリングしているときにエラーが発生します。この構造体型の配列をDLL関数に渡す必要があります。

コード:構造体宣言:

<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[]をアンマネージ構造としてマーシャリングすることはできません。意味のあるサイズやオフセットは計算できません。

4

1 に答える 1

2

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

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

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

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

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メソッドを使用して、返されたバイト配列をポインタが指すメモリにコピーします。

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 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バイトも:

<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
于 2009-07-23T13:41:41.777 に答える