G
Guest
Hi,
I'm upgrading a VB6 app to VB.net and I'm having a problem with a call to a
function provided in a DLL.
The function takes the address of a structure which it will fill in with
values.
I get an error:
----------------
An unhandled exception of type 'System.NullReferenceException' occured in
Project1.exe
Additional Information: Object reference not set to an instance of an object.
----------------
Based on the UPGRADE_TODOs etc that the upgrade wizard put in my code, I
suspect the problem is with marshaling the VB struct to the unmanaged
function.
Below is a (rather long) description of how the VB looked in VB6, what the
wizard turned it into, the C signature of the function, and some of the
things I've tried.
I would be very grateful for suggestions on how to pass the structure
correctly or where to find a good explanation of the rules. Thanks!
in VB6, it was like this
' the structure that the function takes as a parameter
Public Type NifInterfaceInfo ' Interface Infor structure
interfaceName(NIF_NAME_LEN) As Byte
DeviceID(DEV_ID_SIZE) As Byte
End Type
' the declaration of the function that takes the NifInterfaceInfo struct
Declare Function nifGetInterfaceList Lib "nifbstd" (ByVal session As Long,
ByRef numIntf As Integer, ByRef info As NifInterfaceInfo) As Long
' an example of a subroutine which invokes the function
Private Sub OpenSess()
' Open a fieldbus Session
Ret (nifOpenSession(vbNull, SessionDesc))
' Pass the max interface number to function "nifGetInterfaceList"
NoOfInterfaces = MAX_INTERFACES
' Get all the interface information
Ret (nifGetInterfaceList(SessionDesc, NoOfInterfaces, InterfaceInfo(0)))
For i = 0 To NoOfInterfaces - 1
' The interfaceName and DeviceID are array of byte, need to be
converted by function "getString"
ListInterface.AddItem getString(InterfaceInfo(i).interfaceName)
Next
End Sub
The upgrade wizard did this:
Public Structure NifInterfaceInfo ' Interface Infor structure
<VBFixedArray(NIF_NAME_LEN)> Dim interfaceName() As Byte
<VBFixedArray(DEV_ID_SIZE)> Dim DeviceID() As Byte
'UPGRADE_TODO: "Initialize" must be called to initialize instances
of this structure. Click for more:
'ms-help://MS.VSCC.2003/commoner/redir/redirect.htm?keyword="vbup1026"'
Public Sub Initialize()
ReDim interfaceName(NIF_NAME_LEN)
ReDim DeviceID(DEV_ID_SIZE)
End Sub
End Structure
'UPGRADE_WARNING: Structure NifInterfaceInfo may require marshalling
attributes to be passed as an argument in this Declare statement. Click for
more: 'ms-help://MS.VSCC.2003/commoner/redir/redirect.htm?keyword="vbup1050"'
Declare Function nifGetInterfaceList Lib "nifbstd" (ByVal session As
Integer, ByRef numIntf As Short, ByRef info As NifInterfaceInfo) As Integer
Private Sub OpenSess()
' Open a fieldbus Session
Ret((nifOpenSession(VariantType.Null, SessionDesc)))
' Pass the max interface number to function "nifGetInterfaceList"
NoOfInterfaces = MAX_INTERFACES
' Get all the interface information
Ret((nifGetInterfaceList(SessionDesc, NoOfInterfaces,
InterfaceInfo(0))))
For i = 0 To NoOfInterfaces - 1
' The interfaceName and DeviceID are array of byte, need to be
converted by function "getString"
ListInterface.Items.Add(getString(InterfaceInfo(i).interfaceName))
Next
End Sub
--------------
The underlying C declarations are like this:
typedef struct nifInterfaceInfo_t {
char interfaceName[NIF_NAME_LEN];
char deviceID[DEV_ID_SIZE + 1];
} nifInterfaceInfo_t;
extern nifError_t nifGetInterfaceList(nifDesc_t ud, int16 *numInterfaces,
nifInterfaceInfo_t *info);
--------------
As suggested by the UPGRADE_TODO vbup1026, I added a call to Initialize()
like this:
Private Sub OpenSess()
' Open a fieldbus Session
Ret((nifOpenSession(VariantType.Null, SessionDesc)))
' Pass the max interface number to function "nifGetInterfaceList"
NoOfInterfaces = MAX_INTERFACES
InterfaceInfo.Initialize()
For i = InterfaceInfo.GetLowerBound(0) To
InterfaceInfo.GetUpperBound(0)
InterfaceInfo(i).Initialize()
Next
' Get all the interface information
Ret((nifGetInterfaceList(SessionDesc, NoOfInterfaces,
InterfaceInfo(0))))
For i = 0 To NoOfInterfaces - 1
' The interfaceName and DeviceID are array of byte, need to be
converted by function "getString"
ListInterface.Items.Add(getString(InterfaceInfo(i).interfaceName))
Next
End Sub
I examined InterfaceInfo in the debugger, and it looks ok following the
call(s) to Initialize().
The call to nifGetInterfaceList fails with an error
----------------
An unhandled exception of type 'System.NullReferenceException' occured in
Project1.exe
Additional Information: Object reference not set to an instance of an object.
----------------
if I add this
<StructLayout( LayoutKind.Sequential, CharSet:=CharSet.ANSI)>
to the structure declaration, I get the same error.
If I add MarshalAs attributes (as suggested by UPGRADE_WARNING: Structure
NifInterfaceInfo may require marshalling attributes to be passed as an
argument in this Declare statement. Click for more:
'ms-help://MS.VSCC.2003/commoner/redir/redirect.htm?keyword="vbup1050"):
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
Public Structure NifInterfaceInfo ' Interface Infor structure
<VBFixedArray(NIF_NAME_LEN), MarshalAs(UnmanagedType.ByValTStr,
SizeConst:=NIF_NAME_LEN)> Dim interfaceName() As Byte
<VBFixedArray(DEV_ID_SIZE), MarshalAs(UnmanagedType.ByValTStr,
SizeConst:=DEV_ID_SIZE)> Dim DeviceID() As Byte
'UPGRADE_TODO: "Initialize" must be called to initialize instances
of this structure. Click for more:
'ms-help://MS.VSCC.2003/commoner/redir/redirect.htm?keyword="vbup1026"'
Public Sub Initialize()
ReDim interfaceName(NIF_NAME_LEN)
ReDim DeviceID(DEV_ID_SIZE)
End Sub
End Structure
then I get error:
----------------
An unhandled exception of type 'System.TypeLoadException' occured in
Project1.exe
Additional Information: Can not marshal field interfaceName of type
NifInterfaceInfo: This type can not be marshaled as a structure field
----------------
Anyone have suggestions for the right way to pass a VB.net struct containing
fixed length arrays to a DLL?
I'm upgrading a VB6 app to VB.net and I'm having a problem with a call to a
function provided in a DLL.
The function takes the address of a structure which it will fill in with
values.
I get an error:
----------------
An unhandled exception of type 'System.NullReferenceException' occured in
Project1.exe
Additional Information: Object reference not set to an instance of an object.
----------------
Based on the UPGRADE_TODOs etc that the upgrade wizard put in my code, I
suspect the problem is with marshaling the VB struct to the unmanaged
function.
Below is a (rather long) description of how the VB looked in VB6, what the
wizard turned it into, the C signature of the function, and some of the
things I've tried.
I would be very grateful for suggestions on how to pass the structure
correctly or where to find a good explanation of the rules. Thanks!
in VB6, it was like this
' the structure that the function takes as a parameter
Public Type NifInterfaceInfo ' Interface Infor structure
interfaceName(NIF_NAME_LEN) As Byte
DeviceID(DEV_ID_SIZE) As Byte
End Type
' the declaration of the function that takes the NifInterfaceInfo struct
Declare Function nifGetInterfaceList Lib "nifbstd" (ByVal session As Long,
ByRef numIntf As Integer, ByRef info As NifInterfaceInfo) As Long
' an example of a subroutine which invokes the function
Private Sub OpenSess()
' Open a fieldbus Session
Ret (nifOpenSession(vbNull, SessionDesc))
' Pass the max interface number to function "nifGetInterfaceList"
NoOfInterfaces = MAX_INTERFACES
' Get all the interface information
Ret (nifGetInterfaceList(SessionDesc, NoOfInterfaces, InterfaceInfo(0)))
For i = 0 To NoOfInterfaces - 1
' The interfaceName and DeviceID are array of byte, need to be
converted by function "getString"
ListInterface.AddItem getString(InterfaceInfo(i).interfaceName)
Next
End Sub
The upgrade wizard did this:
Public Structure NifInterfaceInfo ' Interface Infor structure
<VBFixedArray(NIF_NAME_LEN)> Dim interfaceName() As Byte
<VBFixedArray(DEV_ID_SIZE)> Dim DeviceID() As Byte
'UPGRADE_TODO: "Initialize" must be called to initialize instances
of this structure. Click for more:
'ms-help://MS.VSCC.2003/commoner/redir/redirect.htm?keyword="vbup1026"'
Public Sub Initialize()
ReDim interfaceName(NIF_NAME_LEN)
ReDim DeviceID(DEV_ID_SIZE)
End Sub
End Structure
'UPGRADE_WARNING: Structure NifInterfaceInfo may require marshalling
attributes to be passed as an argument in this Declare statement. Click for
more: 'ms-help://MS.VSCC.2003/commoner/redir/redirect.htm?keyword="vbup1050"'
Declare Function nifGetInterfaceList Lib "nifbstd" (ByVal session As
Integer, ByRef numIntf As Short, ByRef info As NifInterfaceInfo) As Integer
Private Sub OpenSess()
' Open a fieldbus Session
Ret((nifOpenSession(VariantType.Null, SessionDesc)))
' Pass the max interface number to function "nifGetInterfaceList"
NoOfInterfaces = MAX_INTERFACES
' Get all the interface information
Ret((nifGetInterfaceList(SessionDesc, NoOfInterfaces,
InterfaceInfo(0))))
For i = 0 To NoOfInterfaces - 1
' The interfaceName and DeviceID are array of byte, need to be
converted by function "getString"
ListInterface.Items.Add(getString(InterfaceInfo(i).interfaceName))
Next
End Sub
--------------
The underlying C declarations are like this:
typedef struct nifInterfaceInfo_t {
char interfaceName[NIF_NAME_LEN];
char deviceID[DEV_ID_SIZE + 1];
} nifInterfaceInfo_t;
extern nifError_t nifGetInterfaceList(nifDesc_t ud, int16 *numInterfaces,
nifInterfaceInfo_t *info);
--------------
As suggested by the UPGRADE_TODO vbup1026, I added a call to Initialize()
like this:
Private Sub OpenSess()
' Open a fieldbus Session
Ret((nifOpenSession(VariantType.Null, SessionDesc)))
' Pass the max interface number to function "nifGetInterfaceList"
NoOfInterfaces = MAX_INTERFACES
InterfaceInfo.Initialize()
For i = InterfaceInfo.GetLowerBound(0) To
InterfaceInfo.GetUpperBound(0)
InterfaceInfo(i).Initialize()
Next
' Get all the interface information
Ret((nifGetInterfaceList(SessionDesc, NoOfInterfaces,
InterfaceInfo(0))))
For i = 0 To NoOfInterfaces - 1
' The interfaceName and DeviceID are array of byte, need to be
converted by function "getString"
ListInterface.Items.Add(getString(InterfaceInfo(i).interfaceName))
Next
End Sub
I examined InterfaceInfo in the debugger, and it looks ok following the
call(s) to Initialize().
The call to nifGetInterfaceList fails with an error
----------------
An unhandled exception of type 'System.NullReferenceException' occured in
Project1.exe
Additional Information: Object reference not set to an instance of an object.
----------------
if I add this
<StructLayout( LayoutKind.Sequential, CharSet:=CharSet.ANSI)>
to the structure declaration, I get the same error.
If I add MarshalAs attributes (as suggested by UPGRADE_WARNING: Structure
NifInterfaceInfo may require marshalling attributes to be passed as an
argument in this Declare statement. Click for more:
'ms-help://MS.VSCC.2003/commoner/redir/redirect.htm?keyword="vbup1050"):
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
Public Structure NifInterfaceInfo ' Interface Infor structure
<VBFixedArray(NIF_NAME_LEN), MarshalAs(UnmanagedType.ByValTStr,
SizeConst:=NIF_NAME_LEN)> Dim interfaceName() As Byte
<VBFixedArray(DEV_ID_SIZE), MarshalAs(UnmanagedType.ByValTStr,
SizeConst:=DEV_ID_SIZE)> Dim DeviceID() As Byte
'UPGRADE_TODO: "Initialize" must be called to initialize instances
of this structure. Click for more:
'ms-help://MS.VSCC.2003/commoner/redir/redirect.htm?keyword="vbup1026"'
Public Sub Initialize()
ReDim interfaceName(NIF_NAME_LEN)
ReDim DeviceID(DEV_ID_SIZE)
End Sub
End Structure
then I get error:
----------------
An unhandled exception of type 'System.TypeLoadException' occured in
Project1.exe
Additional Information: Can not marshal field interfaceName of type
NifInterfaceInfo: This type can not be marshaled as a structure field
----------------
Anyone have suggestions for the right way to pass a VB.net struct containing
fixed length arrays to a DLL?