|
web
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
Marshal Structure containing arrays to function in DLLI'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? 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: Show quoteHide quote > Hi, My first stab at it would look like:> 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 > 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]
Show quote
Hide quote
"Tom Shelton" wrote: Thanks Tom,> > 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] > > 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)> _ That didn't compile for me - it says "Name 'SizeConst' is not declared."> Public interfaceName As Byte () 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 and the call is like this:> <MarshalAs (UnmanagedType.ByValArray, SizeConst=NIF_NAME_LEN)> _ > Public interfaceName As Byte () > <MarshalAs (UnmanagedType.ByValArray, SizeConst=DEV_ID_SIZE)> _ > Public DeviceID As Byte () > End Structure 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:
Show quoteHide quote > "Tom Shelton" wrote: David - I don't have time to cover all of these questions right now...> > > > > 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] > > > > > But, I will try and give a more complete answer latter. But, I will try to answer some of them now... > Thanks Tom, Yes - I ment InteropServices... Sorry about that.> 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: It should be := in VB.NET. I mostly work in C#, and so sometimes I> > <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) 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 Blittable types are types that don't need special handling by the> 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? > 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 The default memory layout should be fine most of the time. But, you> 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"? > 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 That would be the same in VB.NET.> 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 > Show quoteHide quote > NifInterfaceInfo is a Structure containing arrays, like this: The marshaller can tell because your array is an instance of> > 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). > 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 It will be laid out as it is in C.> 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 It's up to the declare. You only need the tlbimp and midl stuff if> 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? > your working with a COM object library. > Should I be concentrating on the Marshaling attributes on the members of the Sometimes :) It depends. I didn't look to closely at the declare. I> 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) > 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 MarshalAs and MarshalAsAttribute are the same thing. The compiler will> 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). > automatically change MarshalAs to MarshalAsAttribute. It's just shortcut. Show quoteHide quote > > 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: changing the structure declaration to:> 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} 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:
Show quoteHide quote > "David Fort" wrote: Your original declare was:> > 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. > 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]
Show quote
Hide quote
"Tom Shelton" wrote: I thought so too, and when i tried that, the function completes, but the > > > 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] > > 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:
Show quoteHide quote > Here is the magic syntax: David - I'm glad you got this figured out. I've been busy the last> > <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. > couple of days, and wasn't able to respond. -- Tom Shelton [MVP]
OOP object instance assignment in sub new()
Auto-Updates using MSI Scanning Option Group (VB 6 Option Button Control Array) ExitWindowsEx function not working. String, not Boolean VB.NET: RasDial + CallBacks + throwing events = frozen UI? Is there a Function and Function Argument generic self-reference? Passing an array of to a Sub minimize button click event? Treading for console applications in VB.NET |
|||||||||||||||||||||||