From int[] to IntPtr and back

  • Thread starter Thread starter Thomas Due
  • Start date Start date
T

Thomas Due

Hi,

I am having a bit of trouble with some pinvoke signatures. The orginal
API call takes a pointer to a array. Of course when imported into C# it
takes an IntPtr.

Now, how do I get a int[] instance converted to an IntPtr?

And back again...

--
Thomas Due
Posted with XanaNews version 1.17.6.4

"To fight and conquer in all your battles is not supreme excellence;
supreme excellence consists in breaking the enemy's resistance without
fighting."
-- Sun-Tzu
 
I am tracking a similar problem, I recommend you try

InPtr myPtr = Pointer.Box(ArrayName,typeof(int *));
 
Thomas,

Can you post the original API signature? I recommend declaring the API
in C# using an array. That way the interop marshaler will either copy
or pin the data for you. For example:

[DllImport("kernel32.dll")]
public static extern void CopyMemory(int[] dst, int[] src, int len);

public void Foo()
{
int[] src = new int[] { 1, 2, 3, 4, 5 };
int[] dst = new int[source.Length];
CopyMemory(dst, src, src.Length * Marshal.SizeOf(typeof(int)));
}

If you choose to keep IntPtr in the signature then you'll need to pin
the array manually. You can do that by using GCHandle. For example:

[DllImport("kernel32.dll")]
public static extern void CopyMemory(IntPtr dst, IntPtr src, int len);

public void Foo()
{
int[] src = new int[] { 1, 2, 3, 4, 5 };
int[] dst = new int[source.Length];
GCHandle psrc = GCHandle.Alloc(psrc, GCHandleType.Pinned);
GCHandle pdst = GCHandle.Alloc(pdst, GCHandleType.Pinned);
CopyMemory(
pdst.AddrOfPinnedObject(),
psrc.AddrOfPinnedObject(),
src.Length * Marshal.SizeOf(typeof(int)));
pdst.Free();
psrc.Free();
}

As you can see, the first example is easier.

Brian
 
Why use the CopyMemory while Array.Copy does the same thing through a single
managed API call?

Willy.

Brian Gideon said:
Thomas,

Can you post the original API signature? I recommend declaring the API
in C# using an array. That way the interop marshaler will either copy
or pin the data for you. For example:

[DllImport("kernel32.dll")]
public static extern void CopyMemory(int[] dst, int[] src, int len);

public void Foo()
{
int[] src = new int[] { 1, 2, 3, 4, 5 };
int[] dst = new int[source.Length];
CopyMemory(dst, src, src.Length * Marshal.SizeOf(typeof(int)));
}

If you choose to keep IntPtr in the signature then you'll need to pin
the array manually. You can do that by using GCHandle. For example:

[DllImport("kernel32.dll")]
public static extern void CopyMemory(IntPtr dst, IntPtr src, int len);

public void Foo()
{
int[] src = new int[] { 1, 2, 3, 4, 5 };
int[] dst = new int[source.Length];
GCHandle psrc = GCHandle.Alloc(psrc, GCHandleType.Pinned);
GCHandle pdst = GCHandle.Alloc(pdst, GCHandleType.Pinned);
CopyMemory(
pdst.AddrOfPinnedObject(),
psrc.AddrOfPinnedObject(),
src.Length * Marshal.SizeOf(typeof(int)));
pdst.Free();
psrc.Free();
}

As you can see, the first example is easier.

Brian

Thomas said:
Hi,

I am having a bit of trouble with some pinvoke signatures. The orginal
API call takes a pointer to a array. Of course when imported into C# it
takes an IntPtr.

Now, how do I get a int[] instance converted to an IntPtr?

And back again...

--
Thomas Due
Posted with XanaNews version 1.17.6.4

"To fight and conquer in all your battles is not supreme excellence;
supreme excellence consists in breaking the enemy's resistance without
fighting."
-- Sun-Tzu
 
Without knowing exactly which API the OP was speaking of that was the
best example I could come up with to demonstrate the different ways of
declaring and using an API in C#. More specifically, I was hoping to
convince to the OP that declaring the API with int[] instead of IntPtr
would be easier. You are correct though, perhaps I should have chosen
something a little more realistic.

Brian
Why use the CopyMemory while Array.Copy does the same thing through a single
managed API call?

Willy.

Brian Gideon said:
Thomas,

Can you post the original API signature? I recommend declaring the API
in C# using an array. That way the interop marshaler will either copy
or pin the data for you. For example:

[DllImport("kernel32.dll")]
public static extern void CopyMemory(int[] dst, int[] src, int len);

public void Foo()
{
int[] src = new int[] { 1, 2, 3, 4, 5 };
int[] dst = new int[source.Length];
CopyMemory(dst, src, src.Length * Marshal.SizeOf(typeof(int)));
}

