473,715 Members | 5,945 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Marshal Structure containing arrays to function in DLL

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.NullRef erenceException ' 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 NifInterfaceInf o ' Interface Infor structure
interfaceName(N IF_NAME_LEN) As Byte
DeviceID(DEV_ID _SIZE) As Byte
End Type

' the declaration of the function that takes the NifInterfaceInf o struct
Declare Function nifGetInterface List Lib "nifbstd" (ByVal session As Long,
ByRef numIntf As Integer, ByRef info As NifInterfaceInf o) 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 "nifGetInterfac eList"
NoOfInterfaces = MAX_INTERFACES

' Get all the interface information
Ret (nifGetInterfac eList(SessionDe sc, 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.A ddItem getString(Inter faceInfo(i).int erfaceName)
Next

End Sub

The upgrade wizard did this:
Public Structure NifInterfaceInf o ' Interface Infor structure
<VBFixedArray(N IF_NAME_LEN)> Dim interfaceName() As Byte
<VBFixedArray(D EV_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?ke yword="vbup1026 "'
Public Sub Initialize()
ReDim interfaceName(N IF_NAME_LEN)
ReDim DeviceID(DEV_ID _SIZE)
End Sub
End Structure

'UPGRADE_WARNIN G: Structure NifInterfaceInf o 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?ke yword="vbup1050 "'
Declare Function nifGetInterface List Lib "nifbstd" (ByVal session As
Integer, ByRef numIntf As Short, ByRef info As NifInterfaceInf o) As Integer
Private Sub OpenSess()
' Open a fieldbus Session
Ret((nifOpenSes sion(VariantTyp e.Null, SessionDesc)))

' Pass the max interface number to function "nifGetInterfac eList"
NoOfInterfaces = MAX_INTERFACES

' Get all the interface information
Ret((nifGetInte rfaceList(Sessi onDesc, 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.I tems.Add(getStr ing(InterfaceIn fo(i).interface Name))
Next

End Sub

--------------

The underlying C declarations are like this:
typedef struct nifInterfaceInf o_t {
char interfaceName[NIF_NAME_LEN];
char deviceID[DEV_ID_SIZE + 1];
} nifInterfaceInf o_t;

extern nifError_t nifGetInterface List(nifDesc_t ud, int16 *numInterfaces,
nifInterfaceInf o_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((nifOpenSes sion(VariantTyp e.Null, SessionDesc)))

' Pass the max interface number to function "nifGetInterfac eList"
NoOfInterfaces = MAX_INTERFACES

InterfaceInfo.I nitialize()
For i = InterfaceInfo.G etLowerBound(0) To
InterfaceInfo.G etUpperBound(0)
InterfaceInfo(i ).Initialize()
Next

' Get all the interface information
Ret((nifGetInte rfaceList(Sessi onDesc, 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.I tems.Add(getStr ing(InterfaceIn fo(i).interface Name))
Next

End Sub

I examined InterfaceInfo in the debugger, and it looks ok following the
call(s) to Initialize().

The call to nifGetInterface List fails with an error
----------------
An unhandled exception of type 'System.NullRef erenceException ' occured in
Project1.exe

Additional Information: Object reference not set to an instance of an object.
----------------

if I add this
<StructLayout ( LayoutKind.Sequ ential, CharSet:=CharSe t.ANSI)>

to the structure declaration, I get the same error.
If I add MarshalAs attributes (as suggested by UPGRADE_WARNING : Structure
NifInterfaceInf o 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?ke yword="vbup1050 "):

<StructLayout(L ayoutKind.Seque ntial, CharSet:=CharSe t.Ansi)> _
Public Structure NifInterfaceInf o ' Interface Infor structure
<VBFixedArray(N IF_NAME_LEN), MarshalAs(Unman agedType.ByValT Str,
SizeConst:=NIF_ NAME_LEN)> Dim interfaceName() As Byte
<VBFixedArray(D EV_ID_SIZE), MarshalAs(Unman agedType.ByValT Str,
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?ke yword="vbup1026 "'
Public Sub Initialize()
ReDim interfaceName(N IF_NAME_LEN)
ReDim DeviceID(DEV_ID _SIZE)
End Sub
End Structure

then I get error:
----------------
An unhandled exception of type 'System.TypeLoa dException' occured in
Project1.exe

Additional Information: Can not marshal field interfaceName of type
NifInterfaceInf o: 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?
Jun 12 '06 #1
10 4992

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.NullRef erenceException ' 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 NifInterfaceInf o ' Interface Infor structure
interfaceName(N IF_NAME_LEN) As Byte
DeviceID(DEV_ID _SIZE) As Byte
End Type

' the declaration of the function that takes the NifInterfaceInf o struct
Declare Function nifGetInterface List Lib "nifbstd" (ByVal session As Long,
ByRef numIntf As Integer, ByRef info As NifInterfaceInf o) 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 "nifGetInterfac eList"
NoOfInterfaces = MAX_INTERFACES

' Get all the interface information
Ret (nifGetInterfac eList(SessionDe sc, 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.A ddItem getString(Inter faceInfo(i).int erfaceName)
Next

End Sub

The upgrade wizard did this:
Public Structure NifInterfaceInf o ' Interface Infor structure
<VBFixedArray(N IF_NAME_LEN)> Dim interfaceName() As Byte
<VBFixedArray(D EV_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?ke yword="vbup1026 "'
Public Sub Initialize()
ReDim interfaceName(N IF_NAME_LEN)
ReDim DeviceID(DEV_ID _SIZE)
End Sub
End Structure

My first stab at it would look like:

Public Structure NifInterfaceInf o
<MarshalAs (UnmanagedType. ByValArray, SizeConst=NIF_N AME_LEN)> _
Public interfaceName As Byte ()
<MarshalAs (UnmanagedType. ByValArray, SizeConst=DEV_I D_SIZE)> _
Public DeviceID As Byte ()
End Structure
From the loogs of the declare, this should work for you :)


--
Tom Shelton [MVP]

Jun 12 '06 #2


"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.NullRef erenceException ' 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 NifInterfaceInf o
<MarshalAs (UnmanagedType. ByValArray, SizeConst=NIF_N AME_LEN)> _
Public interfaceName As Byte ()
<MarshalAs (UnmanagedType. ByValArray, SizeConst=DEV_I D_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_N AME_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.Executi onEngineExcepti on' 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(M AX_INTERFACES) As NifInterfaceInf o

NifInterfaceInf o is a Structure containing arrays, like this: Public Structure NifInterfaceInf o
<MarshalAs (UnmanagedType. ByValArray, SizeConst=NIF_N AME_LEN)> _
Public interfaceName As Byte ()
<MarshalAs (UnmanagedType. ByValArray, SizeConst=DEV_I D_SIZE)> _
Public DeviceID As Byte ()
End Structure


and the call is like this:
nifGetInterface List(SessionDes c, 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
MarshalAsAttrib ute. In the Interop Namespace documentation, they refer to
System.Runtime. InteropServices .MarshalAsAttri bute, 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
Jun 13 '06 #3

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.NullRef erenceException ' 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 NifInterfaceInf o
<MarshalAs (UnmanagedType. ByValArray, SizeConst=NIF_N AME_LEN)> _
Public interfaceName As Byte ()
<MarshalAs (UnmanagedType. ByValArray, SizeConst=DEV_I D_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_N AME_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.Executi onEngineExcepti on' 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 StructLayoutAtt ribute with the
LayoutKind.Expl icit and the FieldOffsetAttr ibute 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(M AX_INTERFACES) As NifInterfaceInf o

That would be the same in VB.NET.
NifInterfaceInf o is a Structure containing arrays, like this:
Public Structure NifInterfaceInf o
<MarshalAs (UnmanagedType. ByValArray, SizeConst=NIF_N AME_LEN)> _
Public interfaceName As Byte ()
<MarshalAs (UnmanagedType. ByValArray, SizeConst=DEV_I D_SIZE)> _
Public DeviceID As Byte ()
End Structure
and the call is like this:
nifGetInterface List(SessionDes c, 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
MarshalAsAttrib ute. In the Interop Namespace documentation, they refer to
System.Runtime. InteropServices .MarshalAsAttri bute, 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 MarshalAsAttrib ute are the same thing. The compiler will
automatically change MarshalAs to MarshalAsAttrib ute. 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


Jun 13 '06 #4
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 nifGetInterface List Lib "nifbstd" (ByVal session As
Integer, ByRef numIntf As Short, ByRef info As NifInterfaceInf o) As Integer

this is the type of the argument (as in "First Stab")
Public Structure NifInterfaceInf o
<MarshalAs(Unma nagedType.ByVal Array, SizeConst:=NIF_ NAME_LEN)> _
Public interfaceName As Byte()
<MarshalAs(Unma nagedType.ByVal Array, SizeConst:=DEV_ ID_SIZE)> _
Public DeviceID As Byte()
Public Sub Initialize()
ReDim interfaceName(N IF_NAME_LEN)
ReDim DeviceID(DEV_ID _SIZE)
End Sub
End Structure

this is the instance:
Public InterfaceInfo(M AX_INTERFACES) As NifInterfaceInf o

and this is the function invocation:
nifGetInterface List(SessionDes c, 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}
Jun 14 '06 #5


"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 NifInterfaceInf o
<MarshalAs(Unma nagedType.ByVal Array, SizeConst:=NIF_ NAME_LEN + 1)> _
Public interfaceName As Byte()
<MarshalAs(Unma nagedType.ByVal Array, SizeConst:=DEV_ ID_SIZE + 1)> _
Public DeviceID As Byte()
Public Sub Initialize()
ReDim interfaceName(N IF_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?
Jun 14 '06 #6
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
Jun 14 '06 #7

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 NifInterfaceInf o
<MarshalAs(Unma nagedType.ByVal Array, SizeConst:=NIF_ NAME_LEN + 1)> _
Public interfaceName As Byte()
<MarshalAs(Unma nagedType.ByVal Array, SizeConst:=DEV_ ID_SIZE + 1)> _
Public DeviceID As Byte()
Public Sub Initialize()
ReDim interfaceName(N IF_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 nifGetInterface List Lib "nifbstd" (ByVal session As
Integer, ByRef numIntf As Short, ByRef info As NifInterfaceInf o) As
Integer

That should be changed to:

Declare Function nifGetInterface List Lib "nifbstd" (ByVal session As
Integer, ByRef numIntf As Short, ByVal info() As NifInterfaceInf o) 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:

nifGetInterface List (....., info (0))

do:

nifGetInterface List (...., info)

--
Tom Shelton [MVP]

Jun 14 '06 #8


"Tom Shelton" wrote:


Your original declare was:

Declare Function nifGetInterface List Lib "nifbstd" (ByVal session As
Integer, ByRef numIntf As Short, ByRef info As NifInterfaceInf o) As
Integer

That should be changed to:

Declare Function nifGetInterface List Lib "nifbstd" (ByVal session As
Integer, ByRef numIntf As Short, ByVal info() As NifInterfaceInf o) 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:

nifGetInterface List (....., info (0))

do:

nifGetInterface List (...., 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 nifGetInterface List Lib "nifbstd" (ByVal session As
Integer, ByRef numIntf As Short, ByRef info() As NifInterfaceInf o) 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
Jun 14 '06 #9
Here is the magic syntax:

<StructLayout(L ayoutKind.Seque ntial)> _
Public Structure NifInterfaceInf o
<MarshalAs(Unma nagedType.ByVal Array, SizeConst:=NIF_ NAME_LEN + 1)> _
Public interfaceName As Byte()
<MarshalAs(Unma nagedType.ByVal Array, SizeConst:=DEV_ ID_SIZE + 1)> _
Public DeviceID As Byte()
Public Sub Initialize()
ReDim interfaceName(N IF_NAME_LEN)
ReDim DeviceID(DEV_ID _SIZE)
End Sub
End Structure
Declare Function nifGetInterface List Lib "nifbstd" (ByVal session As
Integer, ByRef numIntf As Short, <Out()> ByVal info As NifInterfaceInf o()) As
Integer

Public InterfaceInfo(M AX_INTERFACES) As NifInterfaceInf o
and call it like this:
nifGetInterface List(SessionDes c, 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(L ayoutKind.Seque ntial)> _
to the Structure declaration
Add <MarshalAs(Unma nagedType.ByVal Array, 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 NifInterfaceInf o())
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
Jun 16 '06 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
1503
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 .compactframework thread, but nobody helped. main problem is that I have tried all the workarounds I have found in the Inet but nothing worked... I tried passing IntPtr, Byte Arrays, Serialisation, even used OpenNETCF, but
1
7227
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 Marshaled as follows: static extern int VFGeneralize(byte features); In C# I have the following: // Allocate memory to store "Count" references to byte arrays
3
3286
by: kevin | last post by:
Hi I have a C struct that is of the following typedef struct{ DWORD num_conversions; ... short *sample_values; ....
0
1640
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 .compactframework thread, but nobody helped. main problem is that I have tried all the workarounds I have found in the Inet but nothing worked... I tried passing IntPtr, Byte Arrays, Serialisation, even used OpenNETCF, but
1
6309
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: public static extern int AddData(IntPtr data);
4
4721
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 has already been covered. I have been trying to learn c# as fast as possible in the last month and in doing so i have been re-visiting old C/C++ problems and trying to overcome them in C#. What i have is a very complex serise of structures. Id...
0
2102
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; Public myInsideStructure inside; }; The myInsideStructure just contains a string. The problem is the size of the myInsideStructure wont be known until runtime and the size variable will have the number of posts in the myInsideStructure structure...
0
2129
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 Detail(int _age)
3
3310
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;
0
8821
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
8718
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
9340
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
9047
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
1
6646
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
4738
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
3175
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
2539
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2118
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.