PInvoke and marshalling question (on .net cf 1.1)

C

CB

Hi. I'm trying to pinvoke GetAdaptersInfo, which returns a pointer and
using that to fill a managed byte array. This is working ok.
Supposedly, I can overlay this byte array with a stucture or class that
has layout.kind sequential, but have not been able to get the class to
fill correctly. I am using a class as opposed to structure because I
want to have fixed size string arrays as some of the fields. Getting
an exception when trying to copy the byte array into the object
instance.
Thanks,

Imports System.Runtime.InteropServices

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
Dim len As Integer = 0
Dim ret As Integer = 0

' Get size of adapter info buffer (num of adapters x 640)
GetAdaptersInfo(IntPtr.Zero, len)

' Init byte buffer, pointer
Dim p As IntPtr = LocalAlloc(64, len)

' Get pointer to info
ret = GetAdaptersInfo(p, len)

' Fill byte array - THIS WORKS OK
Dim b(639) As Byte
System.Runtime.InteropServices.Marshal.Copy(p, b, 0, 640)

' Overlay object
Dim x As New AdapterInfo
' Marshall.SizeOf the object = 72. Shouldn't this be 640?

' THIS THROWS System.Argument exception
Dim gch As GCHandle = GCHandle.Alloc(x)
Marshal.Copy(b, 0, gch.AddrOfPinnedObject, 640)

' THIS appears to fill the first field only
Marshall.PtrToStructure(p, x)

End Sub

<DllImport("iphlpapi.dll", SetLastError:=True)> _
Public Shared Function GetAdaptersInfo(ByVal p As IntPtr, ByRef
pOutBufLen As Integer) As Integer
End Function

<DllImport("coredll.dll", SetLastError:=True)> _
Public Shared Function LocalAlloc(ByVal uFlags As Integer, ByVal
uBytes As Integer) As IntPtr
End Function

End Class

<StructLayout(LayoutKind.Sequential)> _
Public Class AdapterInfo
Public [Next] As Int32 ' 0
Public ComboIndex As Int32 ' 4
Public AdapterName(259) As String ' 8
Public AdapterDescription(135) As String ' 268
Public AddressLength As Int32 ' 400
Public Address(7) As Byte ' 404
Public Index As Int32 ' 412
Public Type As Int32 ' 416
Public DhcpEnabled As Int32 ' 420
Public CurrentIpAddress As Int32 '424
Public IpAddressList As IP_ADDR_STRING '428
Public GatewayList As IP_ADDR_STRING '468
Public DhcpServer As IP_ADDR_STRING ' 508
Public HaveWins As Int32 ' 548
Public PrimaryWinsServer As IP_ADDR_STRING ' 552
Public SecondaryWinsServer As IP_ADDR_STRING ' 592
Public LeaseObtained As Int32 ' 632
Public LeaseExpires As Int32 ' 636
End Class

<StructLayout(LayoutKind.Sequential)> _
Public Class IP_ADDR_STRING
Public [Next] As Int32 ' 0
Public IPAddress(15) As String ' 4
Public IPMask(15) As String ' 20
Public context As Integer ' 36
End Class ' 40
 
D

Daniel Moth

Why not use ready made solution by Alex Feinman:
http://www.alexfeinman.com/download.asp?doc=AdapterInfo.zip

Cheers
Daniel
--
http://www.danielmoth.com/Blog/

CB said:
Hi. I'm trying to pinvoke GetAdaptersInfo, which returns a pointer and
using that to fill a managed byte array. This is working ok.
Supposedly, I can overlay this byte array with a stucture or class that
has layout.kind sequential, but have not been able to get the class to
fill correctly. I am using a class as opposed to structure because I
want to have fixed size string arrays as some of the fields. Getting
an exception when trying to copy the byte array into the object
instance.
Thanks,

Imports System.Runtime.InteropServices

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
Dim len As Integer = 0
Dim ret As Integer = 0

' Get size of adapter info buffer (num of adapters x 640)
GetAdaptersInfo(IntPtr.Zero, len)

' Init byte buffer, pointer
Dim p As IntPtr = LocalAlloc(64, len)

' Get pointer to info
ret = GetAdaptersInfo(p, len)

' Fill byte array - THIS WORKS OK
Dim b(639) As Byte
System.Runtime.InteropServices.Marshal.Copy(p, b, 0, 640)

' Overlay object
Dim x As New AdapterInfo
' Marshall.SizeOf the object = 72. Shouldn't this be 640?

' THIS THROWS System.Argument exception
Dim gch As GCHandle = GCHandle.Alloc(x)
Marshal.Copy(b, 0, gch.AddrOfPinnedObject, 640)

' THIS appears to fill the first field only
Marshall.PtrToStructure(p, x)

End Sub

<DllImport("iphlpapi.dll", SetLastError:=True)> _
Public Shared Function GetAdaptersInfo(ByVal p As IntPtr, ByRef
pOutBufLen As Integer) As Integer
End Function

<DllImport("coredll.dll", SetLastError:=True)> _
Public Shared Function LocalAlloc(ByVal uFlags As Integer, ByVal
uBytes As Integer) As IntPtr
End Function

End Class

<StructLayout(LayoutKind.Sequential)> _
Public Class AdapterInfo
Public [Next] As Int32 ' 0
Public ComboIndex As Int32 ' 4
Public AdapterName(259) As String ' 8
Public AdapterDescription(135) As String ' 268
Public AddressLength As Int32 ' 400
Public Address(7) As Byte ' 404
Public Index As Int32 ' 412
Public Type As Int32 ' 416
Public DhcpEnabled As Int32 ' 420
Public CurrentIpAddress As Int32 '424
Public IpAddressList As IP_ADDR_STRING '428
Public GatewayList As IP_ADDR_STRING '468
Public DhcpServer As IP_ADDR_STRING ' 508
Public HaveWins As Int32 ' 548
Public PrimaryWinsServer As IP_ADDR_STRING ' 552
Public SecondaryWinsServer As IP_ADDR_STRING ' 592
Public LeaseObtained As Int32 ' 632
Public LeaseExpires As Int32 ' 636
End Class

<StructLayout(LayoutKind.Sequential)> _
Public Class IP_ADDR_STRING
Public [Next] As Int32 ' 0
Public IPAddress(15) As String ' 4
Public IPMask(15) As String ' 20
Public context As Integer ' 36
End Class ' 40
 
C

CB

Thanks. I've seen this and will write my own class, somewhat similar
to this, but with less code (and in VB :) Great blog, by the way..
 
A

Alex Feinman [MVP]

1. You want to use Marshal.PtrToStructure rather than
GCHandle.AddressOfPinnedObject
2. You are missing the MarshalAs attributes on the string filelds -
<MarshalAs(UnmanagedType.ByValTStr, SizeConst=128> _
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top