将 C# 字符串传递给 Windows Mobile 中的非托管 C DLL

发布于 2024-09-28 08:53:10 字数 458 浏览 0 评论 0原文

我有一个非托管 c++ DLL,需要从 Windows Mobile C# 应用程序 调用。

我有 C# 包装器,它在桌面上运行得很好。我可以从 C# 桌面程序调用 DLL 函数并毫无问题地传递字符串。

但是,当我编译移动平台的库和包装器时,我在 DllImport 行中收到错误,指出无法识别 CharSet.ANSI。我允许编写的唯一选项是 CharSet.Auto 和 CharSet.Unicode。

问题是,无论此设置如何,c++ 函数中接收到的字符串都是宽字符字符串,而不是它们所期望的纯 char* 字符串。

我们可以使用 wcstombs() 来翻译每个 C++ 函数开头的所有字符串,但我不想将 lib 修改到这样的程度...

有没有办法修复 C# 和 C 之间的编组可以与 .NET Compact Framework 一起使用吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

冰火雁神 2024-10-05 08:53:11

不,没有。

Microsoft 文档 指定:

[...] .NET Compact Framework
仅支持 Unicode,因此仅包括
CharSet.Unicode(和 CharSet.Auto
等于 Unicode) 值,并且
不支持任何条款
声明声明。这意味着
ExactSpelling 属性也不是
支持。

因此,如果您的 DLL 函数
需要一个 ANSI 字符串,你需要
在 DLL 中执行转换,
或将字符串转换为字节数组
使用重载的 GetBytes 方法
ASCIIEncoding 类的
,之前
调用该函数,因为 .NET
Compact Framework 总是会通过
指向 Unicode 字符串的指针。 [...]

解决方案是:

DLL中的函数

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

包装器

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

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

调用代码

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;
}

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;
}
荆棘i 2024-10-05 08:53:11

Windows CE 严重偏向 Unicode(大多数 Win32 API 甚至没有 ANSI 等效项)。因此,CF 在 ANSI 方面的表现也不是很好,它需要一点“帮助”来使其正确。

您可以使用 MarshalAs 属性 (MSDN 文档清楚地表明它在 CF 中受支持),大致如下:

[DllImport("mydll.dll", SetLastError = true)]
public static extern void Foo([MarshalAs(UnmanagedType.LPStr)]string myString);

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);
谜兔 2024-10-05 08:53:11

我发现这个marshal编译器很有用,尽管它有点错误。

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文