J'ai regardé dans un peu, et le premier problème semble que vous passez un tableau dans la méthode Marshal.SizeOf
(c'est cet appel qui lève l'exception). Comme tous les membres de votre structure ont une taille fixe, vous savez que toutes les instances de ce type auront la même taille. Ainsi, vous pouvez demander au lieu de retourner Marshal.SizeOf
la taille pour un tel cas:
Dim structSize As Integer = Marshal.SizeOf(GetType(dx_entry))
La prochaine chose est que Marshal.StructureToPtr
copie les données d'une structure, pas un tableau de structures. Vous aurez donc besoin d'un autre moyen de copier votre tableau de structure dans la mémoire allouée. Il n'y a aucune méthode qui fera ceci pour vous dans un appel, mais ce que vous pouvez faire est de copier chacune des instances de structure dans votre tableau dans un tableau d'octets (en utilisant la méthode Marshal.Copy
), puis en copiant ce tableau d'octets dans la mémoire pointé par le pointeur.
Ceci est plus facile à faire comme une fusée à deux étages. Tout d'abord, nous allons faire une méthode qui convertit le tableau de structures à un tableau d'octets:
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
En second lieu, utiliser la méthode GetByteArray
et copier le tableau d'octets retourné à la mémoire pointée par le pointeur:
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
J'espère que cela fait ce que vous cherchez ...
En note; Puisque vous dans votre structure avez spécifié la taille fixe pour chacun des champs, vous n'avez pas besoin de remplir les valeurs avec des espaces dans votre code; ceci est pris en charge par le framework lors de la mise en place de vos données.
Mise à jour
Pour lire les données en arrière, vous devez essentiellement faire la même chose, mais à l'envers:
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
appelé comme ça:
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)
Remarque : Pour que tout fonctionne correctement, vous devrez modifier légèrement la structure: il semble que vous ayez besoin de augmentez le SizeConst par 1.Ceci est puisque les chaînes sont nulles terminés, donc il faut être une position de l'octet nul ainsi:
<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
Merci beaucoup Fredrik, S'il vous plaît laissez-moi savoir, si je dois retreive les données après la dll appel de fonction, comment je dois aller de l'avant pour le faire. En fait, il y a des valeurs dans cette structure qui seront mises à jour après l'appel de la fonction. – Yogi
J'apprécie votre aide Fredrik. cette solution fonctionne pour moi. Je nedd vous aider, j'ai une Union qui contient une variable de type de structure en langage C. J'ai utilisé la méthode suivante pour rassembler dans VB.net Structure publique grpr_output_block1 DRG public Comme drg_grpr_block1 Fin Structure L'utilisation dans le code - passer comme pointeur dans la fonction Dim stpGob1 Comme grpr_output_block1 Dim pGob1Buf comme IntPtr = Marshal.AllocHGlobal (Marshal.SizeOfstpGob1) Marshal.StructureToPtr (stpGob1, pGob1Buf, Faux) Ezg_Block.pGob1 = pGob1Buf est-il juste Marshall? –
Yogi