marshaling strings - ArrayTypeMismatchException

G

Guest

I am trying to return strings from a P/invoke call to a C based DLL possibly
with a direct interface from C#.
I can get all basic types across, up to pointers to byte[] and then do the
Ascii to Unicode conversion on .netcf.
However I would like to just prepare the strings in the DLL and return them
"ready oto go".
Here's the code - ehant am I missing?
Thanks ahead
tb

C:
DllExport wchar_t* getString()
//a char* can be picked up via IntPtr for conversion
// but this (char* or wchar_t*) always gets me to an exception
{
wchar_t* result;
printf ("wcslen(L\"123abc\")=%d\n",wcslen(L"123abc"));
result = (wchar_t*)malloc((wcslen(L"123abc")+1) * sizeof(wchar_t));//??
somewhere the example said CoTaskMemAlloc - don't have that symbol so far...
wcscpy(result, L"123abc");
//those 2 confirm the string is ok
printf ("returning string to managed side - object reference = %d\n",
result);
wprintf(L"Result = :%s:\n",result);
return (wchar_t*) result;
}

c#:
[DllImport("my.dll")]
public static extern void passString (String str); //this works!!
[DllImport("my.dll")]
public static extern String getString (); //this not

//and the call:
Console.WriteLine("String returned " + getString());
 
S

Sergey Bogdanov

The marshaler in CF 1.0 CLR doesn't support "string" as return value.
That is why instead of:

[DllImport("my.dll")]
public static extern String getString ();

You have to write:

[DllImport("my.dll")]
public static extern IntPtr getString ();

After that use
OpenNETCF.Runtime.InteropServices.MarshalEx.PtrToStringUni to convert
IntPtr to String and don't forget to release pointer after conversion.

For CF2.0 now we have MarshalAs attribute which simplifies it.


HTH
 
G

Guest

Aside from Sergey's comment, that' a nice memory leak you've got. Generally
speaking you should *never* be returning a string from a function because of
this exact possibility.

Your callee is allocating memory, then passing that reference back to the
caller. First, the caller doesn't own it, second, who's going to free that
malloc? This is really bad design and is completly unmaintainable code.
Imagine inheriting the DLL as a developer and trying to debug the leak. You
should pass in an already allocated buffer, then have the called method fill
it, just like everyone else does.

-Chris
 
G

Guest

Sergey,
thanks, that clarifies it. Needing additional code I can then use 2.0 (don't
have VS2005 yet in Germany...) or having to go with the IntPtr I can pull
the string into .NETCF with the encoder class.

Chris,
I know - however the DLL I am using is doing the mmgmt, every string
returned is link-listed and associated with an dll internal object and will
be free'd when that object is deleted. All I need is simple access to strings
that are actually the dll's responsibility and as I am generating the
interface from the DLL's .h files by SW (I guess am too lazy to handwrite
these for n00+ calls...) so I wanted to keep those calls as simple as
possible...

Anyways, thanks, truly appreciate your support & wow, that was really quick!!
:)
Theo



Aside from Sergey's comment, that' a nice memory leak you've got. Generally
speaking you should *never* be returning a string from a function because of
this exact possibility.

Your callee is allocating memory, then passing that reference back to the
caller. First, the caller doesn't own it, second, who's going to free that
malloc? This is really bad design and is completly unmaintainable code.
Imagine inheriting the DLL as a developer and trying to debug the leak. You
should pass in an already allocated buffer, then have the called method fill
it, just like everyone else does.

-Chris



tb2000 said:
I am trying to return strings from a P/invoke call to a C based DLL
possibly
with a direct interface from C#.
I can get all basic types across, up to pointers to byte[] and then do the
Ascii to Unicode conversion on .netcf.
However I would like to just prepare the strings in the DLL and return
them
"ready oto go".
Here's the code - ehant am I missing?
Thanks ahead
tb

C:
DllExport wchar_t* getString()
//a char* can be picked up via IntPtr for conversion
// but this (char* or wchar_t*) always gets me to an exception
{
wchar_t* result;
printf ("wcslen(L\"123abc\")=%d\n",wcslen(L"123abc"));
result = (wchar_t*)malloc((wcslen(L"123abc")+1) * sizeof(wchar_t));//??
somewhere the example said CoTaskMemAlloc - don't have that symbol so
far...
wcscpy(result, L"123abc");
//those 2 confirm the string is ok
printf ("returning string to managed side - object reference = %d\n",
result);
wprintf(L"Result = :%s:\n",result);
return (wchar_t*) result;
}

c#:
[DllImport("my.dll")]
public static extern void passString (String str); //this works!!
[DllImport("my.dll")]
public static extern String getString (); //this not

//and the call:
Console.WriteLine("String returned " + getString());
 
G

Guest

Btw: If the marshaller is not supporting a type it normally throws some
"notSupported" - here however the error is thrown inside String.Concat as
ArrayTypeMismatchException
bei System.String.Concat()
bei tbe.dump.Test()
bei tbe.dump.Main()
So apparently NETCF IS trying to convert the type?
Rgds
Theo


Sergey Bogdanov said:
The marshaler in CF 1.0 CLR doesn't support "string" as return value.
That is why instead of:

[DllImport("my.dll")]
public static extern String getString ();

You have to write:

[DllImport("my.dll")]
public static extern IntPtr getString ();

After that use
OpenNETCF.Runtime.InteropServices.MarshalEx.PtrToStringUni to convert
IntPtr to String and don't forget to release pointer after conversion.

For CF2.0 now we have MarshalAs attribute which simplifies it.


HTH

--
Sergey Bogdanov [.NET CF MVP, MCSD]
http://www.sergeybogdanov.com

I am trying to return strings from a P/invoke call to a C based DLL possibly
with a direct interface from C#.
I can get all basic types across, up to pointers to byte[] and then do the
Ascii to Unicode conversion on .netcf.
However I would like to just prepare the strings in the DLL and return them
"ready oto go".
Here's the code - ehant am I missing?
Thanks ahead
tb

C:
DllExport wchar_t* getString()
//a char* can be picked up via IntPtr for conversion
// but this (char* or wchar_t*) always gets me to an exception
{
wchar_t* result;
printf ("wcslen(L\"123abc\")=%d\n",wcslen(L"123abc"));
result = (wchar_t*)malloc((wcslen(L"123abc")+1) * sizeof(wchar_t));//??
somewhere the example said CoTaskMemAlloc - don't have that symbol so far...
wcscpy(result, L"123abc");
//those 2 confirm the string is ok
printf ("returning string to managed side - object reference = %d\n",
result);
wprintf(L"Result = :%s:\n",result);
return (wchar_t*) result;
}

c#:
[DllImport("my.dll")]
public static extern void passString (String str); //this works!!
[DllImport("my.dll")]
public static extern String getString (); //this not

//and the call:
Console.WriteLine("String returned " + getString());
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top