Array Pointers in C#, calling C++ DLL

G

Guest

I got a DLL that reads some RAW Double Data from a File to an Array
The DLL works fine

This is the Header of the double_read function

int dll_dbl_read (const char * fnam,
/* File name to read from *
int * res,
/* returns int[4]*
float * len,
/* returns float[4]*
double ** data)
/* returns double[unknown size]*

This is how I call the function from C++

char * myfname
int res[4]
float len[4]
double * data
int m_type

int DataStack::dbl_read(const char * fname

m_type = dll_dbl_read(fname,res,len,&data)
myfname = new char[strlen(fname)+1]
strcpy(myfname, fname)

return m_type


This works fine and I would like to know how to call this function from C#????

This is what I try in C# and what doesn´t work

using System
using System.Runtime.InteropServices

namespace min

/// <summary
/// Summary description for FileIO
/// </summary


public unsafe class FileI

public int m_type
public char* myfname
public int * res
public float * len
public double ** data

[DllImport("MYLIB.DLL", EntryPoint="dll_dbl_read", SetLastError=true, CharSet=CharSet.Unicode, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)]
public static unsafe extern int dll_dbl_read(char[] fnam, int* res, float* len, double** data)

public int dbl_read(string fname

int result
int[] resolution = {0,0,0,0}
float[] length = {0,0,0,0}
double[] mydata = {0}
myfname = &fname.ToCharArray()
fixed (int* res = resolution

fixed (float* len = length

fixed (double* data = mydata

result = dll_dbl_read(myfname,res,len,&data)
/*Just for Testing*
int x = res[0]
float xl = len[0]
double test = data[100];
test = data[23]
/*Everything is empty here :blush:(*




return result


public FileIO(




Can Anybody tell me how to Create my Variables to pass to the functio
dll_dbl_read? So that I find my data in there and not only 0 or NULL

Thanks in Advanc

Martin
 
B

BMermuys

Hi,
[inline]

Chucker said:
I got a DLL that reads some RAW Double Data from a File to an Array.
The DLL works fine.

This is the Header of the double_read function:

int dll_dbl_read (const char * fnam,
/* File name to read from */
int * res,
/* returns int[4]*/
float * len,
/* returns float[4]*/
double ** data);
/* returns double[unknown size]*/

This is how I call the function from C++:

Two problems:
1) At least you must know the size of the array when the function returns,
unless it's 0 terminated maybe. How else could you safely use it, even in
c/c++ ?

2) To have a clean/safe solution, the DLL should also export a function
which de-allocates the memory it has allocated to 'data' when the function
(dll_dbl_read) was called. Something like "void dll_free_data( double*
data );".

HTH,
greetings
char * myfname;
int res[4];
float len[4];
double * data;
int m_type;

int DataStack::dbl_read(const char * fname)
{
m_type = dll_dbl_read(fname,res,len,&data);
myfname = new char[strlen(fname)+1];
strcpy(myfname, fname);

return m_type;
}

This works fine and I would like to know how to call this function from C#?????

This is what I try in C# and what doesn´t work:

using System;
using System.Runtime.InteropServices;

