我有一个C ++控制台Exe,它可以进行一些编程。现在我想编写一个C#GUI来完成C ++ exe所做的一些编程。我想的方法很少,
答案 0 :(得分:7)
构建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)); }
答案 1 :(得分:3)
所以你只想从托管的.net代码调用c ++库?
然后你需要在c ++中构建一个COM对象或一个p-invokable库。每种方法都有自己的优点和缺点,具体取决于您的业务需求。您必须在消费者中编组数据。这两个概念都有大量的材料。
答案 2 :(得分:0)
答案 3 :(得分:0)
您可以编写一个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);
}
}
答案 4 :(得分:0)
请参阅the first comment in this page重定向stderr
答案 5 :(得分:0)
可能最好的方法是使用P / Invoke或Platform Invoke。根据结构或C ++ DLL接口,您可能希望将其包装在纯C接口中;如果您的界面仅使用blittable类型,则最简单。如果将dll接口限制为blittable类型(Int32,Single,Boolean,Int32 [],Single [],Double [] - 基础),则无需在托管>之间进行任何复杂的数据封送处理em>(C#)和非托管(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接口是一个很好的策略。这将使您的语言互操作代码保持最清晰。
祝你好运,保