Jump to content
Xtreme .Net Talk

Recommended Posts

Posted

Hi folks,

 

I try to use a DLL file (ReadIMX.DLL) generated with C++ in my VB application. I have the DLL sourcecode and I guess I know how to call the DLL from VB. Still I have some trouble with generating structures like in the C++ code I need calling the DLL.

The DLL basically has the decryption routine to read special image files (*.IMG, *.IMX, ...) associated with a laboratory camera. Looking at the C++ code the DLL is called as follows:

extern "C" int EXPORT ReadIMX ( const char* theFileName, BufferType* myBuffer, AttributeList** myList )

Giving the filename to the DLL it decrypts the image file and stores data into myBuffer. The myList list includes image attributes. Setting myList = NULL, the DLL does not read those attributes. As I am not interested in the attributes I will use the NULL argument here. The DLL returns an integer representing an error code. The BufferType structure is defined like this:

typedef struct
{
float	factor;
float offset;
char	description[16];
char	unit[16];
} BufferScaleType;

typedef struct
{
  int         isFloat;
  int         nx,ny,nz,nf;
  int         totalLines;
int			vectorGrid;			// 0 for images
int			image_sub_type;	// BufferFormat_t
  union 
{
     float*   floatArray;
     Word*    wordArray;
  };
BufferScaleType	scaleX;		// x-scale
BufferScaleType	scaleY;		// y-scale
BufferScaleType	scaleI;		// intensity scale
} BufferType;

I tried to define the structures in my VB script as follows:

Imports System.Runtime.InteropServices

<StructLayout(LayoutKind.Sequential)> _
   Public Structure BufferScaleType
       Public factor As Single
       Public offset As Single
       <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=16)> _
       Public description As String
       <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=16)> _
       Public unit As String
   End Structure

   <StructLayout(LayoutKind.Explicit)> _
   Public Structure Union
       <FieldOffset(0)> _
       Public float As Single()
       <FieldOffset(0)> _
       Public Word As String()
   End Structure

   <StructLayout(LayoutKind.Sequential)> _
   Public Structure BufferType
       Public isFloat As Integer
       Public nx, ny, nz, nf As Integer
       Public totalLines As Integer
       Public vectorGrid As Integer
       Public image_sub_type As Integer
       Public Unionx As Union
       Public scalex As BufferScaleType
       Public scaley As BufferScaleType
       Public scalei As BufferScaleType
   End Structure

Calling the DLL as follows I get an error message pasted below:

Public Declare Function ReadIMX Lib "ReadIMX.dll" (ByVal filename As String, ByRef btype As BufferType, ByRef attributelist As Object) As Integer

   Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
       Dim filename As String = "D:\Daten\Messungen\Test\429mbarAr_7_5kHz_740Vpp_696_64nm\B0001.IMG"
       Dim buftype As New BufferType
       Dim A As Integer = ReadIMX(filename, buftype, System.DBNull.Value)
   End Sub

The error message says (in my VB version the message is German, so please excuse if my translation is not conform with VB error expressions):

InvalidVariant was detected.

Converting a none managed VARIANT to a managed object an invalid INVARIANT was found. If an invalid INVARIANT is passed to the CLR, unexpected exceptions, data harm or loss can occur.

Do you have an idea where the problem is hiding? I attached the DLL and a sample IMG-file to this post.

ReadIMX.zip

  • Leaders
Posted

Is the error due to converting a managed object to a COM variant, or vice-versa?

 

DBNull.Value is not a null value, it is an object that represents a null database value. Visual Basic represents null with the keyword "Nothing", so try this:

Public Declare Function ReadIMX Lib "ReadIMX.dll" (ByVal filename As String, ByRef btype As BufferType, ByRef attributelist As Object) As Integer

   Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
       Dim filename As String = "D:\Daten\Messungen\Test\429mbarAr_7_5kHz_740Vpp_696_64nm\B0001.IMG"
       Dim buftype As New BufferType
       Dim A As Integer = ReadIMX(filename, buftype, [color="Blue"]Nothing[/color])
   End Sub

 

That might help. It's hard to say. Things get tricky with P/Invoke when you throw in pointers and pointers to pointers and unions.

[sIGPIC]e[/sIGPIC]
Posted

Hi marble_eater,

 

thank you for your help. Using the "Nothing" argument did not solve the problem. The error occurs converting an unmanaged variant to a managed object. I guess you are right and the conversion of the C++ structures to VB structures is the main error source.

I will try to find out more on basis of the DLL source code. Changing the arguments in the ReadIMX routine I could check if the communication between the DLL and my VB script works without errors. Then the structure definitions will most probably be the error source. Please excuse if I use unusual terms to describe routines etc. as I am not too experienced with VB and unfamiliar with C++ and C#.

  • Leaders
Posted

Looking over your structure definition again, I see two problems. First of all, you are replacing a pointer to a Word (Word is a numeric type) with a string, and you are replacing a pointer to a float with a float (Single). Secondly, seeing as the C++ union actually contains two pointers of different types, I don't think you actually need a union. VB only supports one kind of pointer, the IntPtr. I don't know whether you need to access the data that this pointer points to.

 

Again, I don't know if it will help, but you can try modifying your code as follows:

Imports System.Runtime.InteropServices

<StructLayout(LayoutKind.Sequential)> _
   Public Structure BufferScaleType
       Public factor As Single
       Public offset As Single
       <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=16)> _
       Public description As String
       <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=16)> _
       Public unit As String
   End Structure

   <StructLayout(LayoutKind.Sequential)> _
   Public Structure BufferType
       Public isFloat As Integer
       Public nx, ny, nz, nf As Integer
       Public totalLines As Integer
       Public vectorGrid As Integer
       Public image_sub_type As Integer
       [b][i][color="Blue"]Public floatOrShortPointer As IntPtr[/color][/i][/b] [color="SeaGreen"]// This might point to an array[/color]
       Public scalex As BufferScaleType
       Public scaley As BufferScaleType
       Public scalei As BufferScaleType
   End Structure

[sIGPIC]e[/sIGPIC]
Posted

if the above don't work you might want to check out

http://www.vbthunder.com/articles/readcpp.php

 

also, the error is an mda error. You can turn off the error by Debug->Exceptions->Managed Debugging Assistants->Invalid Variant

 

Last I read something about structures being something totally different in c++ and vb.net, although I'm not that good with vb.net and hardly use structures in VB.NET I can't provide you with more information about that. Also I can't find that article right now :(

 

Hope this points you in the right direction

 

Good luck

~ DP

My Development System

Intel Core i7 920 @2.66Ghz

6 GB DDR3 SDRAM

Windows 7 Ultimate x64 & Windows Vista Home Premium x64 dual boot

GeForce GTX295 1.8 GB

3.5 TB HD

Posted
Ok, marble_eaters last suggestion solved the problem. I can now access the DLL without error messages and get return values that make sense. Replacing the "union" with a single pointer is a brilliant idea. Thank you both for your help. Now I have to dig myself through the DLL to read the images, which should be ok, now as I can access the DLL properly. Thank you once more.
Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...