gpt4 book ai didi

c# - 从 .Net 调用 native 函数时参数值困惑

转载 作者:行者123 更新时间:2023-12-02 09:51:33 24 4
gpt4 key购买 nike

现在我有一个 c++ DLL 项目,我用它作为 .Net 中较低级别功能的包装器。
C++ 代码:

string testA(uint a) {
cout << a;
return "egrt";
}
bool testB(uint a) {
cout << a;
return false;
}
C++ 头文件:
#pragma once

#ifdef API_EXPORTS
#define API __declspec(dllexport)
#else
#define API __declspec(dllimport)
#endif

typedef unsigned int uint;

extern "C" API string testA(uint a);
extern "C" API bool testB(uint a);
C#代码:
[DllImport(...)] extern static string testA(uint a);
[DllImport(...)] extern static bool testB(uint a);

static void Main() {
testA(10);
testB(13);
}
由于某种原因,testA中的参数不是我给的数字,但在testB中,它可以正常工作。
这是正常的行为吗?我究竟做错了什么?我怎样才能避免这种情况?
如果需要,我很乐意提供有关解决方案设置的更多详细信息。

最佳答案

DllImport 的默认调用约定是 stdcall ,但 C/C++ 中的默认调用约定通常是 cdecl反而。您描述的症状很容易由两种语言之间的调用约定不匹配引起,因此请确保两组代码都同意使用哪种调用约定。
此外,您不能安全地通过 C++ std::string (或任何其他基于类的字符串类型)通常跨越 DLL 边界,绝对不是语言之间。跨越语言边界时,仅使用可移植的 POD 类型非常重要。大多数语言都与 C 兼容,因此请仅使用 C 可以使用的类型(因此,在这种情况下,使用 char*/wchar_t* 表示字符串)。
还必须考虑内存管理问题。内存是如何分配的,谁负责释放内存以及如何释放等。在这种情况下,如果 C/C++ DLL 返回 char*字符串,C# 自动将该数据编码到 native string , 然后 C# 将尝试释放 char*使用 CoTaskMemFree() 的字符串,所以DLL需要分配char*使用 CoTaskMemAlloc() 的字符串,例如:

char* __stdcall testA(uint32_t a) {
cout << a;
const char *str = "egrt";
char *result = (char*) CoTaskMemAlloc(strlen(str)+1);
if (result)
strcpy(result, str);
return result;
}

bool __stdcall testB(uint32_t a) {
cout << a;
return false;
}
#pragma once

#include <cstdint>

#ifdef API_EXPORTS
#define API __declspec(dllexport)
#else
#define API __declspec(dllimport)
#endif

extern "C" API char* __stdcall testA(uint32_t a);
extern "C" API bool __stdcall testB(uint32_t a);
[DllImport(..., CharSet=CharSet.Ansi)]
extern static string testA(uint a);

[DllImport(...)]
extern static bool testB(uint a);

static void Main() {
testA(10);
testB(13);
}
如果这不是 DLL 的选项,那么 char*必须将字符串编码为 IntPtr取而代之,DLL 必须导出一个附加函数供 C# 调用以释放 char*字符串正确,例如:
char* __stdcall testA(uint32_t a) {
cout << a;
const char *str = "egrt";
char *result = ...; // allocated some other way...
if (result)
strcpy(result, str);
return result;
}

void __stdcall freeA(void *p) {
cout << p;
// deallocate p as needed...
}

bool __stdcall testB(uint32_t a) {
cout << a;
return false;
}
#pragma once

#include <cstdint>

#ifdef API_EXPORTS
#define API __declspec(dllexport)
#else
#define API __declspec(dllimport)
#endif

extern "C" API char* __stdcall testA(uint32_t a);
extern "C" API void __stdcall freeA(void *p);
extern "C" API bool __stdcall testB(uint32_t a);
[DllImport(...)]
extern static IntPtr testA(uint a);

[DllImport(...)]
extern static void freeA(IntPtr p);

[DllImport(...)]
extern static bool testB(uint a);

static void Main() {
IntPtr p = testA(10);
// string s = Marshal.PtrToStringAnsi(p);
freeA(p);
testB(13);
}

关于c# - 从 .Net 调用 native 函数时参数值困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64283118/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com