外部 C/C++ 库未在 C# 中打印
External C/C++ library not printing in C#
我正在从 C# 调用 C++ 外部库。 Return 有效,但是 printf()
不在控制台 window 中打印数据。为什么会这样?我做错了什么吗?
即使我调用 DisplayHelloFromDLL
而没有将其 return 分配给变量 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();
}
}
我认为,您的问题是 DLL 没有分配给它的控制台 - 它不应该知道 C#-Console。也许,您可以尝试将对 C#-Console-Object 的引用传递给 "DisplayHelloFromDLL"-Function。
但我从未尝试过 - 我不知道如何从 C/C++ DLL Access/use C#-Console-Object。
您的 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 使用了错误的调用约定。您需要更改其中一项声明才能解决此问题。
并且将 return 类型声明为 string
意味着编组器将尝试通过调用 CoTaskMemFree
来释放 returned 指针。 C 字符串未分配 CoTaskMemAlloc
,因此这是未定义的行为。您应该将 return 类型声明为 IntPtr
并使用 Marshal.PtrToStringAnsi
获取字符串,记住 C++ 代码 return 是不应该(实际上不能)释放的文字。或者,使用其他各种方法之一来 return 一个字符串,在确定内存所有权的方式上可能更清晰一些。
我正在从 C# 调用 C++ 外部库。 Return 有效,但是 printf()
不在控制台 window 中打印数据。为什么会这样?我做错了什么吗?
即使我调用 DisplayHelloFromDLL
而没有将其 return 分配给变量 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();
}
}
我认为,您的问题是 DLL 没有分配给它的控制台 - 它不应该知道 C#-Console。也许,您可以尝试将对 C#-Console-Object 的引用传递给 "DisplayHelloFromDLL"-Function。 但我从未尝试过 - 我不知道如何从 C/C++ DLL Access/use C#-Console-Object。
您的 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 使用了错误的调用约定。您需要更改其中一项声明才能解决此问题。
并且将 return 类型声明为 string
意味着编组器将尝试通过调用 CoTaskMemFree
来释放 returned 指针。 C 字符串未分配 CoTaskMemAlloc
,因此这是未定义的行为。您应该将 return 类型声明为 IntPtr
并使用 Marshal.PtrToStringAnsi
获取字符串,记住 C++ 代码 return 是不应该(实际上不能)释放的文字。或者,使用其他各种方法之一来 return 一个字符串,在确定内存所有权的方式上可能更清晰一些。