将字符串从.net传递到本机(64位)

Passing string from .NET to native (64-bit)

本文关键字:本机 64位 字符串 net      更新时间:2023-10-16

我遇到了一个问题,从我的。net应用程序传递一个简单的字符串,编译为64位,到我的本机DLL,也编译为64位。

c++签名:

DllExport void SetFoo(LPWSTR foo);
c#签名:

[DllImport(Library, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
internal static extern void SetFoo(
     [In][MarshalAs(UnmanagedType.LPWStr)] string foo);

然后我在c#中运行以下代码:

X.SetFoo("some string");

当它到达DLL中的调试器时,该值用中文咒骂我:Ⴐ虘翺

当我将。net和本机代码都更改为32位时,我在调试器中得到的值是正确的字符串。我在哪里犯傻了?

最小化复制作为Visual Studio 2015解决方案:在这里下载

复制:

  • 用WinForms项目创建一个新的Visual Studio解决方案。
  • 在解决方案中添加一个DLL类型的Win32项目
  • 添加以下文件:

foo:

extern "C" {
    __declspec( dllexport ) void SetFoo(LPWSTR);
}

Foo.cpp:

#include "stdafx.h"
#include "Foo.h"
DllExport void SetFoo(LPWSTR foo) 
{
}
  • SetFoo
  • 中设置一个断点
  • 为winforms表单添加一个按钮
  • 双击,呼叫SetFoo("abc123")
  • 实现SetFoo:

Form1.cs:

[DllImport("Win32Project1.dll", CallingConvention = CallingConvention.Cdecl,  CharSet = CharSet.Unicode)]
public static extern void SetFoo(string text);
  • 通过打开配置管理器将应用程序更改为64位模式。
  • 设置Win32Project1构建为x64
  • 设置WindowsFormApplication1构建为x64,通过选择平台新,选择x64, OK。
  • 将WindowsFormsApplication1的输出目录更改为与其他应用程序的输出目录匹配。
  • 不调试启动。
  • 附加调试器(Ctrl+Alt+P)通过设置Attach toManaged (v4.5, v4.0) code, Native code并找到进程。
  • 观察断点处的值

当您将ANSI编码的拉丁文本解释为UTF-16时,您将看到中文字符。这显然是正在发生的事情。所以你的c#代码以某种方式发送ANSI编码文本。

p/调用最好这样写:

[DllImport(Library, CallingConvention = CallingConvention.Cdecl, 
    CharSet = CharSet.Unicode)]
internal static extern void SetFoo(string foo);

[in]是不需要的,它是默认的。MarshalAs是没有意义的,因为您指定了CharSet.Unicode。但是,这两个更改都不会影响语义。

你在问题中所描述的唯一合理的解释是:

  • 实际代码不像你描述的那样,或者
  • 调试器有缺陷

我建议您将非托管函数更改为

DllExport void SetFoo(LPWSTR foo) 
{
    MessageBoxW(0, L"", foo, MB_OK);
}

如果消息框显示正确的文本,则结论似乎是调试器有缺陷。