8

I've got an unmanaged c++ DLL that I need to call from a Windows Mobile C# app.

I've got the C# wrapper and it works nicely in desktop. I can call the DLL functions from a C# desktop program and pass strings around with no problem.

However, when I compile the lib and the wrapper for the mobile platform, I get an error in the DllImport lines saying that the CharSet.ANSI is not recognized. The only options I'm allowed to write are CharSet.Auto and CharSet.Unicode.

The problem is that, regardless of this setting, the strings that are received in the c++ functions are wide char strings, and not plain char* strings that is what they expect.

We can use wcstombs() to translate all strings at the beginning of each c++ function, but I'd rather not modify the lib to such an extent...

Is there a way to fix the marshalling between C# and C that works with the .NET Compact Framework?

Bryan
  • 2,775
  • 3
  • 28
  • 40
tato
  • 5,439
  • 4
  • 31
  • 27
  • [Social.msdn](http://social.msdn.microsoft.com/Forums/en-US/netfxcompact/thread/4aed0776-638a-4fde-ad61-e2462b39a961) says no :( – GSerg Oct 19 '10 at 22:45

3 Answers3

7

No, there isn't.

Microsoft documentation specifies that:

[...] the .NET Compact Framework only supports Unicode, and consequently only includes the CharSet.Unicode (and CharSet.Auto which equals Unicode) value, and does not support any of the clauses of the Declare statement. This means that the ExactSpelling property is also not supported.

As a result, if your DLL function expects an ANSI string, you'll need to perform the conversion in the DLL, or convert the string to a byte array using the overloaded GetBytes method of the ASCIIEncoding class, before calling the function, since the .NET Compact Framework will always pass a pointer to the Unicode string. [...]

The solution is:

Functions in the DLL

int MARSHALMOBILEDLL_API testString(const char* value);
const char* MARSHALMOBILEDLL_API testReturnString(const char* value);

Wrapper

[DllImport("marshalMobileDll.dll")]
public static extern int testString(byte[] value);

[DllImport("marshalMobileDll.dll")]
public static extern System.IntPtr testReturnString(byte[] value);

Calling Code

string s1 = "1234567";
int v = Wrapper.testString( Encoding.ASCII.GetBytes(s1));

string s2 = "abcdef";
IntPtr ps3 = Wrapper.testReturnString(Encoding.ASCII.GetBytes(s2));
string s3 = IntPtrToString(ps3);


private string IntPtrToString(IntPtr intPtr)
{
  string retVal = "";

  byte b = 0;
  int i = 0;
  while ((b = Marshal.ReadByte(intPtr, i++)) != 0)
  {
    retVal += Convert.ToChar(b);
  }
  return retVal;
}
tato
  • 5,439
  • 4
  • 31
  • 27
  • Finally! Explicit conversion really seems the only possible solution... Thank you very much, it works just great now! – matpop Mar 09 '16 at 09:49
2

Windows CE is heavily biased toward Unicode (most Win32 APIs don't even have ANSI equivalents). As such, the CF doesn't really do well with ANSI either and it needs a little "help" in getting it right.

You can tell the marshaler that you want to pass the data as single-byte, null terminated values by using the MarshalAs attribute (the MSDN docs clearly show it is supported in the CF), something along these lines:

[DllImport("mydll.dll", SetLastError = true)]
public static extern void Foo([MarshalAs(UnmanagedType.LPStr)]string myString);
ctacke
  • 66,480
  • 18
  • 94
  • 155
  • unfortunately, MarshalAs is not supported under Compact Framework – tato Oct 20 '10 at 16:15
  • According to who? MarshalAs most certainly *is* supported. I use it quite regularly and I do almost nothing but CF work. – ctacke Oct 20 '10 at 16:53
  • MSDN says supported since 3.5 SP1 – Julien Roncaglia Oct 22 '10 at 08:26
  • Sorry about my previous vague comment. MarshalAs is certainly supported. But the call you suggested, fails at runtime with a NotSupportedException, due to usage of LPStr type. Microsoft documentation (http://msdn.microsoft.com/en-us/library/aa446536.aspx) specifies this (search for All Unicode, All the Time in this page). – tato Nov 12 '10 at 09:05
0

I find this marshal compiler useful even thou it is a bit buggy.

giZm0
  • 1,481
  • 21
  • 37