外部C/C++库未在C#中打印
本文关键字:打印 C++ 外部 | 更新日期: 2023-09-27 17:58:12
我正在从C#调用一个C++外部库。返回有效,但是printf()
不会在控制台窗口中打印数据。为什么会发生这种情况?我做错什么了吗?
即使我调用DisplayHelloFromDLL
而不将其返回值分配给变量x,打印的文本也不会显示在屏幕上。
C++:
#include <stdio.h>
extern "C"
{
__declspec(dllexport) char * DisplayHelloFromDLL()
{
printf ("Hello from DLL !'n");
return "Something";
}
}
C#:
using System;
using System.Runtime.InteropServices;
class HelloWorld
{
[DllImport("Hello.dll", EntryPoint = "DisplayHelloFromDLL")]
public static extern string DisplayHelloFromDLL();
static void Main()
{
Console.WriteLine("This is C# program");
string x = DisplayHelloFromDLL();
Console.WriteLine(x);
Console.ReadKey();
}
}
根据此线程(https://social.msdn.microsoft.com/Forums/en-US/5da6cdb2-bc2b-4fff-8adf-752b32143dae/printf-from-dll-in-console-app-in-visual-studio-c-2010-express-does-not-output-to-console-window?forum=Vsexpressvcs)调试时存在的Visual Studio宿主进程是DLL的控制台输出无法进入控制台的原因。
检查这一点的一个简单方法是直接运行可执行文件,而不是通过IDE的调试器。如果这确实证实了这一点,那么如果你愿意,你可以禁用托管进程,如链接线程中所述。
您的代码还有两个问题:
[DllImport("Hello.dll", EntryPoint = "DisplayHelloFromDLL")]
public static extern string DisplayHelloFromDLL();
默认的p/invoke调用约定是stdcall
,但默认的C++调用约定是cdecl
。因此,您的C#p/invoke使用了错误的调用约定。您需要更改其中一个声明来解决此问题。
将返回类型声明为string
意味着编组器将尝试通过调用CoTaskMemFree
来释放返回的指针。C字符串未分配CoTaskMemAlloc
,因此这是未定义的行为。您应该将返回类型声明为IntPtr
,并使用Marshal.PtrToStringAnsi
来获取字符串,记住C++代码返回的文本不应该(实际上不能)被释放。或者,使用其他各种方法中的一种来返回字符串,这些方法在确定内存所有权的方式上可能更清晰一些。
我认为,您的问题是DLL没有分配控制台-它不应该知道C#控制台。也许,您可以尝试将对C#控制台对象的引用传递给"DisplayHelloFromDLL"-函数。但我从未尝试过——我不知道如何从C/C++DLL访问/使用C#控制台对象。
您的C外部库可能无法访问任何输出控制台。您可以使用以下函数写入输出控制台。
AllocConsole
GetSTDTHandle
WriteConsole