You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#调用C++方法时LPCTSTR参数部分字符显示为?的问题排查

问题场景

C++项目中定义如下导出方法:

long CPPProject::CPPMethod(long lValue, LPCTSTR Data){
    // 业务逻辑实现
}

通过C#项目调用该方法时,LPCTSTR类型的Data参数偶发接收到值为?的异常结果:

  • 传入包含Unicode字符Đ(编码\u0110)的字符串sText1时,Data参数可正常接收Đ字符,对应C#调用代码:
String sText1 = "u0110 \u0110"; //Đ
object.CPPMethod(lValue, sText1);
  • 传入包含Unicode字符腢(编码\u8162)的字符串sText2时,Data参数取值变为?,该现象通过将参数值写入日志文件观测得到,对应C#调用代码:
String sText2 = "u8162 \u8162";//腢 
object.CPPMethod(lValue, sText2);
异常根因

异常由C#与C++互操作时的字符集配置不匹配导致,结合LPCTSTR的类型特性触发:

  • LPCTSTR是Win32平台的自适应字符类型,实际类型由C++项目编译宏决定:预定义UNICODE宏时等价于const wchar_t*(UTF-16宽字符),未定义时等价于const char*(当前系统ANSI代码页对应的多字节字符)。
  • C#的string原生为UTF-16编码,如果P/Invoke互操作声明时未显式指定字符集,运行时默认按ANSI编码封送字符串:即把UTF-16字符串转换为当前系统默认代码页(简体中文Windows环境为GBK/CP936)的多字节序列,转换时遇到代码页未收录的字符,会直接替换为?占位符。
  • 两个字符表现不同的原因:字符Đ(\u0110)在系统ANSI代码页的映射范围内,可正常转换;字符腢(\u8162)不在GBK/CP936字符映射表中,转换阶段被替换为?,与日志观测结果完全一致。

注:如果日志写入时未指定支持全量Unicode的编码(如UTF-8、UTF-16),也可能在日志输出环节额外引入字符替换问题,但本场景的核心触发点是互操作封送阶段的字符集错配。

修复方案

优先选择统一Unicode字符集的方案,可从根源避免字符转换丢失问题:

  1. C++项目侧:打开项目属性页,将「配置属性-常规-字符集」选项设置为使用Unicode字符集,确保LPCTSTR被正确解析为UTF-16宽字符指针。
  2. C#侧:编写P/Invoke声明时显式指定Unicode字符集,同时匹配C++侧的调用约定,示例声明如下:
// 替换DllImport参数为你项目实际的dll名称、调用约定
[DllImport("CPPProject.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
public static extern long CPPMethod(long lValue, string Data);
  1. 日志侧:写入日志文件时显式指定UTF-8或UTF-16编码,不要使用系统默认ANSI编码写文件,避免日志输出环节出现额外的字符乱码。

如果受历史代码限制必须使用ANSI字符集(不推荐),则无法支持全量Unicode字符,仅可通过指定对应支持目标字符的代码页做封送,遇到代码页外的字符仍会出现?占位问题。

内容的提问来源于stack exchange,提问作者Ferrus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 06:15:41