I'm a little new to vb.NET and I'm struggling with calls to an unmanaged DLL
(written in C). I've done a lot with this in VB6 so I know pretty much what
is going on.... until .NET interop got in the way.
PLEASE somebody help me. I've been knocking my head against a brick wall
for 2 days, tried every combination I can think of. I'm getting desperate.
It looks like I should be able to do this... just don't... see.... it.
One API call is giving me serious trouble and is a good example of a complex
struct being passed to the DLL API function. In C it is defined as:
BYTE __declspec(dllexport) dscInitBoard(BYTE boardtype, DSCCB* dsccb,
WORD* board);
... which I have converted into
<DllImport("dscud55.dll")> _
Function dscInitBoard( _
ByVal boardtype As Byte, ByRef pdsccb As DSCCB, ByRef pboard As
Short) As Byte
End Function
When called using the vb.NET DllImport'd function I get an error code in the
return value (when it should not) indicating an invalid parameter value in
the structure argument.
Below is a simplified definition of the C struct (taken from a hardware I/O
vendor's .h file) DSCCB:
typedef struct
{
BYTE boardtype; /* Contains the boardtype constant */
WORD boardnum; /* The handle to the board */
BYTE dma_level; /* DMA level of the board */
LONG clock_freq; /* Clock frequency in hertz */
BYTE int_level; /* Interrupt level of the board */
BOOL RMM_external_trigger; /* Enable/disable external trigger */
BYTE SMM_AD_resolution; /* 12 or 14 bit */
WORD EMM_IOAddr[8]; /* IO addresses for up to eight ports */
WORD EMM_Interrupt[8]; /* Interrupts for up to eight ports */
BYTE clkfrq0; /* 0 = 10Mhz, 1 = 1MHz */
char DALI_host[128];
WORD DALI_port;
char DALI_username[24];
} DSCCB;
I converted this into a vb.NET structure as follows:
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
Structure DSCCB
<MarshalAs(UnmanagedType.U1)> Dim boardtype As Byte '/* Contains
the boardtype constant */
<MarshalAs(UnmanagedType.I2)> Dim boardnum As Short '/* The
handle to the board */
<MarshalAs(UnmanagedType.I1)> Dim dma_level As Byte '/* DMA
level of the board */
<MarshalAs(UnmanagedType.U4)> Dim clock_freq As Int32 '/* Clock
frequency in hertz */
<MarshalAs(UnmanagedType.U1)> Dim int_level As Byte '/*
Interrupt level of the board */
<MarshalAs(UnmanagedType.I2)> Dim RMM_external_trigger As Int16 '/*
Enable/disable external trigger */
<MarshalAs(UnmanagedType.U1)> Dim SMM_AD_resolution As Byte '/* 12
or 14 bit */
<MarshalAs(UnmanagedType.ByValArray), VBFixedArray(8)> _
Dim EMM_IOAddr() As Int16 '/* IO addresses for up to
eight ports */
<MarshalAs(UnmanagedType.ByValArray), VBFixedArray(8)> _
Dim EMM_Interrupt() As Int16 '/* Interrupts for up to
eight ports */
<MarshalAs(UnmanagedType.U1)> Dim clkfrq0 As Byte '/* 0 = 10Mhz, 1
= 1MHz */
<MarshalAs(UnmanagedType.ByValArray), VBFixedArray(128)> _
Dim DALI_host() As Char
<MarshalAs(UnmanagedType.U1)> Dim DALI_port As Int16
<MarshalAs(UnmanagedType.ByValArray), VBFixedArray(24)> _
Dim DALI_username() As Char
End Structure
I put in all the MarshalAs attributes because by now, as I said, I'm getting
desperate. I'm not very sure about the VBFixedArray attribute use for fixed
size arrays. Some posts in this newsgroup suggest putting an extra argument
in the MarshalAs attribute....
MarshalAs( UnmanagedType.AnsiBStr, SizeConst=5 )
But, for me, vb.NET baulked at the SizeConst argument so I trued the
VBFixedArray attribute.
Any help, suggestions, pointers or correct answers will be very very very
welcome.
TIA,
Simon Greener
simon DOT greener AT altecdata DOT com
smam...@re.scum <<< Don't use this to reply with email.... its a honeypot
for spammers....
> <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
You might want to verify how the struct should be packed in memory. If
it uses byte packing, you should add Pack:=1 to the StructLayout
attribute.
> <MarshalAs(UnmanagedType.I2)> Dim RMM_external_trigger As Int16 '/*
>Enable/disable external trigger */
If the BOOL in the original struct definition is a 32bit Win32 BOOL,
this member should be an Int32 or Boolean.
>I put in all the MarshalAs attributes because by now, as I said, I'm getting
>desperate.
OK, but you don't need the MarshalAs attribute on primitive numeric
types. I know some people prefer to be explicit, but it doesn't change
anything for such types, and personally I just think it makes the code
harder to read.
>I'm not very sure about the VBFixedArray attribute use for fixed
>size arrays.
The VBFixedArray attribute is just used by the VB runtime library
functions, for example when you write a structure to a file using
FilePutObject(). It doesn't affect the CLR's marshaling layer.
> MarshalAs( UnmanagedType.AnsiBStr, SizeConst=5 )
>
>But, for me, vb.NET baulked at the SizeConst argument so I trued the
>VBFixedArray attribute.
This is the way to do it. So how, exactly, did it "baulk"? Could it be
because you didn't use named parameter syntax (:=) to set the
SizeConst?
Oh, and you probably want ByValArray instead of AnsiBStr.
Mattias
===
Mattias Sjögren [MVP] mattias @ mvps.org
http://www.msjogren.net/dotnet/
Please reply only to the newsgroup.
Long time no see!!! Nice to see a familiar face. Hope you have been well
since we last spoke (remember the Task Scheduler IDL?).
BOOL is defined as follows:
#ifndef BOOL
#define BOOL int
#endif
... so I think I was correct in converting it to an
<MarshalAs(UnmanagedType.I2)> Int16. Or am I losing it ?
Best regards,
Simon
"Mattias Sjögren" <mattias.don...@mvps.org> wrote in message
news:#bJBufLjCHA.2816@tkmsftngp11...
I don't know how I missed this but there was:
/* MS Visual C++ only - end 1-byte structure alignment */
#ifdef _MSC_VER
#pragma pack(pop, dscud_packing)
#endif
... tucked away in one of the headers supplied by the unmanaged DLL vendor.
So when I included:
<StructLayout(LayoutKind.Sequential, Pack:=1, CharSet:=CharSet.Ansi)>
... everything worked just fine after that (Pack:=1 being the important
bit).
WHO in the their right minds uses single byte packed structures ??? Diamond
Systems Inc do as it turns out. I'm glad I'm doing this with vb.NET as if I
was still using VB6 I would be screwed.
Thanks for the assistance, regards,
Simon Greener
simon DOT greener AT altecdata DOT com
s...@mmers.are.scum
>Long time no see!!! Nice to see a familiar face. Hope you have been well
>since we last spoke (remember the Task Scheduler IDL?).
Of course, how could I forget! :-)
>BOOL is defined as follows:
>
>#ifndef BOOL
>#define BOOL int
>#endif
>
>... so I think I was correct in converting it to an
><MarshalAs(UnmanagedType.I2)> Int16. Or am I losing it ?
int in C++ (well, MS VC++ anyway) is 32 bits, thus Int32 in managed
code.
That is a surprise to me. How long have I been doing this ? [sigh].
Nobody memo'd me when integers when 32 bit (wasn't that back in the 386
days?)
Simon
PS. I've posted another message in here about another little 'issue' that I
best you're substantial talents would have much to contribute. Didn't have
the bottle/cheek to mail you direct. <G> This is jus' like the old days eh?