C# Pointers.. "int*" anyone?

  • Thread starter Thread starter Stuart
  • Start date Start date
S

Stuart

Ok
let me explain: I am writing a c# program that calls into
an unmanaged C++ third-party DLL. I have to make a number
of calls and for simplification the protype I am calling
is:
bool fn(int *pResult);

This result is used by other subsequent functions that I
have to call.
Q: Is it possible to call this function from C# declaring
a variable that is a pointer which can be used later on to
pass as an (int *)?

I have done it using the <unsafe> declaration, but our
*architecture* team dont like it. I have tried with the
Reflection.Pointers and also __makeref(), but these dont
give me what I need.

Anyone got any ideas!
Thanks in anticipation
Stu
 
Stuart said:
let me explain: I am writing a c# program that calls into
an unmanaged C++ third-party DLL. I have to make a number
of calls and for simplification the protype I am calling
is:
bool fn(int *pResult);

This result is used by other subsequent functions that I
have to call.
Q: Is it possible to call this function from C# declaring
a variable that is a pointer which can be used later on to
pass as an (int *)?

Have you tried passing an int by ref instead?
 
Yup... tried bool foo(ref int)

All the time I get a compiler error which effectively
states:
"Cannot convert ref int to int*"

Incidentally:
I *can* do this with code that is marked unsafe... but the
powers at be (i.e. the architecture bods) dont like this
(tbh: i'm not sure if they dont understand, or just *fear*
the unsafe keyword for an aesthetic reason.)

My (limited) understanding is that effectively I am trying
to convince the c# compiler to pass the address of an int
around - something that c# can not inherently do as the
gac randomly moves memory - hence the *pinning* or
*fixing* of variables in the *unsafe* sections. As
c#doesn't have *pointers*, by definition, any code that
declares them is effectively syntactically incorrect
unless explicitly marked as unsafe.

Therefore is this banging my head against a brick wall?
:)

I've even thought of custom marshalling (yuk!)
Stu
 
Stu,

The reason you are getting the compiler error is that you have to remove
the unsafe declaration so that it is not there anymore. For example, your
original definition looked like this:

[DllImport("some.dll")]
public extern unsafe bool fn(int *pResult);

And the call looked like this:

unsafe
{
// Make the call.
int pintResult = 0;
fn(&pintResult);
}

Or something to that effect.

Your declaration should look like this:

[DllImport("some.dll")]
public extern bool fn(ref int pResult);

And the call should look like this:

// The result.
int pintResult = 0;

// Make the call.
fn(ref pintResult);

Hope this helps.
 
Ok,
Firstly apologies! looks like my questions were too
abstracted from the orginal problem. Its my
misunderstanding of the developer's requirements!

The orginal Win32 function is this:

unsigned long
STDCALL findByName(
char *searchString, // pointer to wildcard
search string
long startCategory, // 0
int categoriesOnly, // 0, or 1
long *categoryIDs, // array of long
char categoryNames[][51],// array
int *numCategories, // int (returned count)
long *billerIDs, // array of long
char billerNames[][51], // array
int *numBillers); // int (returned count)

This is exported in a third party DLL. All memory must be
preallocated before call which the function fills in for
you.

In in order to call this, we have to set up and allocate
memory for the required arrays and pass in the pointers.
Invocation of the function fills the arrays and also a the
counts (max elements in all the arrays)

When the arays were returned, C# interpreted them as a
single value types, not as array resulting in some rather
*interesting* code to go through the returned data looking
for null terminators etc.

So is there anyway to *nicely* invoke and manipulate the
returned array information?

Stu


-----Original Message-----
Stu,

The reason you are getting the compiler error is that you have to remove
the unsafe declaration so that it is not there anymore. For example, your
original definition looked like this:

[DllImport("some.dll")]
public extern unsafe bool fn(int *pResult);

And the call looked like this:

unsafe
{
// Make the call.
int pintResult = 0;
fn(&pintResult);
}

Or something to that effect.

Your declaration should look like this:

[DllImport("some.dll")]
public extern bool fn(ref int pResult);

And the call should look like this:

// The result.
int pintResult = 0;

// Make the call.
fn(ref pintResult);

Hope this helps.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Yup... tried bool foo(ref int)

All the time I get a compiler error which effectively
states:
"Cannot convert ref int to int*"

Incidentally:
I *can* do this with code that is marked unsafe... but the
powers at be (i.e. the architecture bods) dont like this
(tbh: i'm not sure if they dont understand, or just *fear*
the unsafe keyword for an aesthetic reason.)

My (limited) understanding is that effectively I am trying
to convince the c# compiler to pass the address of an int
around - something that c# can not inherently do as the
gac randomly moves memory - hence the *pinning* or
*fixing* of variables in the *unsafe* sections. As
c#doesn't have *pointers*, by definition, any code that
declares them is effectively syntactically incorrect
unless explicitly marked as unsafe.

Therefore is this banging my head against a brick wall?
:)

I've even thought of custom marshalling (yuk!)
Stu



that
I on
to


.
 
Stuart,
unsigned long
STDCALL findByName(
char *searchString, // pointer to wildcard
search string
long startCategory, // 0
int categoriesOnly, // 0, or 1
long *categoryIDs, // array of long
char categoryNames[][51],// array
int *numCategories, // int (returned count)
long *billerIDs, // array of long
char billerNames[][51], // array
int *numBillers); // int (returned count)

Try declaring it like this

[DllImport("Your.dll")]
static extern uint findByName(
string searchString,
int startCategory,
int categoriesOnly,
int[] categoryIDs,
IntPtr[] categoryNames,
out int numCategories,
int[] billerIDs,
IntPtr[] billerNames,
out int numBillers);

And then for every valid pointer (IntPtr) you get back in the arrays,
call Marshal.PtrToStringAnsi().



Mattias
 
Back
Top