VB.net编组错误 [英] VB.net Marshalling Error

查看:67
本文介绍了VB.net编组错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我必须在VB.net中创建一个结构类型的数组.但在整理此错误时出现错误.我必须将此结构类型数组传递给Dll函数.

I have to create an array of structure type in VB.net. but I am getting error while marshalling this error. I have to pass this array of structure type in to Dll function.

代码: 结构声明:

<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 []类型的封送处理为非托管结构;不能将其编组为非托管结构.无法计算出有意义的尺寸或偏移量.

Additional information: Type dx_entry[] can not be marshaled as an unmanaged structure; no meaningful size or offset can be computed.

推荐答案

我对此进行了一些研究,第一个问题似乎是您将数组传递给了Marshal.SizeOf方法(正是此调用引发了例外).由于结构的所有成员都具有固定的大小,因此您知道该类型的所有实例将具有相同的大小.因此,您可以改为要求Marshal.SizeOf返回一个这样的实例的大小:

I looked in to this a little bit, and the first issue seems that you pass an array into the Marshal.SizeOf method (it is this call that throws the exception). Since all members of your structure have a fixed size, you know that all instances of that type will have the same size. So, you can instead ask Marshal.SizeOf to return the size for one such instance:

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

接下来的事情是Marshal.StructureToPtr从结构而不是结构数组复制数据.因此,您将需要其他方式将结构数组复制到分配的内存中.没有一种方法可以在一个调用中为您完成此操作,但是您可以做的是将数组中的每个结构实例复制到字节数组中(使用

The next thing is that Marshal.StructureToPtr copies the data from a structure, not an array of structures. So you will need some other way of copying your structure array to the allocated memory. There is no method that will do this for you in one call, but what you can do is to copy each of the structure instances in your array into a byte array (using the Marshal.Copy method), and then copying that byte array to the memory pointed to by the pointer.

这是两步火箭最容易做到的.首先,让我们创建一个将结构数组转换为字节数组的方法:

This is easiest to do as a two step rocket. First, let's make a method that converts the array of structures to a byte array:

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方法并将返回的字节数组复制到指针指向的内存中:

Second, use the GetByteArray method and copy the returned byte array to the memory pointed to by the pointer:

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

我希望这能满足您的需求...

I hope that does what you are looking for...

作为旁注;由于您已在结构中为每个字段指定了固定大小,因此无需在代码中用空格填充值;封送数据时,框架会解决此问题.

As a side note; since you in your structure have specified the fixed size for each of the fields, you don't need to pad the values with spaces in your code; this is taken care of by the framework when marshalling your data.

更新

要回读数据,您基本上需要做相同的事情,但是要倒退:

To read the data back, you basically need to do the same thing, but backwards:

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终止,因此也需要为空字节放置一个位置:

Note: To get all this to work properly, you will need to tweak the structure a bit: it seems you need to increase the SizeConst by 1. This is since the strings are null-terminated, so there need to be a position for the null byte as well:

<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

这篇关于VB.net编组错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