views:

354

answers:

3

Hi,

How can I read the error string in C# from this C++ dll call?

//
//  PARAMETERS:
//   objptr
//    Pointer to class instance.
//
//   pBuffer
//    Pointer to buffer receiving NULL terminated error message string. 
//    If this value is zero, the function returns the required buffer size, in bytes,
//    and makes no use of the pBuffer. 
//
//   nSize
//    Size of receiving buffer.
//    If this value is zero, the function returns the required buffer size, in bytes,
//    and makes no use of the pBuffer. 
//
//  RETURN VALUES:
//   If pBuffer or nSize is zero, the function returns the required buffer size, in bytes.
//   If the function succeeds, the return value is number of bytes copied into pBuffer.
//   If function fails return value is 0.
//
extern unsafe int GetError(uint objptr, byte* pBuffer, int nSize);

thanks!

+1  A: 

If you change the data type from byte* to IntPtr this might work:

Marshal.PtrToStringAnsi

Or one of the string constructors (one of them also includes an Encoding parameter):

String Constructors

Aviad P.
A: 

Marshal.AllocHGlobal(int) plus Marshal.PtrToStringAuto(IntPtr, int) perhaps?

Some code context would be nice, as I'm assuming that you're already coercing byte* into an IntPtr using p/invoke or some other trickery.

Basically, call your function to get the buffer size, allocate a buffer using AllocHGlobal(), call it again, read the string in, then free the buffer (using Marshall.FreeHGlobal(IntPtr)). This is assuming you can use Marshall's allocator, of course.

Kevin Montrose
+2  A: 
byte[] buffer = new byte[1000];
int size;
unsafe
{
  fixed ( byte* p = buffer )
  {
    size = GetError( ???, p, buffer.Length ); 
  }
}
string result = System.Text.Encoding.Default.GetString( buffer, 0, size );
danbystrom
I used GetError(???, null, 0) to get the message size in order to create the buffer and worked also perfect. Thanks!
Dawkins
You could also try to change byte* to StringBuilder and pass that instead and avoid the unsafe code.
Mikael Svenson
@Mikael: how can I do it? The dll method expects byte*
Dawkins
@Dawkins: what the method really expects is a 32 bit pointer. What it points to doesn't really matter as long as it points to something that it can write to without causing a protection fault. Using a StringBuilder will work, just as Mikael says - as long as you remember to allocate sufficient memory in the StringBuilder. Since your question specifically stated a byte* and unsafe code - I just went down that road in my answer. There exists quite a few more possible solutions.
danbystrom
thanks danbystrom, but how should I pass the Stringbuilder? The compiler throws an exception if I just replace the byte* with it.
Dawkins
It should not. Not if you change the declaration and then pass it a StringBuilder.
danbystrom