C#与C++进行互操作时字符串处理的一些问题

现在还在做桌面这一块的,可能非常少了。昨天在调用封装的加密狗模块时,遇到了一些问题。查了一些资料,这里做一些总结。

C#与C++进行互操作时,字符串这一块需要注意几个地方。

使用char*(多字节)的情况

1、不需要修改字符串的情况,直接用string类型即可(不需要提前分配空间),这里提供一段示例代码。

先用C++封装一个导出函数 PrintName(char* strName) (C#与C++交互可参考C#与C++互操作 - zhaotianff - 博客园)

复制代码
1 #include "stdafx.h"
2 #include<iostream>
3 
4 using namespace std;
5 
6 void PrintName(char* strName)
7 {
8     cout << strName<< endl;
9 }

在C#中调用

复制代码
 1 using System.Text;
 2 using System.Runtime.InteropServices;
 3 
 4 namespace ConsoleApplication1
 5 {
 6     class Program
 7     {
 8         [DllImport("Win32Project2.dll")]
 9         public static extern void PrintName(string name);
10 
11         static void Main(string[] args)
12         {            
13             PrintName("Jack");
14         }
15     }
16 }

运行结果如下

2、需要修改字符串的情况,使用StringBuilder(需要提前分配空间),这里提供一段示例代码。

使用C++封装一个导出函数ModifyName(char* strName),这个函数会对传入的字符串进行修改

复制代码
1 void ModifyName(char* strName)
2 {
3     char* name = "David";
4 
5     strcpy_s(strName, sizeof(strName), name);
6 }

C#调用

如果使用string 类型,会发现执行ModifyName后并不会修改字符串里的内容

改成StringBuilder类型,如下

复制代码
 1 using System;
 2 using System.Text;
 3 using System.Runtime.InteropServices;
 4 
 5 namespace ConsoleApplication1
 6 {
 7     class Program
 8     {
 9         [DllImport("Win32Project2.dll")]
10         public static extern void ModifyName(StringBuilder name);
11 
12         static void Main(string[] args)
13         {         
14             var name = new StringBuilder(100);
15 
16             ModifyName(name);
17 
18             Console.WriteLine(name);
19         }
20     }
21 }

运行结果如下,运行结果正常

这里还发现一件有趣的事,就是当我把StringBuilder 的容量写小一点,当这个容量不足以容纳字符串时,CLR会改变StringBuider的容量,使它刚好能装下这些字符串。如果我直接不分配容量,CLR会分配一个稍微大一点的容量。为啥会这样我也没有去深入研究了。

分配Capacity=3的情况

不指定Capacity的情况

使用wchar_t*[LPWSTR、LPCWSTR、PWSTR、PCWSTR ](Unicode)的情况

这种情况跟上面所述一致,不修改字符串内容的,用string ,需要修改并传出的,用StringBuilder ,但是需要使用 MarshalAsAttribute 特性修饰或使用 DllImportAttribute 特性时指定 CharSet = CharSet.Unicode

这里不封装导出函数了,直接用API函数GetCurrentDirectory为例

GetCurrentDirectoryA 是多字节字符集版本,GetCurrentDirectoryW是Unicode字符集版本

复制代码
 1 using System;
 2 using System.Text;
 3 using System.Runtime.InteropServices;
 4 
 5 namespace ConsoleApplication1
 6 {
 7     class Program
 8     {
 9         [DllImport("Kernel32.dll",CharSet = CharSet.Unicode)]
10         public static extern int GetCurrentDirectoryW(int nBufferLength,StringBuilder lpBuffer);
11 
12         //或者声明成下面这种
13         //[DllImport("Kernel32.dll")]
14         //public static extern int GetCurrentDirectoryW(int nBufferLength, 
                     [MarshalAs(UnmanagedType.LPWStr)]StringBuilder lpBuffer);
15 
16 
17         [DllImport("Kernel32.dll", CharSet = CharSet.Ansi)]
18         public static extern int GetCurrentDirectoryA(int nBufferLength, StringBuilder lpBuffer);
19 
20         private const int MAX_PATH = 260;
21 
22         static void Main(string[] args)
23         {
24 
25             StringBuilder sb1 = new StringBuilder(MAX_PATH);
26             StringBuilder sb2 = new StringBuilder(MAX_PATH);
27 
28             GetCurrentDirectoryA(MAX_PATH,sb1);
29             GetCurrentDirectoryW(MAX_PATH,sb2);
30 
31             Console.WriteLine(sb1);
32             Console.WriteLine(sb2);
33            
34         }
35     }
36 }

运行结果如下:

相关推荐
艾莉丝努力练剑34 分钟前
【LeetCode&数据结构】单链表的应用——反转链表问题、链表的中间节点问题详解
c语言·开发语言·数据结构·学习·算法·leetcode·链表
还债大湿兄2 小时前
《C++内存泄漏8大战场:Qt/MFC实战详解 + 面试高频陷阱破解》
c++·qt·mfc
倔强青铜35 小时前
苦练Python第18天:Python异常处理锦囊
开发语言·python
u_topian5 小时前
【个人笔记】Qt使用的一些易错问题
开发语言·笔记·qt
珊瑚里的鱼6 小时前
LeetCode 692题解 | 前K个高频单词
开发语言·c++·算法·leetcode·职场和发展·学习方法
AI+程序员在路上6 小时前
QTextCodec的功能及其在Qt5及Qt6中的演变
开发语言·c++·qt
xingshanchang6 小时前
Matlab的命令行窗口内容的记录-利用diary记录日志/保存命令窗口输出
开发语言·matlab
Risehuxyc6 小时前
C++卸载了会影响电脑正常使用吗?解析C++运行库的作用与卸载后果
开发语言·c++
时光追逐者6 小时前
C#/.NET/.NET Core技术前沿周刊 | 第 46 期(2025年7.7-7.13)
c#·.net·.netcore
AI视觉网奇6 小时前
git 访问 github
运维·开发语言·docker