我编写了一个 C++ DLL,现在我需要从托管应用程序调用 native 函数。
导出的原生函数如下所示:
extern "C" __declspec(dllexport)
bool NativeMethod(char *param1, char *param2, char *result);
因此,在 C# 中,我将调用该函数传递 2 个输入参数、1 个输出参数,显然我将读取返回的 bool 值。
我尝试以多种方式包装所有这些,但总是遇到 PInvokeStackImbalance
异常。
我知道调用 native 函数的唯一方法是在 .NET 函数声明上应用 CallingConvention = CallingConvention.Cdecl
)。然而,通过这种方式我无法读取输出参数(它始终为空字符串)并且返回值始终为真。
最佳答案
首先,我会调整您的原生函数的原型(prototype)。
因为这个函数有一个 C 接口(interface),你应该为 bool 值使用 C 类型,而不是像 bool
这样的 C++ 类型。您可能希望使用 Win32 的 BOOL
类型。
此外,就目前而言,您的函数很容易缓冲区溢出:最好添加另一个参数来指定目标result
字符串缓冲区的最大大小。
另请注意,导出纯 C 接口(interface)函数(如许多 Win32 API 函数)的 DLL 的广泛调用约定是__stdcall
(不是__cdecl
).我也会用它。
最后,由于前两个参数是输入 字符串,您可能希望使用const
来明确并强制执行const 正确性。
所以,我会像这样制作导出的 native 函数的原型(prototype):
extern "C" __declspec(dllexport)
BOOL __stdcall NativeFunction(
const char *in1,
const char *in2,
char *result,
int resultMaxSize);
然后,在 C# 端,您可以使用以下 P/Invoke:
[DllImport(
"NativeDll.dll",
CharSet = CharSet.Ansi,
CallingConvention = CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool NativeFunction(
string in1,
string in2,
StringBuilder result,
int resultMaxSize);
请注意,对于输出字符串,使用了 StringBuilder
。
另请注意,CharSet = CharSet.Ansi
用于将 C# 的 Unicode UTF-16 字符串编码为 ANSI(注意转换有损 - 如果你想要一个无损转换,也只需在 C++ 端使用 wchar_t*
字符串)。
我用一个简单的 C++ native DLL 做了一个测试:
// NativeDll.cpp
#include <string.h>
#include <windows.h>
extern "C" __declspec(dllexport)
BOOL __stdcall NativeFunction(
const char *in1,
const char *in2,
char *result,
int resultMaxSize)
{
// Parameter check
if (in1 == nullptr
|| in2 == nullptr
|| result == nullptr
|| resultMaxSize <= 0)
return FALSE;
// result = in1 + in2
strcpy_s(result, resultMaxSize, in1);
strcat_s(result, resultMaxSize, in2);
// All right
return TRUE;
}
它被以下 C# 控制台应用程序代码成功调用:
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace CSharpClient
{
class Program
{
[DllImport(
"NativeDll.dll",
CharSet = CharSet.Ansi,
CallingConvention = CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool NativeFunction(
string in1,
string in2,
StringBuilder result,
int resultMaxSize);
static void Main(string[] args)
{
var result = new StringBuilder(200);
if (! NativeFunction("Hello", " world!", result, result.Capacity))
{
Console.WriteLine("Error.");
return;
}
Console.WriteLine(result.ToString());
}
}
}
关于c# - 为 C# 包装 native DLL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14673049/