通过 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 应用程序。重定向clogcerr 只需要在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):访问冲突读取位置

如何将 C++ windows dll 合并到 C# 应用程序 exe 中?

C++。将.dll文件链接到项目[重复]

创建 DLL 的编程语言:C++ 或 C#

执行用 C++ 编写的 .exe 的问题(使用 mingw 编译器)