Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I pass a pointer to an integer in C#

I have a C API with the signature:

int GetBuffer(char* buffer, int* maxSize)

In C, I will call it this way:

char buffer[4096];
int maxSize = 4096;
GetBuffer(buffer, &maxSize);

maxSize is set to the buffer size, and set with the actual size filled.

I need to call it from C#. How do I do that under "safe mode"?

like image 502
Sherwood Hu Avatar asked Oct 16 '09 17:10

Sherwood Hu


People also ask

Can you cast a pointer to an integer in C?

Any pointer type may be converted to an integer type. Except as previously specified, the result is implementation-defined.

Can you assign a pointer to an int?

No, it is no valid to assign a pointer to an integer. It's a constraint violation of the assignment operator (C99, 6.5. 16.1p1). A compiler has the right to refuse to translate a program with a pointer to integer assignment.

How do you pass a pointer to an integer in C++?

Passing Pointers to Functions in C++ C++ allows you to pass a pointer to a function. To do so, simply declare the function parameter as a pointer type.

Can you pass a pointer by value?

Pointers are passed by value as anything else. That means the contents of the pointer variable (the address of the object pointed to) is copied.


2 Answers

One option is simply to use C# pointer types - this requires unsafe block (or modifier on method/class), and compiling with /unsafe:

[DllImport(...)]
static extern int GetBuffer(byte* buffer, ref int maxSize);

Buffer can be allocated in several different ways. One would be to use a pinned heap array:

fixed (byte* buffer = new byte[4096])
{
    int maxSize = buffer.Length;
    GetBuffer(buffer, ref maxSize);
}

Another is to use stackalloc, though this is only feasible for small buffers:

byte* buffer = stackalloc byte[4096];
int maxSize = 4096;
GetBuffer(buffer, ref maxSize);

This particular approach is virtually identical to your C code in terms of performance and allocation patterns.

Another option altogether is to use marshaling for heap arrays, and avoid pointers entirely.

[DllImport(...)]
static extern int GetBuffer([Out] byte[] buffer, ref int maxSize);

byte[] buffer = new byte[4096];
int maxSize = buffer.Length;
GetBuffer(buffer, ref maxSize);
like image 60
Pavel Minaev Avatar answered Sep 20 '22 22:09

Pavel Minaev


This should work without unsafe code.

extern int GetBuffer(IntPtr buffer, ref int bufSize);

// ...
byte[] buf = new byte[kBufSize];
GCHandle handle = GCHandle.Alloc(buf, GCHandleType.Pinned); // possibly expensive call 
IntPtr p = handle.AddrOfPinnedObject();
int size = buf.Length;
int ret = GetBuffer(p, ref size);
handle.Free();
like image 23
plinth Avatar answered Sep 17 '22 22:09

plinth