Interop technic withan array of Point ???

  • Thread starter Thread starter azerty
  • Start date Start date
A

azerty

Hello

I want to create a fonction in DLL C to change value in an array of Point
come from C# world ...

I do this sample fonction in C witch return sum of (X+Y) af all items in an
Array of Point and change the value of its ...

int GetPoints5(int length, POINT* points)
{
int result = 0;
for (int i = 0; i < length; i++ )
{
result += points->x;
result += points->y;
points->x++;
points->y++;
points++;
}
return result;
}

in C# world, i do this :

[DllImport("DllENC")]
private extern static int GetPoints5(int length, Point[] points);
.....
Point[] points = new Point[int.Parse(textBox3.Text)];
for (int i = 0; i < points.Length; i++ )
{
points.X = 1;
points.Y = 2;
}
button6.Text = GetPoints5(int.Parse(textBox3.Text), points).ToString();
listBox1.DataSource = points;
.....

GetPoints5 return the good sum !!!! but points array is not modify !!! Its
seem Point pass to C function by value and not by ref ....

someone can may help me !!

thanks a lot for your help !!!
 
Sure. Allocate the array of Points so they're fixed (not sure if you're
using CF 1.0 or 2.0, so the method will be different) then pass the pointer
to the first one as an IntPtr.

-Chris
 
thanks ! chris

I will try this technic as soon as possible !!

anothers questions :

* do you think it is possible to reverse the process :

I want create an array of POINT in C DLL and get the reference in C#
assembly ??

NB : the real target is to optimize the read/write set of Point[] in file on
pocket PC .... and C DLL must be very faster than C# DLL (may be 10 times or
more !)

* Why do you say "not sure if you're using CF 1.0 or 2.0, so the method will
be different" ??


Sure. Allocate the array of Points so they're fixed (not sure if you're
using CF 1.0 or 2.0, so the method will be different) then pass the pointer
to the first one as an IntPtr.

-Chris


azerty said:
Hello

I want to create a fonction in DLL C to change value in an array of Point
come from C# world ...

I do this sample fonction in C witch return sum of (X+Y) af all items in
an Array of Point and change the value of its ...

int GetPoints5(int length, POINT* points)
{
int result = 0;
for (int i = 0; i < length; i++ )
{
result += points->x;
result += points->y;
points->x++;
points->y++;
points++;
}
return result;
}

in C# world, i do this :

[DllImport("DllENC")]
private extern static int GetPoints5(int length, Point[] points);
....
Point[] points = new Point[int.Parse(textBox3.Text)];
for (int i = 0; i < points.Length; i++ )
{
points.X = 1;
points.Y = 2;
}
button6.Text = GetPoints5(int.Parse(textBox3.Text), points).ToString();
listBox1.DataSource = points;
....

GetPoints5 return the good sum !!!! but points array is not modify !!! Its
seem Point pass to C function by value and not by ref ....

someone can may help me !!

thanks a lot for your help !!!

 
Inline...

azerty said:
thanks ! chris

I will try this technic as soon as possible !!

anothers questions :

* do you think it is possible to reverse the process :

I want create an array of POINT in C DLL and get the reference in C#
assembly ??

Yes, but it's more dangerous. You have to make sure you keep track of who
owns the pointer and who needs to free it.
NB : the real target is to optimize the read/write set of Point[] in file
on
pocket PC .... and C DLL must be very faster than C# DLL (may be 10 times
or
more !)

Just the speed of file writing. no manipulation? I doubt you'll see much
speed difference at all, but it's worth testing.
* Why do you say "not sure if you're using CF 1.0 or 2.0, so the method
will
be different" ??

In CF 2.0 I'd use Marshal.AllocHGlobal. In CF 1.0 I'd P/Invoke LocalAlloc.

-Chris
 
inline too ;-)
Yes, but it's more dangerous. You have to make sure you keep track of who
owns the pointer and who needs to free it.

I am not a specialist of theses technics ... just to understand : If I do
this, who must free the memory ?? C DLL or C# assembly ?
If C DLL create a new POINT struct, and give it to C# assembly, when GC free
the Point .net structure, it would be free the equivalent memory ? no ???


NB : the real target is to optimize the read/write set of Point[] in file
on
pocket PC .... and C DLL must be very faster than C# DLL (may be 10 times
or
more !)

Just the speed of file writing. no manipulation? I doubt you'll see much
speed difference at all, but it's worth testing.

This strategy came from another test point a few days ago : I create an
array of Int[] with ArrayList.ToArray method and directly (with the same
algo) with int[] >> I found 8 factor different speed time !!!

If I want read a file to create a very big array of Point(), I need use, in
C# world, something like BinaryReader and a lot of call of ReadInt32()
method ...

If I look inside mscorlib.dll with Reflector tools, BinaryReader execute a
lot of MSIL code to do this ...

So I think the factor between use binaryReader and C DLL must be very high
!! (but not today testing by me ...)

In CF 2.0 I'd use Marshal.AllocHGlobal. In CF 1.0 I'd P/Invoke
LocalAlloc.

