Passing a structure to a C dll in VB .NET

G

Guest

I have read several interesting posts on passing structures to C dlls, but none seem to cover the following case. The structure (as seen in C) is as follows:

typedef struct tag_scanparm
{
short cmd;
short fdc;
WORD dsf;
short boxcar;
short average;
short chan_ena[\4];
short scan_dark;
short correct_dark;
short extrig;
short upper4chan;
float sdat[\4][\2048]
} SCANPARM;

The real problem seems to be with the arrays. Even using attributes and specifying a size when I decalre the structure in VB, I can't get this to work. It has to be passed by reference, and when I call "GetType" as a part of my call to Marshall.StructureToPtr, I get an error message to the effect that my structure cannot be marshalled as an unmanaged type.

Please forgive the fact that I don't have the exact error message handy...I tried getting this to work for about a day, scanning all types of message boards, and finally threw in the towel and created a COM object in C++ that wrapped the calls to this 3rd Party dll. That's OK for me, but for some of our customers who use VB exclusively it would be nice to know how to do this directly from VB...there has to be a way, and I think I was close!

Any help would be greatly appreciated!


Thanks,


Steve
 
R

Rob Teixeira [MVP]

You might want to post your VB version of the structure definition. This
should work fine. When defining the structure in VB, make sure to use the
MarshalAs attribute, and specify the unamangedtype as ByValArray (for the
arrays), including the SizeConst and the ArraySubType properties of the
attribute.

Also, you don't need to use Marshal.StructureToPtr. When defining the C DLL
function export in VB, just set the structure parameter to ByRef instead of
ByVal, and you can pass a structure variable of this type directly to the
function.

-Rob Teixeira [MVP]

Steve Turner said:
I have read several interesting posts on passing structures to C dlls, but
none seem to cover the following case. The structure (as seen in C) is as
follows:
typedef struct tag_scanparm
{
short cmd;
short fdc;
WORD dsf;
short boxcar;
short average;
short chan_ena[\4];
short scan_dark;
short correct_dark;
short extrig;
short upper4chan;
float sdat[\4][\2048]
} SCANPARM;

The real problem seems to be with the arrays. Even using attributes and
specifying a size when I decalre the structure in VB, I can't get this to
work. It has to be passed by reference, and when I call "GetType" as a part
of my call to Marshall.StructureToPtr, I get an error message to the effect
that my structure cannot be marshalled as an unmanaged type.
Please forgive the fact that I don't have the exact error message
handy...I tried getting this to work for about a day, scanning all types of
message boards, and finally threw in the towel and created a COM object in
C++ that wrapped the calls to this 3rd Party dll. That's OK for me, but for
some of our customers who use VB exclusively it would be nice to know how to
do this directly from VB...there has to be a way, and I think I was close!
 
G

Guest

I have decalred the following structure

<StructLayout(LayoutKind.Sequential, Pack:=1)>
Public Structure Scanpara
Public cmd As Shor
Public fdc As Shor
Public dsf As Int3
Public boxcar As Shor
Public average As Shor
Public chan_ena() As Shor
Public scan_dark As Shor
Public correct_dark As Shor
Public extrig As Shor
Public upper4chan As Shor
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=8192)>
Public sdat() As Singl

Public Sub Initialize(
ReDim chan_ena(3
ReDim sdat(8191
End Su
End Structur
[/code

And the following function declaration

Declare Function OOI_DoScan Lib "OOIDrv32.dll" (ByRef pVal As Scanparam) As Shor

The original function (from C++ Header) looks like this

short EXPORTED OOI_DoScan(SCANPARM FAR *); // perform 1 acquisitio

The function executes just fine, however if you look at my origianl declaration of the C structure, you'll see that what I really want is a 2-D array (4X2048). If I assume that my first row of data is in positions 0-2047 of the returned (sdat) array, it looks like I'm missing one point off of the front and back of that array (2047 has no data, and position 1 does not either..I expect position 0 to have no data...strange behavior of the third party dll). If I write a C++ COM object to do the same call, and use it in the VB .NET program, I do not see this behavior. I am assuming that this is because I am passing in a 1-D array and making possibly erroneous assumptions about the order in which they will be written to

Decalre a 2-D array you say? HA HA HA! If I decalre the stucture in the following way

<StructLayout(LayoutKind.Sequential, Pack:=1)>
Public Structure Scanpara
Public cmd As Shor
Public fdc As Shor
Public dsf As Int3
Public boxcar As Shor
Public average As Shor
Public chan_ena() As Shor
Public scan_dark As Shor
Public correct_dark As Shor
Public extrig As Shor
Public upper4chan As Shor
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=8192)>
Public sdat(,) As Singl

Public Sub Initialize(
ReDim chan_ena(3
ReDim sdat(3, 2047
End Su
End Structur

then when I call my scan function, I get the error

System.TypeLoadException: Con not marshal field sdat of the type OOResourceServer.Scanparam: This type can not be marshaled as a structure field

To say the least, I am frustrated. Is my line of work, lab automation, I often have to interact with third party dlls that have complicated structures that need to be passed in by reference, to do things like high data rate scans. Althought there is the workaround of using C++ to develop a COM wrapper, I need to be able to tell VB .NET programmers how to do this...and they may not be C++ programmers themselves. This seems silly...why can't VB .NET understand that I am passing a 2_D array of float values...is that too much to ask?? There is absolutely not material that I have found that addresses this problem...all examples use 1-D arrays

I will stop now, lest I begin ranting (If I haven't already)

Thanks

Stev

----- Rob Teixeira [MVP] wrote: ----

You might want to post your VB version of the structure definition. Thi
should work fine. When defining the structure in VB, make sure to use th
MarshalAs attribute, and specify the unamangedtype as ByValArray (for th
arrays), including the SizeConst and the ArraySubType properties of th
attribute

Also, you don't need to use Marshal.StructureToPtr. When defining the C DL
function export in VB, just set the structure parameter to ByRef instead o
ByVal, and you can pass a structure variable of this type directly to th
function

-Rob Teixeira [MVP

Steve Turner said:
I have read several interesting posts on passing structures to C dlls, bu
none seem to cover the following case. The structure (as seen in C) is a
follows:
typedef struct tag_scanparm
{
short cmd;
short fdc;
WORD dsf;
short boxcar;
short average;
short chan_ena[\4];
short scan_dark;
short correct_dark;
short extrig;
short upper4chan;
float sdat[\4][\2048]
} SCANPARM;
The real problem seems to be with the arrays. Even using attributes and
specifying a size when I decalre the structure in VB, I can't get this to
work. It has to be passed by reference, and when I call "GetType" as a part
of my call to Marshall.StructureToPtr, I get an error message to the effect
that my structure cannot be marshalled as an unmanaged type.handy...I tried getting this to work for about a day, scanning all types of
message boards, and finally threw in the towel and created a COM object in
C++ that wrapped the calls to this 3rd Party dll. That's OK for me, but for
some of our customers who use VB exclusively it would be nice to know how to
do this directly from VB...there has to be a way, and I think I was close!
 

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