通过 C++ dll 或 C++ exe 编写 C# GUI
Posted
技术标签:
【中文标题】通过 C++ dll 或 C++ exe 编写 C# GUI【英文标题】:Writing C# GUI over a C++ dll or C++ exe 【发布时间】:2011-01-14 04:10:25 【问题描述】:我有一个 C++ 控制台 Exe,它可以进行一些编程。现在我想编写一个 C# GUI,它执行 C++ exe 所做的一些编程。我正在考虑几种方法,
-
编写 C# GUI 并从头开始使用 C++ 进行所有编程。(我不想这样做,因为它需要大量的返工)
构建一个 C++ dll 进行编程并将其导入 GUI 应用程序。(现在我有一个问题。如何在 c++ dll 中捕获例程的输出并在 GUI 中显示它?我应该返回输出作为应用程序调用的每个例程的字符串。?因为我不知道托管 C++ 我要构建一个非托管 C++ dll。)
【问题讨论】:
你考虑过添加COM接口吗?因为,恕我直言,使用 COM 容器传递参数和程序数据可能是解决方案。 【参考方案1】:构建 C++/CLI dll 真的没有那么难。您基本上使用非托管 C++ 代码,只是您定义了一个“public ref class
”,它承载您希望 C# 代码看到的函数。
您要返回什么样的数据?单个数字、数字矩阵、复杂对象?
更新:由于已明确“输出”是 iostreams,here is a project 演示了将cout
重定向到调用该库的 .NET 应用程序。重定向clog
或cerr
只需要在DllMain
中按照现有重定向的模式添加一些额外的行。
The zip file 包含 VS2010 项目文件,但源代码应该也可以在 2005 或 2008 年使用。
iostreams 捕获功能包含在以下代码中:
// compile this part without /clr
class capturebuf : public std::stringbuf
protected:
virtual int sync()
// ensure NUL termination
overflow(0);
// send to .NET trace listeners
loghelper(pbase());
// clear buffer
str(std::string());
return __super::sync();
;
BOOL WINAPI DllMain(_In_ HANDLE _HDllHandle, _In_ DWORD _Reason, _In_opt_ LPVOID _Reserved)
static std::streambuf* origbuf;
static capturebuf* altbuf;
switch (_Reason)
case DLL_PROCESS_ATTACH:
origbuf = std::cout.rdbuf();
std::cout.rdbuf(altbuf = new capturebuf());
break;
case DLL_PROCESS_DETACH:
std::cout.rdbuf(origbuf);
delete altbuf;
break;
return TRUE;
// compile this helper function with /clr
void loghelper(char* msg) Trace::Write(gcnew System::String(msg));
【讨论】:
我想在 C# GUI 中显示来自 C++ DLL 的日志消息。 @user97642:所以 C++ DLL 正在写入std::clog
,您想将此输出发送到 C#?
@user97642:好的,这些设计非常灵活。我有一些 cout-interception 代码,我可以重新编写以将流发送到 .NET,但这需要一点时间,而且现在已经过了午夜,所以我现在不能这样做。【参考方案2】:
所以你只想从托管的 .net 代码中调用 c++ 库?
然后您需要在 c++ 中构建 COM 对象或 p-invokable 库。根据您的业务需求,每种方法都有自己的优缺点。您必须在您的消费者中编组数据。这两个概念都有大量的材料。
【讨论】:
【参考方案3】:可能相关:Possible to call C++ code from C#?
【讨论】:
【参考方案4】:您可以只编写一个 C# GUI 包装器(如您在选项 2 中建议的那样)并生成 C++ 进程;但是,这会有点慢(我不知道这是否重要)。
要运行您的 C++ exe 并捕获输出,您可以使用我放在一起的 ProcessRunner。下面是基本用法:
using CSharpTest.Net.Processes;
partial class Program
static int Main(string[] args)
ProcessRunner run = new ProcessRunner("svn.exe", "update");
run.OutputReceived += new ProcessOutputEventHandler(run_OutputReceived);
return run.Run();
static void run_OutputReceived(object sender, ProcessOutputEventArgs args)
Console.WriteLine("0: 1", args.Error ? "Error" : "Output", args.Data);
【讨论】:
我正在寻找一种方法来找出第二个选项。使用 C++ DLL 的 C# GUI。【参考方案5】:参见the first comment in this page 重定向标准错误
【讨论】:
【参考方案6】:可能最好的方法是使用 P/Invoke 或 Platform Invoke。根据结构或您的 C++ dll 接口,您可能希望将其包装在纯 C 接口中;如果你的界面只使用blittable 类型,那是最简单的。如果您将 dll 接口限制为 blittable 类型(Int32、Single、Boolean、Int32[]、Single[]、Double[] - 基础),您将不需要在 managed 之间进行任何复杂的数据封送处理em> (C#) 和 unmanaged (C) 内存空间。
例如,在您的 c# 代码中,您可以使用 DllImport 属性在 C/C++ dll 中定义可用的调用。
[DllImport, "ExactDllName.dll"]
static extern boolean OneOfMyCoolCRoutines([In] Double[] x, [In] Double[] y, [Out] Double result)
小 [In] 和 [Out] 不是严格要求的,但它们可以加快速度。现在已经添加了“ExactDllName.dll”作为对 C# 项目的引用,您可以从 C# 代码中调用 C/C++ 函数。
fixed(Double *x = &x[0], *y = &y[0] )
Boolean returnValue = OneOfMyCoolCRoutines(x, y, r);
请注意,我实际上是在我的 dll 和 C# 代码之间来回传递指针。这可能会导致内存错误,因为这些数组的位置可能会被 CLR 垃圾收集器更改,但 C/C++ dll 对此一无所知。所以为了防止这种情况,我只是在我的 C# 中修复了这些指针,现在当我的 dll 对这些数组进行操作时,它们不会在内存中移动。现在这是不安全的代码,我需要使用该标志编译我的 C# 代码。
语言互操作有很多细节,但这应该会让您大开眼界。如果可能的话,坚持使用 blittable 类型的无状态 C 接口是一个很好的策略。这将使您的语言互操作代码保持最干净。
祝你好运,
保罗
【讨论】:
以上是关于通过 C++ dll 或 C++ exe 编写 C# GUI的主要内容,如果未能解决你的问题,请参考以下文章
怎么查看用C++ builder编写的程序都调用了哪些dll文件,谢谢!
Project2.exe中的C++ OpenCV“找不到或打开PDB文件”和“(opencv_world310.dll):访问冲突读取位置