How to receive an array of doubles using VB from a C DLL

N

Neville Lang

Hi all,

Here is a problem I first struck a while back in the Compact Framework. I am
now using the full Framework (v2.0) and wanted to know whether there is
anyway around this issue without building separate shim code in another DLL.

Here is the layout of the external C DLL function:

int thisFunction( [in] double a, [in] int b, [out] double* c)

The double* c argument passes back an array of 6 doubles.

My VB code is like this:

<DllImport("External.DLL")> _
Public Shared Function thisFunction( ByVal a As Double, ByVal b As Integer,
ByRef c As Double() ) As Integer
End Function
...
...
...
Dim iRet As Integer
Dim a As Double
Dim b As Integer
Dim c(5) As Double

a = 36.12
b = 4

iRet = thisFunction( a, b, c )
....
....

At the moment, the call to this function is crashing. What is the best
solution for this type of problem on the full Framework?

Regards,
Neville Lang
 
T

tomb

Is that an old C dll, or a newer C++ dll? If it's old, it may be using
a 16 bit int, but you are passing it a 32 bit int. That may be what's
making it crash, rather than the array of doubles.

T
 
N

Neville Lang

The DLL is using 32-bit INTs, if that is any help.

Regards,
Neville Lang



tomb said:
Is that an old C dll, or a newer C++ dll? If it's old, it may be using a
16 bit int, but you are passing it a 32 bit int. That may be what's
making it crash, rather than the array of doubles.

T

Neville said:
Hi all,

Here is a problem I first struck a while back in the Compact Framework. I
am now using the full Framework (v2.0) and wanted to know whether there is
anyway around this issue without building separate shim code in another
DLL.

Here is the layout of the external C DLL function:

int thisFunction( [in] double a, [in] int b, [out] double* c)

The double* c argument passes back an array of 6 doubles.

My VB code is like this:

<DllImport("External.DLL")> _
Public Shared Function thisFunction( ByVal a As Double, ByVal b As
Integer, ByRef c As Double() ) As Integer
End Function
..
..
..
Dim iRet As Integer
Dim a As Double
Dim b As Integer
Dim c(5) As Double

a = 36.12
b = 4

iRet = thisFunction( a, b, c )
...
...

At the moment, the call to this function is crashing. What is the best
solution for this type of problem on the full Framework?

Regards,
Neville Lang
 
M

Mattias Sjögren

Neville,
<DllImport("External.DLL")> _
Public Shared Function thisFunction( ByVal a As Double, ByVal b As Integer,
ByRef c As Double() ) As Integer
^^^^^

Should be ByVal


Mattias
 
F

FishingScout

Neville,

You state that 6 doubles are returned but you are only allocating an
array of 5 to receive those 6 values.

Dim c(6) As Double might do the trick...


Neville said:
int thisFunction( [in] double a, [in] int b, [out] double* c)

The double* c argument passes back an array of 6 doubles.
 
N

Neville Lang

Hi Mattias,

I tried your suggestion but it still gives an error.

I am going to revert to my shim code approach as I did in the Compact
Framework, and will report back if I get it working. I had hoped the full
Framework would not have required separate shim code in another DLL to make
receiving 6 doubles work. ( [out] double * construct in the C++ DLL)

Regards,
Neville Lang
 
N

Neville Lang

I tried your suggestion but this did not change anything.

I mainly have a C# background and I understand that in VB .NET, you specify
a value of one less when dimensioning an array as you do in C#. As I
understand it, the figure that is used for the dimension of an array in
VB.NET is the number of the last element - so in my case to get 6 elements
in an array, elements 0 - 5, I dimension an array using "array(5)" in
VB.NET.

As I stated in my reply to Mattias, I will try out my shim code and approach
report back.

Regards,
Neville Lang




FishingScout said:
Neville,

You state that 6 doubles are returned but you are only allocating an
array of 5 to receive those 6 values.

Dim c(6) As Double might do the trick...


Neville said:
int thisFunction( [in] double a, [in] int b, [out] double* c)

The double* c argument passes back an array of 6 doubles.
Dim c(5) As Double

a = 36.12
b = 4

iRet = thisFunction( a, b, c )
 
J

Jay B. Harlow

Neville,
In addition to the other comments, I understand that you need to pass the
array ByVal (as Mattias suggests) plus you need to use the MarshalAs
attribute to indicate an array pointer & the size of the array.

Something like:

