c++ 中的字符串?

发布于 2024-12-08 01:14:03 字数 508 浏览 0 评论 0原文

我的问题是,我在 DLL 中有一些函数,其中一些函数例如:

#include <string>
using namespace std;
extern "C" __declspec(dllexport) string __cdecl encryption(string s)
{
 return s;
}

每当我尝试从 C# 调用此函数时,这是我使用的代码:

[DllImport("Packer.dll", EntryPoint = "encryption")]
static extern string encryption(string s);

我收到错误: 对 PInvoke 函数“Packer”的调用使堆栈不平衡。这可能是因为托管 PInvoke 签名与非托管目标签名不匹配。检查 PInvoke 签名的调用约定和参数是否与目标非托管签名匹配。

我猜我收到此错误是因为我没有正确的函数声明 谁能指导我如何解决这个问题,提前致谢

My problem is , i have some functions in a DLL some of these functions are for example :

#include <string>
using namespace std;
extern "C" __declspec(dllexport) string __cdecl encryption(string s)
{
 return s;
}

Whenever i try to call this function from C# , here is the code im using :

[DllImport("Packer.dll", EntryPoint = "encryption")]
static extern string encryption(string s);

i get an error :
A call to PInvoke function 'Packer' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.

im guessing i get this error because i dont have the right declarations for the function
can anyone guide me how to fix that , thanks in advance

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

明月松间行 2024-12-15 01:14:03

std::string 不能与 PInvoke 一起使用,因为 C++ 没有为其对象提供正确清理堆栈、复制对象等所需的 ABI。这是 C++ 最大的痛苦之一。

您必须使用 char* 指针和纯 C API。简而言之,PInvoke 不适用于 C++。

std::string can not be used with PInvoke, because C++ does not have an ABI for its objects which is required to properly clean stack, copy objects, etc. This is one of the greatest pains of C++.

You have to use char* pointers and plain C APIs. Simply put, PInvoke does not work with C++.

我的黑色迷你裙 2024-12-15 01:14:03

我相信您已经知道,C++ std::string 实际上是一个模板。仅当模板被实例化时(在本例中为 std::basic_string),该类型的对象的确切布局和方法的签名由 C++ 编译器确定。

不幸的是,只有相关的 C++ 编译器才能访问所有相关信息(例如模板源代码)来做出此类决策。这就是为什么模板等非 C 功能即使在不同的 C++ 编译器之间通常也不能“转移”,更不用说 C++ 和 C# 了。

此外,C++ 名称通常以 C++ 编译器特定的方式“损坏”。

您必须更改本机方法的签名,以便它成为“纯”C 函数:

  • 通过将函数声明为 extern "C" (您是已经在这样做了)。
  • 使用 char* 参数而不是 std::string
  • 返回 char* 结果而不是 std::string,但为 非常小心你的做法。
  • 确保您的 DllImportAttribute.CallingConvention 与 C 中的 __cdecl__stdcall__fastcall 匹配。

As I'm sure you already know, the C++ std::string is actually a template. Only when the template is instantiated (as std::basic_string<char> in this case), the exact layout of the objects of that type and signatures of the methods are determined by the C++ compiler.

Unfortunately, only the C++ compiler in question has the access to all the relevant information (such as template source code) to make these kinds of decisions. That's why non-C features such as templates are generally not "transferable" even between different C++ compilers, let alone C++ and C#.

Also, C++ names are typically "mangled" in a C++ compiler-specific manner.

You'll have to change the signature of your native method, so it is becomes a "pure" C function:

  • Ensure there is no C++ name mangling by declaring the function as extern "C" (you are already doing that).
  • Use char* parameter instead of std::string.
  • Return char* result instead of std::string, but be very careful how you do it.
  • Ensure your DllImportAttribute.CallingConvention matches the __cdecl, __stdcall or __fastcall in your C.
岁吢 2024-12-15 01:14:03

这里的问题是,您使用的是 C# 不知道如何封送的 STL string 类。这里有两个选择:

  1. 重构 C++ 代码以使用 char * 缓冲区。或者编写一个包装器或重载或使用 char * 而不是 string 的内容。
  2. 围绕使用 System::String 的 C++ 函数编写一个 C++/CLI 包装器,并在内部调用 STL 字符串版本。

The problem here is, you're using the STL string class which C# doesn't know how to marshal. You have two options here:

  1. refactor your C++ code to work with char * buffers. Or write a wrapper or an overload or something that uses char * instead of string.
  2. Write a C++/CLI wrapper around your C++ functions that uses System::String and calls the STL string versions internally.
生生漫 2024-12-15 01:14:03

如果内存可用,如果您没有另外指定,P/Invoke 假定调用约定为 __stdcall。如果是这样,将 __cdecl 更改为 __stdcall 应该可以解决第一个问题。
正如@Adam Rosenfield 指出的那样,您可能还需要传递并返回一个 char const *,而不是 string。 C# 和 C++ 几乎肯定对字符串的构成有一些不同的想法。

If memory serves, if you don't specify otherwise P/Invoke assumes the calling convention is __stdcall. If so, changing your __cdecl to __stdcall should fix the first problem.
As @Adam Rosenfield points out, you probably also need to pass and return a char const *, not a string. C# and C++ almost certainly have somewhat different ideas of what constitutes a string.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文