【问题标题】:Calling C code from managed code从托管代码调用 C 代码
【发布时间】:2011-04-29 11:17:12
【问题描述】:

我目前有一个想在 .NET (C#) 中使用的 C 函数。

我可以看到两种实现方式:

  1. 在 VC++.NET 上使用 /clr 编译它(我认为这是可能的),实现了调用 C 代码的“外观”托管方法。

  2. 将 C 代码编译为 DLL,然后进行 API 调用。

你觉得什么最好?第一个怎么做?

更新

根据要求,这是我需要从托管代码调用的(唯一)函数:

int new_game(double* params1, double* params2);

再问一个问题(虽然更难)

我有一个表单的功能

int my_hard_to_interop_function(double** input, double **output, int width);

输入和输出都是二维双精度数组。它们的宽度由width 给出,它们的高度由函数已知。我应该从我的 C# 应用程序中调用这个 C 方法。

【问题讨论】:

    标签: c# c++-cli interop pinvoke


    【解决方案1】:

    由于无论如何您都需要将 C 函数部署在与主 C# 程序不同的 DLL 中,因此使用 C++/CLI 是迄今为止最简单的。

    你有 C 函数的源代码吗?如果是这样,您也许可以轻松地将它们转换为ref class 的静态成员函数。然后您可以使用/clr:safe 选项并拥有纯托管代码。

    如果您没有源代码,或者本机代码无法轻松运行(例如,使用大量 C 运行时库函数),那么您可以构建您所称的包装器或外观。托管包装器和本机 C 代码最终将一起在 DLL 中,这使部署更容易,因为不涉及本机 DLL 搜索路径。

    【讨论】:

      【解决方案2】:

      如果这是一个简单的 C API,那么最直接的访问方法是使用 PInvoke。 PInvoke 正是为这种情况而设计的。

      您可以发布 C 方法的签名吗?如果是这样,我们可以提供适当的托管签名。

      编辑

      [DllImport("insert_the_dll_name_here")]
      public static extern int new_game(ref double param1, ref double param2);
      

      正如 Hans 指出的那样,考虑到参数的复数名称,这些参数似乎可能是数组与单个值。如果是这样,则需要更改签名以解决此问题。例如,如果预计它们是预定的固定大小,则签名将如下所示

      [DllImportAttribute("insert_the_dll_name_here"]
      public static extern int M1(
        [MarshalAsAttribute(UnmanagedType.LPArray, ArraySubType=UnmanagedType.R8, SizeConst=5)] 
        double[] params1),
        [MarshalAsAttribute(UnmanagedType.LPArray, ArraySubType=UnmanagedType.R8, SizeConst=5)] 
        double[] params2) ;
      

      【讨论】:

      • 我的钱花在了这些参数是数组上。注意 OP 中的复数形式。
      • @Hans,这是一个很好的观点,但是没有相应长度参数的数组似乎很奇怪。也许他们应该有一个固定的价值。我会更新我的答案以要求澄清。
      【解决方案3】:

      正如 JaredPar 所说,这是最简单的方法 - 确实是设计好的方法。

      具体来说,您需要选项 2,并且 .dll 需要可从您的可执行文件中访问(路径方式)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-12-29
        • 2013-08-24
        • 1970-01-01
        • 2010-09-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多