我有一个.NET程序,该程序使用DLL导出来获取用户名称.

public static extern string Name(byte[] buf);

这是导出,我真的不想更改它,因为许多代码都依赖于它.所以,我想知道,在C++中,如何将char*数组转换为字节缓冲区?

我试过这个:

void Name(std::byte buf[256])
{
    std::string s{ "test" };
    std::byte* ptr = reinterpret_cast<std::byte*>(s.data());
    buf = ptr;
    return;
}

当我打印出我转换的字符串时,我什么也得不到,它是空的.

推荐答案

您的C++函数实现与C#函数声明的预期不匹配.

C#字节数组作为指向数组原始内存的固定指针编组到函数中.您在C++代码中为参数(std::byte buf[256])使用的语法只是语法糖,编译器实际上将其视为指针(std::byte* buf).在这种情况下这很好.但是,您的C++函数实际上并没有将指针指向的任何内容复制到内存中.您只需将指针本身更改为指向不同的内存地址.指针本身是一个局部变量,因此当函数退出时,指针将不再存在,并且不管它指向什么.

此外,C#声明期望函数返回可以封送到的内容.NET string,但C++函数实际上并没有return'ing任何东西.string返回值的默认编组行为为UnmanagedType.LPStr,因此C++函数需要返回指向以null结尾的char*字符串的指针.该字符串的内存必须分配CoTaskMemAlloc(),因为封送拆收器将获得内存的所有权,并在将char个数据转换为string后释放CoTaskMemFree()个内存.

此外,C++函数没有定义调用约定,因此它将使用编译器的默认值(通常为__cdecl,除非您更改编译器的设置).但是,默认的调用约定是.NET的DllImport期望使用的C++函数是__stdcall(为了与Win32 API兼容).这种不匹配在64位中无关紧要,但在32位中却很重要.

在不更改C#声明的情况下,在C++端try 以下操作:

char* __stdcall Name(std::byte buf[256])
{
    std::string s{ "test" };
    size_t size = s.size() + 1;
    memcpy(buf, s.c_str(), size);
    void *ptr = CoTaskMemAlloc(size);
    memcpy(ptr, s.c_str(), size);
    return ptr;
}

这就是说,让一个函数同时在字节数组输出参数和返回值中返回字符串是很奇怪的.您确定字节数组不是要用作输入参数,而是函数解析其内容以提取amd字符串吗?这会更有意义.如果你能更新你的问题来展示你的答案,这将非常有帮助.NET代码实际上是调用C++函数并使用字节array.

Csharp相关问答推荐

MongoDB实体框架核心:表达必须可写

C#将参数传递给具有变化引用的变量

我无法在Ubuntu下编译使用microsoft.extension.configurationbuilder jsonapi和mono mcs的c#应用程序

哪个nuget包含SecurityStampValidatorOptions

如何在Visual Studio代码中更改大括号模式{},用于C#语言

在路由中使用枚举

应用程序重新启动后,EFCore列表的BSON反序列化错误

C#-从基类更新子类

如何在C#中使用Postman中的本地IP向本地主机上运行的本地API发出请求

异步任务导致内存泄漏

当试图限制EF Select 的列时,如何避免重复代码?

无法将生产环境的AppDbContext设置替换为用于集成测试的内存数据库

Regex字母数字校验

在implementationFactory中避免循环依赖

这是否比决定是否使用ConfigureAWait(False)更好?

使用可空引用类型时C#接口实现错误

Linq SELECT的多条指令

SharpZipLib在文件名前加上目录名,生成tar.gz

HttpClient,上传文件时实现进度

C#LINQ多行条件