-Chris
Thanks a lot for this entry point of documentation, I would be able to read
this documentation before ask another question about this !
 
I am not a specialist of theses technics ... just to understand : If I do
this, who must free the memory ?? C DLL or C# assembly ?

Depends on who allocated it.
If C DLL create a new POINT struct, and give it to C# assembly, when GC
free the Point .net structure, it would be free the equivalent memory ? no
???

To be "correct" the creator should destory it. The GC has no way to free it
becasue it has no idea about it's allocation. You're better off creating
the pointer in C#, passing it to C++ and having it populate it or telling
you if it needs to be resized.
This strategy came from another test point a few days ago : I create an
array of Int[] with ArrayList.ToArray method and directly (with the same
algo) with int[] >> I found 8 factor different speed time !!!

Totally different animal. Creating an array manually and calling
ArrayList.ToArray will be significantly different if you use C# for both.
If I want read a file to create a very big array of Point(), I need use,
in C# world, something like BinaryReader and a lot of call of ReadInt32()
method ...

Read it in larger chunks and use Buffer.BlockCopy or even more fun, unsafe
code
If I look inside mscorlib.dll with Reflector tools, BinaryReader execute a
lot of MSIL code to do this ...

So I think the factor between use binaryReader and C DLL must be very high
!! (but not today testing by me ...)

I'd put money on it that you can write it in C# with no measurable
difference in time over a C++ implementation. Maybe even faster with pure
C# because you don't need to cross the managed/unmanaged boundary and eat
the overhead of the call.

-Chris
 
Thanks a lot for your help, Chris

see inline comments more ...


Chris Tacke said:
Depends on who allocated it.

of course !! :-)
To be "correct" the creator should destory it. The GC has no way to free
it becasue it has no idea about it's allocation. You're better off
creating the pointer in C#, passing it to C++ and having it populate it or
telling you if it needs to be resized.


good way ! I try to do this with this example but something work wrong ...

for one point, it work fine :

C++:
int GetPoints4(POINT* unPoint)
{
unPoint->x++;
unPoint->y++;
return (unPoint->x + unPoint->y);
}

c# :
private extern static int GetPoints4(ref Point unPoint);
....
Point point = new Point(1,2);
int r = GetPoints4(ref point);

r=5 and point.x = 2 and point.y=3 >> perfect !!!

BUT for an array of Point() problem ! I miss something, sure :-) :

C++:
int GetPoints5(int length, POINT* points)
{
int result = 0;
for (int i = 0; i < length; i++ )
{
result += points->x;
result += points->y;
points->x++;
points->y++;
points++;
}
return result;
}

c# :
[DllImport("DllENC")]
private extern static int GetPoints5(int length, Point[] points);

Point[] points = new Point[10];
for (int i = 0; i < points.Length; i++ )
{
points.X = 1;
points.Y = 2;
}
int r = GetPoints5(int.Parse(textBox3.Text), points);
listBox1.DataSource = points;

r = 30 perfect BUT listBox1 show 10 time 1,2 and not 2,3 !!

If ref keyword is adding before Point[] ... my C# application halt directly
!!!
This strategy came from another test point a few days ago : I create an
array of Int[] with ArrayList.ToArray method and directly (with the same
algo) with int[] >> I found 8 factor different speed time !!!

Totally different animal. Creating an array manually and calling
ArrayList.ToArray will be significantly different if you use C# for both.

of course too, Array is not too expansive if I compare object[] and ToArray
method
(may be 2 times ...) the difference is very important with int[] ... (int is
valueobject, object not !! logic !!)
In fact, I wanted to create an dynamic array (I don't know the length of the
array before the process ...), so I just reproduce the algo (see with
reflector) in ArrayList and so, I delete every code to control outofRange
parameter and some other control code ...

Read it in larger chunks and use Buffer.BlockCopy or even more fun, unsafe
code

Can i do with Point() object the documentation of BlockCopy explain for
int,char, int16, etc ....
how ??
I agree with you, unsafe seems a good way too ... but in fact, I don't know
this good technic and did 'nt find an example on web ...


I'd put money on it that you can write it in C# with no measurable
difference in time over a C++ implementation. Maybe even faster with pure
C# because you don't need to cross the managed/unmanaged boundary and eat
the overhead of the call.

If I can do the GetPoints5 example with success, i totaly agree with you !!
 
int GetPoints5(int length, POINT* points)
{
int result = 0;
for (int i = 0; i < length; i++ )
{
result += points->x;
result += points->y;
points->x++;
points->y++;
points++;
}
return result;
}

c# :
[DllImport("DllENC")]
// private extern static int GetPoints5(int length, Point[] points);
private extern static int GetPoints5(int length, ref Point points);

Point[] points = new Point[10];
for (int i = 0; i < points.Length; i++ )
{
points.X = 1;
points.Y = 2;
}

// int r = GetPoints5(int.Parse(textBox3.Text), points);
int r = GetPoints5(int.Parse(textBox3.Text), ref points[0]);
listBox1.DataSource = points;

it work fine !!!
 
Back
Top