外部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();
    }
}

外部C/C++库未在C#中打印

根据此线程(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