使用 C# 中的 LPStr return 值调用 C++ 函数
Calling C++ function with LPStr return value from C#
我有一个 64 位的 C++ dll,其中包含 return 一个 LPStr
的函数。我想在 C# 中调用这个函数。函数声明如下所示:
__declspec(dllexport) LPSTR __stdcall function(int16_t error_code);
在我的 C# 代码中,我尝试了以下操作:
[DllImport(@"<PathToInterface.dll>", EntryPoint = "function")]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern string function(Int16 error_code);
然后在程序中:
string ErrorMessage = "";
ErrorMessage = function(-10210);
我知道函数本身很好,因为我可以从另一个程序(用 LabVIEW FWIW 编写)调用它。但是当我执行 C# 程序时,它只是退出并显示错误代码 0x80000003
,我什至无法尝试,捕获异常。
如何正确调用这个函数?
作为侧节点:我在这个 dll 中还有其他函数,它们使用 LPStr
作为参数,我可以毫无问题地调用它们。 return LPStr
出问题的只有两个函数
如何正确调用这个函数?
作为互操作?你不能...它在纯 C++ 中也容易出错
你应该像
那样做
extern "C" __declspec(dllexport) int __stdcall function(int16_t error_code,
LPSTR buffer, size_t size)
{
LPCSTR format = "error: %i";
size_t req = _scprintf(format, error_code); // check for require size
if (req > size) //buffer size is too small
{
return req; //return required size
}
sprintf_s(buffer, size, format, error_code); //fill buffer
return 0;
}
和用法
class Program
{
static void Main(string[] args)
{
short error_code = -10210;
var ret = function(error_code, null, 0); // check for required size of the buffer
var sb = new StringBuilder(ret); // create large enough buffer
ret = function(error_code, sb, (uint)sb.Capacity + 1); //call again
var error_desc = sb.ToString(); //get results
Console.WriteLine(error_desc);
Console.ReadKey();
}
[DllImport("TestDll.dll", EntryPoint = "function", CharSet = CharSet.Ansi)]
public static extern int function(short error_code, StringBuilder sb, int size);
}
在 C++ 中的用法
typedef int (__stdcall *function)(int16_t error_code, LPSTR buffer, size_t size);
int main()
{
auto handle = LoadLibrary(L"TestDll.dll");
auto proc = (function)GetProcAddress(handle, "_function@12");
// of course it can be done via linking
int16_t error_code = 333;
const int ret = proc(error_code, NULL, 0); // check for size
CHAR* buffer = new CHAR[ret + 1];
//CHAR buffer[200]; //eventually allocate on stack
//but size have to be constant value and may be too small
proc(error_code, buffer, ret+1); // call again
MessageBoxA(0, buffer, "Return", 0); //show result
delete[] buffer; //free buffer!
FreeLibrary(handle);
return 0;
}
我有一个 64 位的 C++ dll,其中包含 return 一个 LPStr
的函数。我想在 C# 中调用这个函数。函数声明如下所示:
__declspec(dllexport) LPSTR __stdcall function(int16_t error_code);
在我的 C# 代码中,我尝试了以下操作:
[DllImport(@"<PathToInterface.dll>", EntryPoint = "function")]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern string function(Int16 error_code);
然后在程序中:
string ErrorMessage = "";
ErrorMessage = function(-10210);
我知道函数本身很好,因为我可以从另一个程序(用 LabVIEW FWIW 编写)调用它。但是当我执行 C# 程序时,它只是退出并显示错误代码 0x80000003
,我什至无法尝试,捕获异常。
如何正确调用这个函数?
作为侧节点:我在这个 dll 中还有其他函数,它们使用 LPStr
作为参数,我可以毫无问题地调用它们。 return LPStr
出问题的只有两个函数
如何正确调用这个函数?
作为互操作?你不能...它在纯 C++ 中也容易出错
你应该像
那样做extern "C" __declspec(dllexport) int __stdcall function(int16_t error_code,
LPSTR buffer, size_t size)
{
LPCSTR format = "error: %i";
size_t req = _scprintf(format, error_code); // check for require size
if (req > size) //buffer size is too small
{
return req; //return required size
}
sprintf_s(buffer, size, format, error_code); //fill buffer
return 0;
}
和用法
class Program
{
static void Main(string[] args)
{
short error_code = -10210;
var ret = function(error_code, null, 0); // check for required size of the buffer
var sb = new StringBuilder(ret); // create large enough buffer
ret = function(error_code, sb, (uint)sb.Capacity + 1); //call again
var error_desc = sb.ToString(); //get results
Console.WriteLine(error_desc);
Console.ReadKey();
}
[DllImport("TestDll.dll", EntryPoint = "function", CharSet = CharSet.Ansi)]
public static extern int function(short error_code, StringBuilder sb, int size);
}
在 C++ 中的用法
typedef int (__stdcall *function)(int16_t error_code, LPSTR buffer, size_t size);
int main()
{
auto handle = LoadLibrary(L"TestDll.dll");
auto proc = (function)GetProcAddress(handle, "_function@12");
// of course it can be done via linking
int16_t error_code = 333;
const int ret = proc(error_code, NULL, 0); // check for size
CHAR* buffer = new CHAR[ret + 1];
//CHAR buffer[200]; //eventually allocate on stack
//but size have to be constant value and may be too small
proc(error_code, buffer, ret+1); // call again
MessageBoxA(0, buffer, "Return", 0); //show result
delete[] buffer; //free buffer!
FreeLibrary(handle);
return 0;
}