Public Declare Function thisFunction Lib "External.DLL" ( _
ByVal a As Double, _
ByVal b As Integer, _
<Out(), MarshalAs(UnmanagedType.LPArray, SizeConst:=6)> _
ByVal c As Double() _
) As Integer


For details see:

http://msdn2.microsoft.com/en-us/library/z6cfh6e6.aspx
 
N

Neville Lang

Jay,

Your feedback on this topic has fixed my problem.

Thank you also for the link to the MSDN information - it was very useful to
understand what is going on here. I must admit that one of my weaknesses in
..NET programming is in using Platform Invoke and the correct construction of
the arguments.

I slightly departed from your code after reading MSDN - I did not use the
Out() attribute - only the MarshalAs() was all that was needed. I also found
that if I only typed in the <MarshalAs(...)> attribute followed by the
argument name, VB.NET automatically put in the "ByVal".

I can now move on...

Regards,
Neville Lang



Jay B. Harlow said:
Neville,
In addition to the other comments, I understand that you need to pass the
array ByVal (as Mattias suggests) plus you need to use the MarshalAs
attribute to indicate an array pointer & the size of the array.

Something like:

Public Declare Function thisFunction Lib "External.DLL" ( _
ByVal a As Double, _
ByVal b As Integer, _
<Out(), MarshalAs(UnmanagedType.LPArray, SizeConst:=6)> _
ByVal c As Double() _
) As Integer


For details see:

http://msdn2.microsoft.com/en-us/library/z6cfh6e6.aspx


--
Hope this helps
Jay B. Harlow
.NET Application Architect, Enthusiast, & Evangelist
T.S. Bradley - http://www.tsbradley.net


Neville Lang said:
Hi all,

Here is a problem I first struck a while back in the Compact Framework. I
am now using the full Framework (v2.0) and wanted to know whether there
is anyway around this issue without building separate shim code in
another DLL.

Here is the layout of the external C DLL function:

int thisFunction( [in] double a, [in] int b, [out] double* c)

The double* c argument passes back an array of 6 doubles.

My VB code is like this:

<DllImport("External.DLL")> _
Public Shared Function thisFunction( ByVal a As Double, ByVal b As
Integer, ByRef c As Double() ) As Integer
End Function
..
..
..
Dim iRet As Integer
Dim a As Double
Dim b As Integer
Dim c(5) As Double

a = 36.12
b = 4

iRet = thisFunction( a, b, c )
...
...

At the moment, the call to this function is crashing. What is the best
solution for this type of problem on the full Framework?

Regards,
Neville Lang
 
J

Jay B. Harlow

Neville,
I must admit that one of my weaknesses in .NET programming is in using
Platform Invoke and the correct construction of the arguments.
I find www.pinvoke.net to be invaluable when working with P/Invoke. I also
recommend Adam Nathan's book ".NET and COM - The Complete Interoperability
Guide" from SAMS press if you are doing a lot of P/Invoke.

--
Hope this helps
Jay B. Harlow
..NET Application Architect, Enthusiast, & Evangelist
T.S. Bradley - http://www.tsbradley.net


Neville Lang said:
Jay,

Your feedback on this topic has fixed my problem.

Thank you also for the link to the MSDN information - it was very useful
to understand what is going on here. I must admit that one of my
weaknesses in .NET programming is in using Platform Invoke and the correct
construction of the arguments.

I slightly departed from your code after reading MSDN - I did not use the
Out() attribute - only the MarshalAs() was all that was needed. I also
found that if I only typed in the <MarshalAs(...)> attribute followed by
the argument name, VB.NET automatically put in the "ByVal".

I can now move on...

Regards,
Neville Lang



Jay B. Harlow said:
Neville,
In addition to the other comments, I understand that you need to pass the
array ByVal (as Mattias suggests) plus you need to use the MarshalAs
attribute to indicate an array pointer & the size of the array.

Something like:

Public Declare Function thisFunction Lib "External.DLL" ( _
ByVal a As Double, _
ByVal b As Integer, _
<Out(), MarshalAs(UnmanagedType.LPArray, SizeConst:=6)> _
ByVal c As Double() _
) As Integer


For details see:

http://msdn2.microsoft.com/en-us/library/z6cfh6e6.aspx


--
Hope this helps
Jay B. Harlow
.NET Application Architect, Enthusiast, & Evangelist
T.S. Bradley - http://www.tsbradley.net


Neville Lang said:
Hi all,

