C# 将字符串从.NET传递到本机(64位)
我在将一个简单字符串从.NET应用程序(编译为64位)传递到本机DLL(也编译为64位)时遇到问题 C++签名:C# 将字符串从.NET传递到本机(64位),c#,c++,64-bit,pinvoke,C#,C++,64 Bit,Pinvoke,我在将一个简单字符串从.NET应用程序(编译为64位)传递到本机DLL(也编译为64位)时遇到问题 C++签名: DllExport void SetFoo(LPWSTR foo); [DllImport(Library, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] internal static extern void SetFoo( [In][MarshalAs(Unmanage
DllExport void SetFoo(LPWSTR foo);
[DllImport(Library, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
internal static extern void SetFoo(
[In][MarshalAs(UnmanagedType.LPWStr)] string foo);
C#签名:
DllExport void SetFoo(LPWSTR foo);
[DllImport(Library, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
internal static extern void SetFoo(
[In][MarshalAs(UnmanagedType.LPWStr)] string foo);
然后我在C#中运行以下代码:
当它到达DLL中的调试器时,该值正在用中文咒骂我:Ⴐ虘翺代码>
当我将.NET和本机代码都更改为32位时,调试器中得到的值就是正确的字符串。我在哪里犯傻
作为Visual Studio 2015解决方案的最小复制:
复制:
- 使用WinForms项目创建新的Visual Studio解决方案
- 将类型为DLL的Win32项目添加到解决方案中
- 添加以下文件:
Foo.h:
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
:
表格1.cs:
[DllImport("Win32Project1.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
public static extern void SetFoo(string text);
- 打开Configuration Manager,将应用程序更改为以64位模式构建
- 将Win32Project1设置为生成为x64
- 将WindowsFormApplication1设置为生成为x64,通过拾取平台新建,拾取x64,确定
- 更改WindowsFormsApplication1的输出目录以匹配其他应用的输出目录
- 无需调试即可启动
- 通过将
Attach to
设置为Managed(v4.5、v4.0)代码、本机代码
并查找进程,附加调试器(Ctrl+Alt+P)
- 观察断点处的值
当您将ANSI编码的拉丁文本解释为UTF-16时,您会看到汉字。这显然是正在发生的事情。因此,您的C#代码以某种方式发送ANSI编码的文本
p/invoke最好这样写:
[DllImport(Library, CallingConvention = CallingConvention.Cdecl,
CharSet = CharSet.Unicode)]
internal static extern void SetFoo(string foo);
不需要[in]
,它是默认值。由于您指定了CharSet.Unicode
,所以MarshalAs
是没有意义的。但是,这两个更改都不会影响语义
对于您在问题中所描述的内容,唯一合理的解释是:
- 实际代码与您描述的不同,或者
- 调试器中有一个缺陷
我建议您将非托管函数更改为
DllExport void SetFoo(LPWSTR foo)
{
MessageBoxW(0, L"", foo, MB_OK);
}
如果消息框显示正确的文本,那么结论似乎是调试器有缺陷。David,谢谢您的评论,但事实就是这样。我已经复制了一个最小解和。在不调试的情况下运行它,然后在调试器启动后但在您按下按钮之前附加调试器(具有本机支持)。请在问题中包含您的最小复制。非网站链接是不好的。当我在回答中使用代码时,它工作正常。我在问题中添加了一个指向解决方案的链接。有相当多的步骤设置它失败,所以我建议看看解决方案,看到它失败。场外链接不是很有用。我不知道你为什么不在这里创建MCVE。这似乎是调试器的缺陷。