If you choose to keep IntPtr in the signature then you'll need to pin
the array manually. You can do that by using GCHandle. For example:

[DllImport("kernel32.dll")]
public static extern void CopyMemory(IntPtr dst, IntPtr src, int len);

public void Foo()
{
int[] src = new int[] { 1, 2, 3, 4, 5 };
int[] dst = new int[source.Length];
GCHandle psrc = GCHandle.Alloc(psrc, GCHandleType.Pinned);
GCHandle pdst = GCHandle.Alloc(pdst, GCHandleType.Pinned);
CopyMemory(
pdst.AddrOfPinnedObject(),
psrc.AddrOfPinnedObject(),
src.Length * Marshal.SizeOf(typeof(int)));
pdst.Free();
psrc.Free();
}

As you can see, the first example is easier.

Brian

Thomas said:
Hi,

I am having a bit of trouble with some pinvoke signatures. The orginal
API call takes a pointer to a array. Of course when imported into C# it
takes an IntPtr.

Now, how do I get a int[] instance converted to an IntPtr?

And back again...

--
Thomas Due
Posted with XanaNews version 1.17.6.4

"To fight and conquer in all your battles is not supreme excellence;
supreme excellence consists in breaking the enemy's resistance without
fighting."
-- Sun-Tzu
 
Brian Gideon said:
Without knowing exactly which API the OP was speaking of that was the
best example I could come up with to demonstrate the different ways of
declaring and using an API in C#. More specifically, I was hoping to
convince to the OP that declaring the API with int[] instead of IntPtr
would be easier. You are correct though, perhaps I should have chosen
something a little more realistic.

Brian

I see, you are correct the OP could remove the guesswork by posting the API
he's speaking of.

Willy.
 
Willy said:
I see, you are correct the OP could remove the guesswork by posting
the API he's speaking of.

Of course, my bad. It is the DeviceIOControl in kernel32.dll, according
to Win32SDK help, it is declared like this:

BOOL DeviceIoControl(
HANDLE hDevice,
DWORD dwIoControlCode,
LPVOID lpInBuffer,
DWORD nInBufferSize,
LPVOID lpOutBuffer,
DWORD nOutBufferSize,
LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped
);

According to www.pinvoke.net, this is "translated" to:

[DllImport("kernel32.dll", ExactSpelling = true,
SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool DeviceIoControl(
IntPtr hDevice,
uint dwIoControlCode,
IntPtr lpInBuffer,
uint nInBufferSize,
IntPtr lpOutBuffer,
uint nOutBufferSize,
out uint lpBytesReturned,
IntPtr lpOverlapped);


--
Thomas Due
Posted with XanaNews version 1.17.6.5

"To fight and conquer in all your battles is not supreme excellence;
supreme excellence consists in breaking the enemy's resistance without
fighting."
-- Sun-Tzu
 
Thomas,

Try the following:

[DllImport("kernel32.dll")]
public static extern bool DeviceIoControl(
IntPtr hDevice,
uint dwIoControlCode,
byte[] lpInBuffer,
uint nInBufferSize,
byte[] lpOutBuffer,
uint nOutBufferSize,
out uint lpBytesReturned,
IntPtr lpOverlapped);

You can declare other overloads that accept int arrays instead of byte
arrays as well. The lpOverlapped parameter is really a pointer to the
OVERLAPPED structure. If you don't plan on using overlapped operations
I'd leave it as an IntPtr and just pass in IntPtr.Zero when called.

Brian

Thomas said:
Willy said:
I see, you are correct the OP could remove the guesswork by posting
the API he's speaking of.

Of course, my bad. It is the DeviceIOControl in kernel32.dll, according
to Win32SDK help, it is declared like this:

BOOL DeviceIoControl(
HANDLE hDevice,
DWORD dwIoControlCode,
LPVOID lpInBuffer,
DWORD nInBufferSize,
LPVOID lpOutBuffer,
DWORD nOutBufferSize,
LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped
);

According to www.pinvoke.net, this is "translated" to:

[DllImport("kernel32.dll", ExactSpelling = true,
SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool DeviceIoControl(
IntPtr hDevice,
uint dwIoControlCode,
IntPtr lpInBuffer,
uint nInBufferSize,
IntPtr lpOutBuffer,
uint nOutBufferSize,
out uint lpBytesReturned,
IntPtr lpOverlapped);


--
Thomas Due
Posted with XanaNews version 1.17.6.5

"To fight and conquer in all your battles is not supreme excellence;
supreme excellence consists in breaking the enemy's resistance without
fighting."
-- Sun-Tzu
 
Back
Top