2009-07-23 35 views
2

我必須在VB.net中創建一個結構類型的數組。但在編組此錯誤時出現錯誤。我必須將這個結構類型的數組傳遞給Dll函數。VB.net編組錯誤

代碼: 結構聲明:

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 [

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 

代碼]不能作爲非託管結構進行編組;無法計算出有意義的大小或偏移量。

回答

2

我仔細看了一下,第一個問題似乎是你將一個數組傳遞給Marshal.SizeOf方法(正是這個調用拋出異常)。由於您的結構中的所有成員都具有固定的大小,因此您知道該類型的所有實例都具有相同的大小。所以,你可以而要求Marshal.SizeOf返回的大小對於一個這樣的例子:

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

接下來的事情是,Marshal.StructureToPtr複製從結構數據,而不是結構的數組。所以你將需要一些其他的方式來複制你的結構數組到分配的內存。沒有辦法可以在一次調用中爲您執行此操作,但可以執行的操作是將數組中的每個結構實例複製到一個字節數組中(然後使用Marshal.Copy方法),然後將該字節數組複製到內存中由指針指向。

這是最容易做到的兩步火箭。首先,讓我們作出這樣的結構數組轉換爲字節數組的方法:

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。這是因爲該字符串是空終止,所以必須爲空字節的位置,以及:

<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

非常感謝弗雷德裏克, 請讓我知道,如果我有該DLL後中檢索數據函數調用,我該如何去做這件事。 實際上在這個結構中有一些值會在函數調用後得到提升。 – Yogi 2009-07-23 15:10:11