Here is a problem I first struck a while back in the Compact Framework.
I am now using the full Framework (v2.0) and wanted to know whether
there is anyway around this issue without building separate shim code in
another DLL.

Here is the layout of the external C DLL function:

int thisFunction( [in] double a, [in] int b, [out] double* c)

The double* c argument passes back an array of 6 doubles.

My VB code is like this:

<DllImport("External.DLL")> _
Public Shared Function thisFunction( ByVal a As Double, ByVal b As
Integer, ByRef c As Double() ) As Integer
End Function
..
..
..
Dim iRet As Integer
Dim a As Double
Dim b As Integer
Dim c(5) As Double

a = 36.12
b = 4

iRet = thisFunction( a, b, c )
...
...

At the moment, the call to this function is crashing. What is the best
solution for this type of problem on the full Framework?

Regards,
Neville Lang
 
N

Neville Lang

Jay,

Thank you for the PInvoke.net link and the reference to the book. I have a
number of .NET books but not that one.

I have been working with C# on the Compact Framework for the last few years
so using VB.NET on the full Framework has taken me a bit more time to used
to the VB.NET style. I gave up on VB when it was about version 4 so this
project has given me the opportunity to get back up to speed with the VB
..NET version.

I only occasionally need to do some P/Invoke things and when I do, it is an
area I seem to get caught on. I am quite comfortable in the Compact
Framework (CF) for Pocket PCs and the need to write shim code in a separate
DLL for some calls to make some things work, due to the limited number of
things the Marshal class can do in CF.

Until recently, I have not done much on the full Framework and when this
P/Invoke came up, I just knew that there should have been an easier way to
solve my problem with the larger number of features in marshaling in the
full Framework.

Thanks again.

Regards,
Neville Lang




Jay B. Harlow said:
Neville,
I must admit that one of my weaknesses in .NET programming is in using
Platform Invoke and the correct construction of the arguments.
I find www.pinvoke.net to be invaluable when working with P/Invoke. I also
recommend Adam Nathan's book ".NET and COM - The Complete Interoperability
Guide" from SAMS press if you are doing a lot of P/Invoke.

--
Hope this helps
Jay B. Harlow
.NET Application Architect, Enthusiast, & Evangelist
T.S. Bradley - http://www.tsbradley.net


Neville Lang said:
Jay,

Your feedback on this topic has fixed my problem.

Thank you also for the link to the MSDN information - it was very useful
to understand what is going on here. I must admit that one of my
weaknesses in .NET programming is in using Platform Invoke and the
correct construction of the arguments.

I slightly departed from your code after reading MSDN - I did not use the
Out() attribute - only the MarshalAs() was all that was needed. I also
found that if I only typed in the <MarshalAs(...)> attribute followed by
the argument name, VB.NET automatically put in the "ByVal".

I can now move on...

Regards,
Neville Lang



Jay B. Harlow said:
Neville,
In addition to the other comments, I understand that you need to pass
the array ByVal (as Mattias suggests) plus you need to use the MarshalAs
attribute to indicate an array pointer & the size of the array.

Something like:

Public Declare Function thisFunction Lib "External.DLL" ( _
ByVal a As Double, _
ByVal b As Integer, _
<Out(), MarshalAs(UnmanagedType.LPArray, SizeConst:=6)> _
ByVal c As Double() _
) As Integer


For details see:

http://msdn2.microsoft.com/en-us/library/z6cfh6e6.aspx


--
Hope this helps
Jay B. Harlow
.NET Application Architect, Enthusiast, & Evangelist
T.S. Bradley - http://www.tsbradley.net


Hi all,

Here is a problem I first struck a while back in the Compact Framework.
I am now using the full Framework (v2.0) and wanted to know whether
there is anyway around this issue without building separate shim code
in another DLL.

Here is the layout of the external C DLL function:

int thisFunction( [in] double a, [in] int b, [out] double* c)

The double* c argument passes back an array of 6 doubles.

My VB code is like this:

<DllImport("External.DLL")> _
Public Shared Function thisFunction( ByVal a As Double, ByVal b As
Integer, ByRef c As Double() ) As Integer
End Function
..
..
..
Dim iRet As Integer
Dim a As Double
Dim b As Integer
Dim c(5) As Double

a = 36.12
b = 4

iRet = thisFunction( a, b, c )
...
...

At the moment, the call to this function is crashing. What is the best
solution for this type of problem on the full Framework?

Regards,
Neville Lang
 

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