Calling into C++ DLL with structure - Is this code correct?

P

Paul Coene

The code below is snipets from my application.

I believe I have the LoadLibrary and the GetProcAddress code down pat. Several
other functions in this program get through the API, and even the ones where I
pass integers by reference work and get filled in.

My question is can I do a Structure this way? I know at least part of the
structure is working, because the DLL reacts correctly to the ProtocolID field.

My fear is that perhaps only the 1st of the (3) structures is getting through
correctly, as I pass three in a row and maybe I have some problem there? I
can't get this API call to accept 3 structures that look valid, so I fear some
corruption along the way.

Another key is the API wants a NULL pointer for the 3rd structure. You can see
below I try to do this with the nothing keyword.... Not sure about this either.

Code snips below:



Public Structure PASSTHRU_MSG
Dim ProtocolID As Integer
Dim RxStatus As Integer
Dim TxFlags As Integer
Dim Timestamp As Integer
Dim DataSize As Integer
Dim ExtraDataIndex As Integer
Dim Data() As Byte
End Structure

Private Delegate Function dPassThruStartMsgFilter(ByVal channelid As Integer, _
ByVal filtertype As Integer, _
ByRef pmaskmap As PASSTHRU_MSG, _
ByRef pPatternMsg As PASSTHRU_MSG, ByRef
pflowcontrolmsg As PASSTHRU_MSG, _ ByRef
pfilterid As Integer) As Integer

Private hPassThruStartMsgFilter As Integer

( I use LoadLibrary and GetProcAddress to get hPassThruStartMsgFilter filled
in. Left out for conciseness)


Public Function PassThruStartMsgFilter(ByVal ChannelId As Integer, _
ByVal FilterType As Integer, _
ByRef pMaskMsg As PASSTHRU_MSG, _
ByRef pPatternMask As PASSTHRU_MSG, _
ByRef pFlowControlMsg As PASSTHRU_MSG, _
ByRef pFilterId As Integer) As Integer

Dim arg() As Object
Dim ret As Integer

pFlowControlMsg.Data = Nothing
arg = New Object() {ChannelId, FilterType, pMaskMsg, pPatternMask, _
pFlowControlMsg, pFilterId}
ret = Marshal.GetDelegateForFunctionPointer(hPassThruStartMsgFilter, _
GetType(dPassThruStartMsgFilter)).DynamicInvoke(arg)

If ret = 0 Then
pFilterId = arg(5)
Form1.Status.Text += "Connection Filter(" + ChannelId.ToString _
+ ") Set" + vbNewLine
Else
Form1.Status.Text += "Connection Filter Failed: " + ret.ToString + _
vbNewLine
End If

Return ret
End Function
 
T

Tom Shelton

The code below is snipets from my application.

I believe I have the LoadLibrary and the GetProcAddress code down pat. Several
other functions in this program get through the API, and even the ones where I
pass integers by reference work and get filled in.

My question is can I do a Structure this way? I know at least part of the
structure is working, because the DLL reacts correctly to the ProtocolID field.

My fear is that perhaps only the 1st of the (3) structures is getting through
correctly, as I pass three in a row and maybe I have some problem there? I
can't get this API call to accept 3 structures that look valid, so I fear some
corruption along the way.

Another key is the API wants a NULL pointer for the 3rd structure. You can see
below I try to do this with the nothing keyword.... Not sure about this either.

Code snips below:

What is the C/C++ delcartions for this structure? Wat is the C/C++
delcaration for the API function? The Data() As Byte member looks
questionable, since it is really only going to be pointer to an array.
So, it most likely should be declared as an IntPtr (if the function
allocates a dynamic array), and then you would use the functions in the
Marshal class to get the data from the pointer (and most likely free the
unmanaged memory as well)... Or, this is a fixed array and you need to
add a MarshalAs attribute to this member.

It's hard to tell with out seeing the native declaration.
Public Structure PASSTHRU_MSG
Dim ProtocolID As Integer
Dim RxStatus As Integer
Dim TxFlags As Integer
Dim Timestamp As Integer
Dim DataSize As Integer
Dim ExtraDataIndex As Integer
Dim Data() As Byte
End Structure
Private Delegate Function dPassThruStartMsgFilter(ByVal channelid As Integer, _
ByVal filtertype As Integer, _
ByRef pmaskmap As PASSTHRU_MSG, _
ByRef pPatternMsg As PASSTHRU_MSG, ByRef
pflowcontrolmsg As PASSTHRU_MSG, _ ByRef
pfilterid As Integer) As Integer

Private hPassThruStartMsgFilter As Integer

( I use LoadLibrary and GetProcAddress to get hPassThruStartMsgFilter filled
in. Left out for conciseness)
Is that really necessary? You can't just pass a delegate?
 
P

Paul Coene

