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? 10 4892
David - upgrade wizard is not all that great with api calls... That
said, you'll want to look at the System.Runtime.Interop namespace for
further infromation on marshaling to unmanaged code... Anyway, here is
a short bit of advice.
David Fort (donotspam) wrote: 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
My first stab at it would look like:
Public Structure NifInterfaceInfo
<MarshalAs (UnmanagedType.ByValArray, SizeConst=NIF_NAME_LEN)> _
Public interfaceName As Byte ()
<MarshalAs (UnmanagedType.ByValArray, SizeConst=DEV_ID_SIZE)> _
Public DeviceID As Byte ()
End Structure
From the loogs of the declare, this should work for you :)
--
Tom Shelton [MVP]
"Tom Shelton" wrote: David - upgrade wizard is not all that great with api calls... That said, you'll want to look at the System.Runtime.Interop namespace for further infromation on marshaling to unmanaged code... Anyway, here is a short bit of advice.
David Fort (donotspam) wrote: 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. ---------------- My first stab at it would look like:
Public Structure NifInterfaceInfo <MarshalAs (UnmanagedType.ByValArray, SizeConst=NIF_NAME_LEN)> _ Public interfaceName As Byte () <MarshalAs (UnmanagedType.ByValArray, SizeConst=DEV_ID_SIZE)> _ Public DeviceID As Byte () End Structure
From the loogs of the declare, this should work for you :)
-- Tom Shelton [MVP]
Thanks Tom,
I'm struggling with the info in the System.Runtime.Interop namespace help
documentation, but I'm trying. In an effort to reveal my VB and .Net
ignorance, I'd like to ask a few hopefully easy qustions:
1. by System.Runtime.Interop namespace, do you mean
System.Runtime.InteropServices?
2. in your "first stab" suggestion you proposed: <MarshalAs (UnmanagedType.ByValArray, SizeConst=NIF_NAME_LEN)> _ Public interfaceName As Byte ()
That didn't compile for me - it says "Name 'SizeConst' is not declared."
I changed it to SizeConst:=NIF_NAME_LEN, and that compiles, but I don't
understand the difference between := and = (and I see places in the help that
use = as you did)
3. Should i keep (and use) the Initialize Sub that the Upgrade wizard added?
Assuming I made the correct choices about the above (yes, :=, and yes), then
I get the error
-------------------
An unhandled exception of type 'System.ExecutionEngineException' occured in
Project1.exe
-------------------
So, I've been trying to dig through the help info on Interop, and realize I
don't even have the vocabulary to understand it.
Is an Array of Structures containing 2 fixed length Arrays a blittable type?
Will VB use a memory layout that matches the unmanaged stuff, or is there a
magic layer that will convert from a VB Array of VB Structures of VB arrays
to the C-style array of C-style Struct of C-style arrays?
If there is such a layer, is that the "marshaller"?
Since the argument to the unmanaged function is the address of array of
structs containing fixed lenth arrays, how does the marshaller know how many
structs are in the array? for example, in VB, the instance of the array of
structures of arrays is like this:
Public InterfaceInfo(MAX_INTERFACES) As NifInterfaceInfo
NifInterfaceInfo is a Structure containing arrays, like this: Public Structure NifInterfaceInfo <MarshalAs (UnmanagedType.ByValArray, SizeConst=NIF_NAME_LEN)> _ Public interfaceName As Byte () <MarshalAs (UnmanagedType.ByValArray, SizeConst=DEV_ID_SIZE)> _ Public DeviceID As Byte () End Structure
and the call is like this:
nifGetInterfaceList(SessionDesc, NoOfInterfaces, InterfaceInfo(0))
NoOfInterfaces tells the function how big the array InterfaceInfo is, but I
don't see how a marshaller could figure that out. (but this works in VB6, so
there must be a way).
In VB, will the array of structures of arrays be layed out like it would in
C, or will it get a bunch of stuff added, like upper and lower bounds?
The Interop help has a lot of stuff about tlbimp and midl and stuff like
that, but I don't see any idl files in my VB6 project and when i run tlbimp
against the .dll or the .lib files provided, it says they aren't valid type
libraries. Using Dependency Walker on the .DLL, i can find the function and
see its ordinal and stuff like that, but how does VB know what the signature
is? Is it all up to the Declare that I put in my VB code? Or is there some
check against the DLL?
Should I be concentrating on the Marshaling attributes on the members of the
Structure declaration, or might I also need to put something on the argument
list of the Declare Function statement? (or even on the instance of the
array of structs)
I don't really understand the difference between MarshalAs and
MarshalAsAttribute. In the Interop Namespace documentation, they refer to
System.Runtime.InteropServices.MarshalAsAttribute, but the examples just say
MarshalAs. Does Attribute just mean it is in <> and not really part of the
name? (i realize this question should clearly identify me as a VB newbie).
Thanks for your help, I apologize for being overwhelmed by the interop help
info. I'd really appreciate any suggestions/comments on my additional
questions to help guide me through the maze.
Best regards,
David
David Fort (donotspam) wrote: "Tom Shelton" wrote:
David - upgrade wizard is not all that great with api calls... That said, you'll want to look at the System.Runtime.Interop namespace for further infromation on marshaling to unmanaged code... Anyway, here is a short bit of advice.
David Fort (donotspam) wrote: 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. ---------------- My first stab at it would look like:
Public Structure NifInterfaceInfo <MarshalAs (UnmanagedType.ByValArray, SizeConst=NIF_NAME_LEN)> _ Public interfaceName As Byte () <MarshalAs (UnmanagedType.ByValArray, SizeConst=DEV_ID_SIZE)> _ Public DeviceID As Byte () End Structure
From the loogs of the declare, this should work for you :)
-- Tom Shelton [MVP]
David - I don't have time to cover all of these questions right now...
But, I will try and give a more complete answer latter. But, I will
try to answer some of them now...
Thanks Tom, I'm struggling with the info in the System.Runtime.Interop namespace help documentation, but I'm trying. In an effort to reveal my VB and .Net ignorance, I'd like to ask a few hopefully easy qustions: 1. by System.Runtime.Interop namespace, do you mean System.Runtime.InteropServices?
Yes - I ment InteropServices... Sorry about that.
2. in your "first stab" suggestion you proposed: <MarshalAs (UnmanagedType.ByValArray, SizeConst=NIF_NAME_LEN)> _ Public interfaceName As Byte () That didn't compile for me - it says "Name 'SizeConst' is not declared." I changed it to SizeConst:=NIF_NAME_LEN, and that compiles, but I don't understand the difference between := and = (and I see places in the help that use = as you did)
It should be := in VB.NET. I mostly work in C#, and so sometimes I
mangle the VB syntax... Again Sorry.
3. Should i keep (and use) the Initialize Sub that the Upgrade wizard added?
You don't need it if you using the structure in interop scenarios.
Assuming I made the correct choices about the above (yes, :=, and yes), then I get the error ------------------- An unhandled exception of type 'System.ExecutionEngineException' occured in Project1.exe -------------------
So, I've been trying to dig through the help info on Interop, and realize I don't even have the vocabulary to understand it.
Is an Array of Structures containing 2 fixed length Arrays a blittable type?
Blittable types are types that don't need special handling by the
marshaler. A one dimensional array of value types is normally a
blittable type - but, I'm not sure that would apply when used in side
of a structure because the marshaler has to allocate an array (base on
the SizeConst argument) when it is passed to a function.
Will VB use a memory layout that matches the unmanaged stuff, or is there a magic layer that will convert from a VB Array of VB Structures of VB arrays to the C-style array of C-style Struct of C-style arrays?
If there is such a layer, is that the "marshaller"?
The default memory layout should be fine most of the time. But, you
can change if by applying various attributes to the structure and the
fields. For example, by using the StructLayoutAttribute with the
LayoutKind.Explicit and the FieldOffsetAttribute you can essentially
imitate the passing of Unions to unmanaged code.
Since the argument to the unmanaged function is the address of array of structs containing fixed lenth arrays, how does the marshaller know how many structs are in the array? for example, in VB, the instance of the array of structures of arrays is like this: Public InterfaceInfo(MAX_INTERFACES) As NifInterfaceInfo
That would be the same in VB.NET.
NifInterfaceInfo is a Structure containing arrays, like this: Public Structure NifInterfaceInfo <MarshalAs (UnmanagedType.ByValArray, SizeConst=NIF_NAME_LEN)> _ Public interfaceName As Byte () <MarshalAs (UnmanagedType.ByValArray, SizeConst=DEV_ID_SIZE)> _ Public DeviceID As Byte () End Structure and the call is like this: nifGetInterfaceList(SessionDesc, NoOfInterfaces, InterfaceInfo(0))
NoOfInterfaces tells the function how big the array InterfaceInfo is, but I don't see how a marshaller could figure that out. (but this works in VB6, so there must be a way).
The marshaller can tell because your array is an instance of
System.Array and there for will have a length argument to tell how many
elements it contains.
In VB, will the array of structures of arrays be layed out like it would in C, or will it get a bunch of stuff added, like upper and lower bounds?
It will be laid out as it is in C.
The Interop help has a lot of stuff about tlbimp and midl and stuff like that, but I don't see any idl files in my VB6 project and when i run tlbimp against the .dll or the .lib files provided, it says they aren't valid type libraries. Using Dependency Walker on the .DLL, i can find the function and see its ordinal and stuff like that, but how does VB know what the signature is? Is it all up to the Declare that I put in my VB code? Or is there some check against the DLL?
It's up to the declare. You only need the tlbimp and midl stuff if
your working with a COM object library.
Should I be concentrating on the Marshaling attributes on the members of the Structure declaration, or might I also need to put something on the argument list of the Declare Function statement? (or even on the instance of the array of structs)
Sometimes :) It depends. I didn't look to closely at the declare. I
probably should have. I will try and go back and take a closer look at
that latter (if someone doesn't beat me to it).
I don't really understand the difference between MarshalAs and MarshalAsAttribute. In the Interop Namespace documentation, they refer to System.Runtime.InteropServices.MarshalAsAttribute, but the examples just say MarshalAs. Does Attribute just mean it is in <> and not really part of the name? (i realize this question should clearly identify me as a VB newbie).
MarshalAs and MarshalAsAttribute are the same thing. The compiler will
automatically change MarshalAs to MarshalAsAttribute. It's just
shortcut. Thanks for your help, I apologize for being overwhelmed by the interop help info. I'd really appreciate any suggestions/comments on my additional questions to help guide me through the maze.
Best regards, David
here are 4 interesting (in a geeklike way) new observations which lead me to
think we are close.
1. The DLL function is actually working a little bit before it throws the
exception.
2. The first byte of the first array in the structure is 0, and it shouldn't
be, but the rest of the bytes look ok
3. At the point of the exception, the Length of the first array contained
within the structure has been changed to 32, but the rest of them still say
33. (same for the other array contained with the struct)
4. Initialize, which simply does a ReDim DeviceID(DEV_ID_SIZE) (where
DEV_ID_SIZE is 32) creates an array of {Length=33}.
The function should have filled in 2 elements of the array, and it only
filled in one before it threw the exception.
A little more detail:
this is the function:
Declare Function nifGetInterfaceList Lib "nifbstd" (ByVal session As
Integer, ByRef numIntf As Short, ByRef info As NifInterfaceInfo) As Integer
this is the type of the argument (as in "First Stab")
Public Structure NifInterfaceInfo
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=NIF_NAME_LEN)> _
Public interfaceName As Byte()
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=DEV_ID_SIZE)> _
Public DeviceID As Byte()
Public Sub Initialize()
ReDim interfaceName(NIF_NAME_LEN)
ReDim DeviceID(DEV_ID_SIZE)
End Sub
End Structure
this is the instance:
Public InterfaceInfo(MAX_INTERFACES) As NifInterfaceInfo
and this is the function invocation:
nifGetInterfaceList(SessionDesc, NoOfInterfaces, InterfaceInfo(0))
So InterfaceInfo(0) gets filled in with expected data.
InterfaceInfo(1) is unchanged (and should have changed, because
NoOfInterfaces comes back as a 2)
InterfaceInfo(0).DeviceID is filled in correctly except for the first byte,
which is a 0.
The other values are shifted down. ie. the first byte of the DeviceID is in
InterfaceInfo(0).DeviceID(1).
InterfaceInfo(0).DeviceID {Length=32}
InterfaceInfo(1).DeviceID {Length=33}
"David Fort" wrote: 2. The first byte of the first array in the structure is 0, and it shouldn't be, but the rest of the bytes look ok .... InterfaceInfo(0).DeviceID {Length=32} InterfaceInfo(1).DeviceID {Length=33}
changing the structure declaration to:
Public Structure NifInterfaceInfo
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=NIF_NAME_LEN + 1)> _
Public interfaceName As Byte()
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=DEV_ID_SIZE + 1)> _
Public DeviceID As Byte()
Public Sub Initialize()
ReDim interfaceName(NIF_NAME_LEN)
ReDim DeviceID(DEV_ID_SIZE)
End Sub
End Structure
(note the +1 on the SizeConst)
seems to make the data line up in the right spots in the structure at the
first element of the array.
I'm still not getting anything in the remaining structures in the array, so
it feels like only the first element gets marshalled, then when the DLL
function tries to fill in the second element, it generates an exception
because the second element isn't there.
Does that sound like barking up the right tree? If so, how do you tell the
marshaller how many elements are in the array actually being passed?
Don't burn any calories on this question for now.
I just talked with National Instruments, the provider of the DLL, and they
have a .Net version ready for Beta to release in the next few days. I'll see
if that reveals the secret of how to marshal this array of structs.
News as it develops.
david
David Fort (donotspam) wrote: "David Fort" wrote: 2. The first byte of the first array in the structure is 0, and it shouldn't be, but the rest of the bytes look ok .... InterfaceInfo(0).DeviceID {Length=32} InterfaceInfo(1).DeviceID {Length=33}
changing the structure declaration to: Public Structure NifInterfaceInfo <MarshalAs(UnmanagedType.ByValArray, SizeConst:=NIF_NAME_LEN + 1)> _ Public interfaceName As Byte() <MarshalAs(UnmanagedType.ByValArray, SizeConst:=DEV_ID_SIZE + 1)> _ Public DeviceID As Byte() Public Sub Initialize() ReDim interfaceName(NIF_NAME_LEN) ReDim DeviceID(DEV_ID_SIZE) End Sub End Structure
(note the +1 on the SizeConst) seems to make the data line up in the right spots in the structure at the first element of the array.
I'm still not getting anything in the remaining structures in the array, so it feels like only the first element gets marshalled, then when the DLL function tries to fill in the second element, it generates an exception because the second element isn't there.
Your original declare was:
Declare Function nifGetInterfaceList Lib "nifbstd" (ByVal session As
Integer, ByRef numIntf As Short, ByRef info As NifInterfaceInfo) As
Integer
That should be changed to:
Declare Function nifGetInterfaceList Lib "nifbstd" (ByVal session As
Integer, ByRef numIntf As Short, ByVal info() As NifInterfaceInfo) As
Integer
When you call it, don't pass just the first element like in VB6 - just
pass the array... In other words, don't do:
nifGetInterfaceList (....., info (0))
do:
nifGetInterfaceList (...., info)
--
Tom Shelton [MVP]
"Tom Shelton" wrote:
Your original declare was:
Declare Function nifGetInterfaceList Lib "nifbstd" (ByVal session As Integer, ByRef numIntf As Short, ByRef info As NifInterfaceInfo) As Integer
That should be changed to:
Declare Function nifGetInterfaceList Lib "nifbstd" (ByVal session As Integer, ByRef numIntf As Short, ByVal info() As NifInterfaceInfo) As Integer
When you call it, don't pass just the first element like in VB6 - just pass the array... In other words, don't do:
nifGetInterfaceList (....., info (0))
do:
nifGetInterfaceList (...., info)
-- Tom Shelton [MVP]
I thought so too, and when i tried that, the function completes, but the
array is unchanged.
So I thought maybe this was the ticket: (same idea with 1 dim array, but
ByRef)
Declare Function nifGetInterfaceList Lib "nifbstd" (ByVal session As
Integer, ByRef numIntf As Short, ByRef info() As NifInterfaceInfo) As Integer
and that doesn't throw an exception, but the program exits at that point.
It doesn't give much of a hint why:
The program '[3444] Project1.exe' has exited with code 0 (0x0).
I'll see if I can get my hands on the .Net Beta version of this DLL and
hopefully the secrets will be revealed.
Thanks,
David
Here is the magic syntax:
<StructLayout(LayoutKind.Sequential)> _
Public Structure NifInterfaceInfo
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=NIF_NAME_LEN + 1)> _
Public interfaceName As Byte()
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=DEV_ID_SIZE + 1)> _
Public DeviceID As Byte()
Public Sub Initialize()
ReDim interfaceName(NIF_NAME_LEN)
ReDim DeviceID(DEV_ID_SIZE)
End Sub
End Structure
Declare Function nifGetInterfaceList Lib "nifbstd" (ByVal session As
Integer, ByRef numIntf As Short, <Out()> ByVal info As NifInterfaceInfo()) As
Integer
Public InterfaceInfo(MAX_INTERFACES) As NifInterfaceInfo
and call it like this:
nifGetInterfaceList(SessionDesc, NoOfInterfaces, InterfaceInfo)
So, the only change from Tom's last suggestion was the addition of <Out()>
in the function declaration on the third argument.
In summary, changes from what the Upgrade Wizard produced:
Add <StructLayout(LayoutKind.Sequential)> _
to the Structure declaration
Add <MarshalAs(UnmanagedType.ByValArray, SizeConst:=NIF_NAME_LEN +
1)> _
to the fields in the structure that are contained arrays
Add <Out()> to the third argument
change ByRef to ByVal in third argument
Change info to info() in the declaration of the function (or put the () on
the type name: <Out()> info as NifInterfaceInfo())
Change call of function to pass the whole array: fn(arrayname) instead of
passing the first element, as you might in C: fn(arrayname(0))
voila! success.
Thanks for your help, Tom.
Best regards,
David Fort
David Fort (donotspam) wrote: Here is the magic syntax:
<StructLayout(LayoutKind.Sequential)> _ Public Structure NifInterfaceInfo <MarshalAs(UnmanagedType.ByValArray, SizeConst:=NIF_NAME_LEN + 1)> _ Public interfaceName As Byte() <MarshalAs(UnmanagedType.ByValArray, SizeConst:=DEV_ID_SIZE + 1)> _ Public DeviceID As Byte() Public Sub Initialize() ReDim interfaceName(NIF_NAME_LEN) ReDim DeviceID(DEV_ID_SIZE) End Sub End Structure
Declare Function nifGetInterfaceList Lib "nifbstd" (ByVal session As Integer, ByRef numIntf As Short, <Out()> ByVal info As NifInterfaceInfo()) As Integer
Public InterfaceInfo(MAX_INTERFACES) As NifInterfaceInfo
and call it like this: nifGetInterfaceList(SessionDesc, NoOfInterfaces, InterfaceInfo)
So, the only change from Tom's last suggestion was the addition of <Out()> in the function declaration on the third argument.
David - I'm glad you got this figured out. I've been busy the last
couple of days, and wasn't able to respond.
--
Tom Shelton [MVP] This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics
by: Ivan |
last post by:
Hi All,
I have a problem with marshaling complex structures (containing numbers,
strings, arrays of another structures) to native C function in dll.
I have already posted same question to...
|
by: Eric Hendriks |
last post by:
// In an unmanaged DLL the following function must be called:
// int VFGeneralize(const BYTE * const * features);
// "features" parameter is supposed to be an array of byte arrays.
// function is...
|
by: kevin |
last post by:
Hi
I have a C struct that is of the following
typedef struct{
DWORD num_conversions; ...
short *sample_values;
....
|
by: Ivan |
last post by:
Hi All,
I have a problem with marshaling complex structures (containing numbers,
strings, arrays of another structures) to native C function in dll.
I have already posted same question to...
|
by: nicewenyan |
last post by:
I want to pass a managed c# byte (8 bit) array into a unmanaged c++
function:
extern "C" void AddData(unsigned int* data);
I use P/Invoke on managed side to do the marshaling as following:
...
|
by: cleanrabbit |
last post by:
Hello!
I hate having to do this, because im almost certain there is someone in the world that has come across this problem and i just havent found their solution yet, so i do appologise if this...
|
by: RobbieJosefson |
last post by:
I want to marshal a structure containing a variable length array which will be populated within a C++ dll. the structure is the following
Public Structure myStructure{
Public int size;...
|
by: Charming12 |
last post by:
Hi All,
I have a strange problem and due to my inefficiency with IntPtr i am unable to figure it out.
I have an structure something like:
public struct Detail
{
public int age;
public...
|
by: Charming12 |
last post by:
Hi All,
This is a problem which is eating my head from several days.
I have a structure which contains an array of elements as
public byte pinNumbers;
|
by: isladogs |
last post by:
The next Access Europe meeting will be on Wednesday 2 August 2023 starting at 18:00 UK time (6PM UTC+1) and finishing at about 19:15 (7.15PM)
The start time is equivalent to 19:00 (7PM) in Central...
|
by: erikbower65 |
last post by:
Here's a concise step-by-step guide for manually installing IntelliJ IDEA:
1. Download: Visit the official JetBrains website and download the IntelliJ IDEA Community or Ultimate edition based on...
|
by: kcodez |
last post by:
As a H5 game development enthusiast, I recently wrote a very interesting little game - Toy Claw ((http://claw.kjeek.com/))。Here I will summarize and share the development experience here, and hope it...
|
by: isladogs |
last post by:
The next Access Europe meeting will be on Wednesday 6 Sept 2023 starting at 18:00 UK time (6PM UTC+1) and finishing at about 19:15 (7.15PM)
The start time is equivalent to 19:00 (7PM) in Central...
|
by: Taofi |
last post by:
I try to insert a new record but the error message says the number of query names and destination fields are not the same
This are my field names
ID, Budgeted, Actual, Status and Differences
...
|
by: DJRhino1175 |
last post by:
When I run this code I get an error, its Run-time error# 424 Object required...This is my first attempt at doing something like this. I test the entire code and it worked until I added this -
If...
|
by: Rina0 |
last post by:
I am looking for a Python code to find the longest common subsequence of two strings. I found this blog post that describes the length of longest common subsequence problem and provides a solution in...
|
by: lllomh |
last post by:
Define the method first
this.state = {
buttonBackgroundColor: 'green',
isBlinking: false, // A new status is added to identify whether the button is blinking or not
}
autoStart=()=>{
|
by: DJRhino |
last post by:
Was curious if anyone else was having this same issue or not....
I was just Up/Down graded to windows 11 and now my access combo boxes are not acting right. With win 10 I could start typing...
| |