namespace mine
{
/// <summary>
/// Summary description for FileIO.
/// </summary>


public unsafe class FileIO
{
public int m_type;
public char* myfname;
public int * res;
public float * len;
public double ** data;

[DllImport("MYLIB.DLL", EntryPoint="dll_dbl_read",
SetLastError=true, CharSet=CharSet.Unicode, ExactSpelling=true,
CallingConvention=CallingConvention.StdCall)]
public static unsafe extern int dll_dbl_read(char[] fnam, int* res, float* len, double** data);

public int dbl_read(string fname)
{
int result;
int[] resolution = {0,0,0,0};
float[] length = {0,0,0,0};
double[] mydata = {0};
myfname = &fname.ToCharArray();
fixed (int* res = resolution)
{
fixed (float* len = length)
{
fixed (double* data = mydata)
{
result = dll_dbl_read(myfname,res,len,&data);
/*Just for Testing*/
int x = res[0];
float xl = len[0];
double test = data[100];
test = data[23];
/*Everything is empty here :blush:(*/
}
}
}

return result;
}

public FileIO()
{
}
}

Can Anybody tell me how to Create my Variables to pass to the function
dll_dbl_read? So that I find my data in there and not only 0 or NULL?

Thanks in Advance

Martin
 
G

Guest

Hi BMermuys

thanks for your effort
The Array in **data represents 4-D Data in a 1-D Arra
by the value in m_type I can see if it´s Double or Float Dat
in the Array. In res[4] I get the Dimensions of the Arra
this means xres, yres, zres and tres. So I can calculat
the boundaries of the array.

Its xres*yres*zres*tres*(sizeoffloat or sizeofdouble

When using the dll from c++ I delete the pointer to th
array in my calling function after use. But you ar
right, I don´t know how to do this in C# either

Will be a problem anyway since the dll runs wit
vc6 runtime and uses a different heap

But I can fix the deallocation problem in the dll
But I still can´t call it

So if I know the size of the Array (after the call
of the dll function, how to create my variables

Thanks in advanc

Marti



----- BMermuys wrote: ----

Hi
[inline

Chucker said:
I got a DLL that reads some RAW Double Data from a File to an Array
The DLL works fine
This is the Header of the double_read function
int dll_dbl_read (const char * fnam
/* File name to read from *
int * res
/* returns int[4]*
float * len
/* returns float[4]*
double ** data)
/* returns double[unknown size]*
This is how I call the function from C++

Two problems
1) At least you must know the size of the array when the function returns
unless it's 0 terminated maybe. How else could you safely use it, even i
c/c++

2) To have a clean/safe solution, the DLL should also export a functio
which de-allocates the memory it has allocated to 'data' when the functio
(dll_dbl_read) was called. Something like "void dll_free_data( double
data );"

HTH
greeting
char * myfname
int res[4]
float len[4]
double * data
int m_type
int DataStack::dbl_read(const char * fname

m_type = dll_dbl_read(fname,res,len,&data)
myfname = new char[strlen(fname)+1]
strcpy(myfname, fname)
return m_type
This works fine and I would like to know how to call this function fro C#????
This is what I try in C# and what doesn´t work
using System
using System.Runtime.InteropServices
namespace min

/// <summary>> /// Summary description for FileIO
/// </summary>>>> public unsafe class FileI

public int m_type
public char* myfname
public int * res
public float * len
public double ** data
[DllImport("MYLIB.DLL", EntryPoint="dll_dbl_read"
SetLastError=true, CharSet=CharSet.Unicode, ExactSpelling=true
CallingConvention=CallingConvention.StdCall)
public static unsafe extern int dll_dbl_read(char[] fnam, int* res float* len, double** data)
public int dbl_read(string fname

int result
int[] resolution = {0,0,0,0}
float[] length = {0,0,0,0}
double[] mydata = {0}
myfname = &fname.ToCharArray()
fixed (int* res = resolution

fixed (float* len = length

fixed (double* data = mydata

result = dll_dbl_read(myfname,res,len,&data)
/*Just for Testing*
int x = res[0]
float xl = len[0]
double test = data[100]
test = data[23]
/*Everything is empty here :blush:(*


return result
public FileIO(

}
Can Anybody tell me how to Create my Variables to pass to the function
dll_dbl_read? So that I find my data in there and not only 0 or NULL?
Thanks in Advance
Martin
 
B

BMermuys

Hi,
[inline]
Chucker said:
Hi BMermuys,

thanks for your effort.
The Array in **data represents 4-D Data in a 1-D Array
by the value in m_type I can see if it´s Double or Float Data
in the Array. In res[4] I get the Dimensions of the Array
this means xres, yres, zres and tres. So I can calculate
the boundaries of the array.

Its xres*yres*zres*tres*(sizeoffloat or sizeofdouble)

When using the dll from c++ I delete the pointer to the
array in my calling function after use. But you are
right, I don´t know how to do this in C# either.

Will be a problem anyway since the dll runs with
vc6 runtime and uses a different heap.

But I can fix the deallocation problem in the dll.
But I still can´t call it!

So if I know the size of the Array (after the call)
of the dll function, how to create my variables?

public class FileIO
{
int[] resolution;
float[] length;
double[] data;

[DllImport("MYLIB.DLL", SetLastError=true)]
public static extern int dll_dbl_read(
[MarshalAs(UnmanagedType.LPStr)] string fname,
ref int[] res,
ref float[] len,
ref IntPtr data);

public int dbl_read(string fname)
{
int result = 0;
resolution = new int[] {0,0,0,0};
length = new float[] {0,0,0,0 };

IntPtr pData = IntPtr.Zero;
result = dll_dbl_read( fname, ref resolution, ref length, ref pData );

int n = ... ; // calculate _number of elements_ in data
data = new double[n];
Marshal.Copy ( pData, data, 0, n );

// here you should free the memory pointed by pData...

return result;
}
}

- Passing a null-pointer by reference which means passing a pointer to a
null-pointer.
- The dll function sets this null pointer into a valid pointer by allocating
memory for the data.
- After return copy the unmanaged data into managed data.

Note that Marshal.Copy is overloaded for different data types, so you should
give the number of elements not the byte size.


HTH,
greetings

Thanks in advance

Martin





----- BMermuys wrote: -----

Hi,
[inline]

Chucker said:
I got a DLL that reads some RAW Double Data from a File to an Array.
The DLL works fine.
This is the Header of the double_read function:
int dll_dbl_read (const char * fnam,
/* File name to read from */
int * res,
/* returns int[4]*/
float * len,
/* returns float[4]*/
double ** data);
/* returns double[unknown size]*/
This is how I call the function from C++:

Two problems:
1) At least you must know the size of the array when the function returns,
unless it's 0 terminated maybe. How else could you safely use it, even in
c/c++ ?

2) To have a clean/safe solution, the DLL should also export a function
which de-allocates the memory it has allocated to 'data' when the function
(dll_dbl_read) was called. Something like "void dll_free_data( double*
data );".

HTH,
greetings
char * myfname;
int res[4];
float len[4];
double * data;
int m_type;
int DataStack::dbl_read(const char * fname)
{
m_type = dll_dbl_read(fname,res,len,&data);
myfname = new char[strlen(fname)+1];
strcpy(myfname, fname);
return m_type; }
This works fine and I would like to know how to call this function
from
C#?????
This is what I try in C# and what doesn´t work:
using System;
using System.Runtime.InteropServices;
namespace mine
{
/// <summary>> /// Summary description for FileIO.
/// </summary>>>> public unsafe class FileIO
{
public int m_type;
public char* myfname;
public int * res;
public float * len;
public double ** data;
[DllImport("MYLIB.DLL", EntryPoint="dll_dbl_read",
SetLastError=true, CharSet=CharSet.Unicode, ExactSpelling=true,
CallingConvention=CallingConvention.StdCall)]
public static unsafe extern int dll_dbl_read(char[] fnam,
int* res,
float* len, double** data);
public int dbl_read(string fname)
{
int result;
int[] resolution = {0,0,0,0};
float[] length = {0,0,0,0};
double[] mydata = {0};
myfname = &fname.ToCharArray();
fixed (int* res = resolution)
{
fixed (float* len = length)
{
fixed (double* data = mydata)
{
result = dll_dbl_read(myfname,res,len,&data);
/*Just for Testing*/
int x = res[0];
float xl = len[0];
double test = data[100];
test = data[23];
/*Everything is empty here :blush:(*/
}
}
}
return result; }
public FileIO() {
}
}
Can Anybody tell me how to Create my Variables to pass to the
function
dll_dbl_read? So that I find my data in there and not only 0 or NULL?
Thanks in Advance
Martin
 
B

BMermuys

Hi,

I've tested the code and there seems to be some problem with the fixed-size
array and the ref keyword. There's nothing wrong with the return and
process of the unfixed-size array.

Try changing the following things to:

[DllImport("MYLIB.DLL", SetLastError=true)]
public static extern int dll_dbl_read(
[MarshalAs(UnmanagedType.LPStr)] string fname,
[In, Out] int[] res,
[In, Out] float[] len,
ref IntPtr data);

result = dll_dbl_read( fname, resolution, length, ref pData );

I've tested this succesfully.

HTH more,
greetings
 
G

Guest

Thanks a lot, it works

But now my -maybe stupid- question again

How does it work the other way around

You can see what I tried in dbl_write

How to do the Marshal Copy to my Pointe
or how to get a Pointer to my data[] Array

I tried Marshal.StructureToPtr, &, and Marshal.Copy bu
none worked

Thanks in Advanc

Marti

using System
using System.Runtime.InteropServices

namespace Dickenbestimmun

/// <summary
/// Summary description for FileIO
/// </summary


public class FileI

//[DllImport("OMASLIB.DLL", EntryPoint="omas_dbl_write", SetLastError=true, CharSet=CharSet.Unicode, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)]
//public static unsafe extern int omas_dbl_write(char[] fnam, int[] res, float[] len, double[] data, int bFlt)

public int maxindex
public int canFloat
public int[] resolution
public float[] length
public double[][][] VoxelData
double[] data
IntPtr pData = IntPtr.Zero

[DllImport("OMASLIB.DLL", SetLastError=true)
public static extern int omas_dbl_write
[MarshalAs(UnmanagedType.LPStr)] string fname
[In, Out] int[] res
[In, Out] float[] len
ref IntPtr data
int canFloat)

public int dbl_write(string fname

//Marshal.Copy ( data, pData, 0, maxindex )

int result = omas_dbl_write( fname, resolution, length, ref pData, canFloat )

return result


[DllImport("OMASLIB.DLL", SetLastError=true)
public static extern int omas_dbl_read
[MarshalAs(UnmanagedType.LPStr)] string fname
[In, Out] int[] res
[In, Out] float[] len
ref IntPtr data)

public int dbl_read(string fname

int result = 0
resolution = new int[] {0,0,0,0}
length = new float[] {0,0,0,0 }

canFloat = omas_dbl_read( fname, resolution, length, ref pData )
maxindex = resolution[0]* resolution[1] * resolution[2]* resolution[3]; // calculate _number of elements_ in dat
data = new double[maxindex]
Marshal.Copy ( pData, data, 0, maxindex )

return canFloat


public FileIO(

/
// TODO: Add constructor logic her
/
 
B

BMermuys

Hi,
[inline]

Chucker said:
Thanks a lot, it works!

But now my -maybe stupid- question again.

How does it work the other way around?

You can see what I tried in dbl_write.

How to do the Marshal Copy to my Pointer
or how to get a Pointer to my data[] Array?

If a function returns an unknown-size array then you cannot allocate any
managed memory before calling it. That's why unmanaged memory is used and a
copy from unmanaged to managed heap must be done. And the reason you need
to do the copy yourself is because the framework doesn't know the size of
the returned array...


You forgot to write the C function for the writing, if data is an
one-dimensional array (e.g. double* ), then you must know a way to translate
between 4D and 1D. Then you can store only an one-dimensional array and
have some 4D methods to manipulate the data. This way you can easily pass
the 1D array without any copy.

If you write the data then I assume the data is fixed in size and not
changed by the function. If so, the framework can pin it and no copy must
be done, the dll function can use the managed data because it's pinned. The
framework will do this pinning for you.


public int maxindex;
public int canFloat;
public int[] resolution;
public float[] length;
public double[][][] VoxelData;
// wasn't this 4D ?
// are you sure about a jagged array
// multi-dimension arrays are declared as double[,,,] data = new
double[10,10,10,10];
// OR make methods that take md-cordinates to manipulate and read the 1d
data
double[] data;
IntPtr pData = IntPtr.Zero;

[DllImport("OMASLIB.DLL", SetLastError=true)]
public static extern int omas_dbl_write(
[MarshalAs(UnmanagedType.LPStr)] string fname,
[In, Out] int[] res,
[In, Out] float[] len,
[In, Out] double[] data,
int canFloat);

public int dbl_write(string fname)
{
int result = omas_dbl_write( fname, resolution, length, data,
canFloat );
return result;
}


( [In,Out] is the default for value-arrays )

HTH,
greetings

I tried Marshal.StructureToPtr, &, and Marshal.Copy but
none worked.

Thanks in Advance

Martin

using System;
using System.Runtime.InteropServices;

namespace Dickenbestimmung
{
/// <summary>
/// Summary description for FileIO.
/// </summary>


public class FileIO
{
//[DllImport("OMASLIB.DLL", EntryPoint="omas_dbl_write",
SetLastError=true, CharSet=CharSet.Unicode, ExactSpelling=true,
CallingConvention=CallingConvention.StdCall)]
//public static unsafe extern int omas_dbl_write(char[] fnam, int[] res,
float[] len, double[] data, int bFlt);
public int maxindex;
public int canFloat;
public int[] resolution;
public float[] length;
public double[][][] VoxelData;
double[] data;
IntPtr pData = IntPtr.Zero;

[DllImport("OMASLIB.DLL", SetLastError=true)]
public static extern int omas_dbl_write(
[MarshalAs(UnmanagedType.LPStr)] string fname,
[In, Out] int[] res,
[In, Out] float[] len,
ref IntPtr data,
int canFloat);

public int dbl_write(string fname)
{
//Marshal.Copy ( data, pData, 0, maxindex );

int result = omas_dbl_write( fname, resolution, length, ref pData, canFloat );

return result;
}

[DllImport("OMASLIB.DLL", SetLastError=true)]
public static extern int omas_dbl_read(
[MarshalAs(UnmanagedType.LPStr)] string fname,
[In, Out] int[] res,
[In, Out] float[] len,
ref IntPtr data);

public int dbl_read(string fname)
{
int result = 0;
resolution = new int[] {0,0,0,0};
length = new float[] {0,0,0,0 };

canFloat = omas_dbl_read( fname, resolution, length, ref pData );
maxindex = resolution[0]* resolution[1] * resolution[2]* resolution[3];
// calculate _number of elements_ in data
data = new double[maxindex];
Marshal.Copy ( pData, data, 0, maxindex );

return canFloat;
}

public FileIO()
{
//
// TODO: Add constructor logic here
//
}
}
}
 

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