What is the C/C++ delcartions for this structure? Wat is the C/C++
delcaration for the API function? The Data() As Byte member looks
questionable, since it is really only going to be pointer to an array.
So, it most likely should be declared as an IntPtr (if the function
allocates a dynamic array), and then you would use the functions in the
Marshal class to get the data from the pointer (and most likely free the
unmanaged memory as well)... Or, this is a fixed array and you need to
add a MarshalAs attribute to this member.

C++ Version of Structure is:

6 longs + unsigned char Data[4128]

All I have is the documentation that documents the structure and the DLL.
The first long is getting through, as the DLL reacts to it. I can't say
for sure after that.

I had tried the following and it always caused exceptions. I also need to
put binary data into this field so String did not work. Maybe I should
try a variant with Byte?

Ideas? Thanks for the response.

'<VBFixedString(4128), System.Runtime.InteropServices.MarshalAs( _
System.Runtime.InteropServices.UnmanagedType.ByValTStr, _
SizeConst:=4128)> Public Data As String


Is that really necessary? You can't just pass a delegate?

I won't know even the name of the dll until runtime - its found in the
registry.
 
P

Paul Coene

Or, this is a fixed array and you need to
add a MarshalAs attribute to this member.


I have been looking at this and I agree. I'm so new to this and
the syntax that I'm stymied.

I tried:

<VBFixedArray(4127), System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst:=4127)> Public Data() As Byte

as an entry in the structure. This does not crash. I redim this field as
4127 long and send it. The data I fill it in with is valid, but the
DLL still says invalid data message.
 
T

Tom Shelton

What is the C/C++ delcartions for this structure? Wat is the C/C++
delcaration for the API function? The Data() As Byte member looks
questionable, since it is really only going to be pointer to an array.
So, it most likely should be declared as an IntPtr (if the function
allocates a dynamic array), and then you would use the functions in the
Marshal class to get the data from the pointer (and most likely free the
unmanaged memory as well)... Or, this is a fixed array and you need to
add a MarshalAs attribute to this member.

C++ Version of Structure is:

6 longs + unsigned char Data[4128]

Ok...

Structure TheStruct
Public Long1 As Integer
Public Long2 As Integer
Public Long3 As Integer
Public Long4 As Integer
Public Long5 As Integer
Public Long6 As Integer

' SizeConst is the number of elements in the array, not the
' last index as in VB.
<MarshalAs (UnmanagedType.ByValArray, SizeConst:=4128> _
Public Data() As Byte
End Structure
 
P

Paul Coene

Ok...

Structure TheStruct
Public Long1 As Integer
Public Long2 As Integer
Public Long3 As Integer
Public Long4 As Integer
Public Long5 As Integer
Public Long6 As Integer

' SizeConst is the number of elements in the array, not the
' last index as in VB.
<MarshalAs (UnmanagedType.ByValArray, SizeConst:=4128> _
Public Data() As Byte
End Structure


Thank you.

I am pretty sure I had that once before, but I was unsure of myself
and the API was still failing, so I kept changing it.

Here's the deal. I got my hands on the API source code.

The API call:

Public Function PassThruStartMsgFilter(ByVal ChannelId As Integer, _
ByVal FilterType As Integer, _
ByRef pMaskMsg As PASSTHRU_MSG, _
ByRef pPatternMask As PASSTHRU_MSG, _
ByRef pFlowControlMsg As PASSTHRU_MSG, _
ByRef pFilterId As Integer) As Integer


Sends this structure 3 times. In all of the cases I use, I need
to send the 3rd instance of PASSTRUR_MSG as a null pointer. Looking
at their code, if it is NOT a null pointer, it will indeed give me
the error I am getting.

I pass this using the nothing keyword for that parameter. However,
it's not quite that simple, as I use Dynamic invoke and ParamArray:

pFlowControlMsg.Data = Nothing
arg = New Object() {ChannelId, FilterType, pMaskMsg, pPatternMask, _
pFlowControlMsg, pFilterId}
ret = Marshal.GetDelegateForFunctionPointer(hPassThruStartMsgFilter, _
GetType(dPassThruStartMsgFilter)).DynamicInvoke(arg)

Do you think the Nothing is getting through, or will this confuse
the Marshall stuff? It seems to me after thinking about it, that
that layer might just pass an real pointer to a constructed array?
 
P

Paul Coene

Correction: This is how the code looks: I Had posted the wrong
line.

pFlowControlMsg = Nothing
 
P

Paul Coene

On Fri, 22 Feb 2008 13:42:08 -0600, Paul Coene wrote:

I'm set. I read that marshal can't deal with NULL all on its own.

I changed the API to send an IntPtr and sent Int.Zero.

This worked.

I am a bit concerned that I'll need to learn how to get valid
data into that IntPtr if I ever need to send that field, but that's
work for me, not you all ;)
 

Ask a Question

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

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

Ask a Question

Top