简体   繁体   English

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

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

I am having an issue passing a simple string from my .NET app, compiled as 64-bit, to my native DLL, also compiled as 64-bit. 我在将一个简单的字符串从我的.NET应用程序(编译为64位)传递到我的本机DLL(也编译为64位)时遇到问题。

C++ signature: C ++签名:

DllExport void SetFoo(LPWSTR foo);

C# signature: C#签名:

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

Then I run the following code in C#: 然后,我在C#中运行以下代码:

X.SetFoo("some string");

When it reaches the debugger in the DLL, the value is swearing at me in Chinese: Ⴐ虘翺 当它到达DLL中的调试器,该值在我在中国宣誓: Ⴐ虘翺

When I change both the .NET and native code to 32-bit, the value I get in the debugger is the correct string. 当我将.NET和本机代码都更改为32位时,我在调试器中获得的值是正确的字符串。 Where am I being stupid? 我在哪里傻?

Minimal reproduction as a Visual Studio 2015 Solution: download here 作为Visual Studio 2015解决方案的最小复制: 在此处下载

To reproduce: 复制:

  • Create a new Visual Studio solution with a WinForms project. 使用WinForms项目创建一个新的Visual Studio解决方案。
  • Add a Win32 Project, of type DLL to the solution 将一个DLL类型的Win32项目添加到解决方案
  • Add the following files: 添加以下文件:

Foo.h: foo.h中:

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

Foo.cpp: Foo.cpp中:

#include "stdafx.h"
#include "Foo.h"

DllExport void SetFoo(LPWSTR foo) 
{

}
  • Set a breakpoint on the opening brace in SetFoo SetFoo括号中设置断点
  • Add a button to the winforms form 在winforms表单中添加一个按钮
  • Double click it, and call SetFoo("abc123") . 双击它,然后调用SetFoo("abc123")
  • Implement SetFoo : 实现SetFoo

Form1.cs: Form1.cs中:

[DllImport("Win32Project1.dll", CallingConvention = CallingConvention.Cdecl,  CharSet = CharSet.Unicode)]
public static extern void SetFoo(string text);
  • Change the apps to build in 64-bit mode by opening Configuration Manager. 通过打开配置管理器,将应用程序更改为以64位模式构建。
  • Set Win32Project1 to build as x64 将Win32Project1设置为x64
  • Set WindowsFormApplication1 to build as x64, by picking platform new, pick x64, OK. 通过选择新平台,选择x64,确定,将WindowsFormApplication1设置为x64。
  • Change the output directory of WindowsFormsApplication1 to match the output directory of the other app. 更改WindowsFormsApplication1的输出目录以匹配另一个应用程序的输出目录。
  • Start without debugging. 无需调试即可开始。
  • Attach debugger (Ctrl+Alt+P) by setting Attach to to Managed (v4.5, v4.0) code, Native code and finding the process. 通过设置“ Attach toManaged (v4.5, v4.0) code, Native code并找到进程Attach to附加调试器(Ctrl + Alt + P)。
  • Observe value at breakpoint. 在断点处观察值。

When you interpret ANSI encoded latin text as UTF-16 you see Chinese characters. 当您将ANSI编码的拉丁文解释为UTF-16时,会看到中文字符。 That's clearly what is happening. 显然这是正在发生的事情。 So your C# code is sending ANSI encoded text somehow. 因此,您的C#代码以某种方式发送ANSI编码的文本。

The p/invoke would be better written like this: p / invoke最好这样写:

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

The [in] is not needed, it is the default. 不需要[in] ,它是默认值。 And the MarshalAs is pointless since you specified CharSet.Unicode . 并且MarshalAs是没有意义的,因为您指定了CharSet.Unicode However, neither change affects the semantics. 但是,这两个更改都不会影响语义。

The only sound explanations for what you describe in the question are: 您在问题中所描述的唯一合理的解释是:

  • The actual code is not as you have described it, or 实际的代码不是您所描述的,或者
  • There is a defect in the debugger. 调试器中存在缺陷。

I suggest that you change the unmanaged function to 我建议您将非托管功能更改为

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

If the message box displays the correct text then the conclusion would appear to be that the debugger is defective. 如果消息框显示正确的文本,则结论是调试器有缺陷。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM