【问题标题】:How do you export a method in a CIL DLL so that a native program can call it?如何在 CIL DLL 中导出方法以便本地程序可以调用它?
【发布时间】:2012-01-22 00:25:01
【问题描述】:

我已经查看了 ECMA 335,但我只找到了对 .export 关键字的引用,这似乎很有希望,但文档很少。我在 StackOverflow 上发现了关于在 C# 中执行此操作的类似问题。然而,到目前为止,这些都没有让我有任何用处。

底线是:我有一个 CIL DLL,我想从本机 C++ 应用程序调用它的一些静态方法。

【问题讨论】:

    标签: .net pinvoke cil


    【解决方案1】:

    在较新版本的 ILAsm 中,您只需执行以下操作:

    .method public static void Foo ()
    {
        .export [1]
    
        // code ...
    }
    

    这会在导出表中的索引 1 处导出 Foo。导出序号应该是唯一且连续的。

    在旧版本中,您必须这样做:

    .data vt = int32 (0) [n]
    .vtfixup [n] int32 fromunmanaged at vt
    
    .method public static void Foo ()
    {
        .vtentry 1:1
        .export [1]
    
        // code ...
    }
    

    (其中“n”是您想要的导出数量。)

    .vtentry 表示将方法存储在哪个 vtable:slot 中。(表 ID 是连续的,因此取决于声明顺序。)

    如果您不将导出表用于其他任何事情,较新的 ILAsms 会为您完成所有这些工作。

    请注意,所有这些都非常不便携。

    【讨论】:

      【解决方案2】:

      您必须将您的 dll 公开为 com dll。 Com 完成了本地到 .net 互操作的工作。除了 .net VM,你不能在任何地方运行 IL 代码。

      【讨论】:

      • 正如 Zor 的解决方案所示,没有 COM 的疯狂也是可能的。
      • 如果我错了,请纠正我,但 ilasm 仍然会生成一个 PE MSIL 文件,仍然不适合从本机应用程序调用。你仍然需要一个 .net VM 来执行代码。
      • 即使通过 COM 调用,托管代码也无法在没有 VM 的情况下神奇地运行。我的解决方案只是导出托管方法,这样,当从本机代码调用它们时,.NET VM 会介入并执行托管代码,然后返回到本机代码。
      【解决方案3】:

      到目前为止,根据我的实验,仅当方法没有任何参数时,仅添加 .export [n] 而没有任何其他垃圾就足够了。我从一个小型函数库开始,比如

      [DllExport]
      public static double fooz(double arg) {
          return arg + 42;
      }
      
      [DllExport]
      public static int foo0(int arg) {
          return arg + 42;
      }
      
      [DllExport]
      public static ulong foo1(ulong arg) {
          return arg + 42;
      }
      

      只用.export 就看到我的函数没有崩溃,而是忽略了它们的参数。

      看看 Robert Giesecke 的 UnmanagedExports 的使用,它在 Visual Studio 中以 Nuget 包的形式提供。我发现它相当有气质和微妙,除非我从一开始就正确配置,有时它不会构建调试或将其放置在发布等中。其他人还有其他迭代加上一些进一步的开发,从 Nuget 菜单中都可以看到。我从最简单的开始,用VS2015、VS2017、VS2019试了一下。当您有一个 DLL 时,您可以使用 IL 反汇编程序更仔细地检查它,ildasm.

      首先将它编译为普通的 C# DLL,不要 [DllExport],请务必相应地设置解决方案配置(调试,x64)。然后使用 ildasm 进入并查看引擎盖下的内容。从小事做起。

      下一步是再次尝试使用 [DllExport] 并查看进行了哪些更改。我使用了 WinMerge。必须准确了解此工具的作用,而不是盲目地使用它并期望一切都能自动运行。

      至于函数参数,为了测试,我坚持用最简单的方法,先用 VBA 测试 DLL。

      Declare PtrSafe Function fooz Lib "C:\Users\bill\source\repos\Test3\bin\x86\Debug\Test3.dll" (ByVal arg As Double) As Double
      

      由于我的 Excel 只有 32 位,配套的 DLL 必须具有相同的位数,因此是 x86。

      如果您有任何复杂的参数和结果(byte[] 及以上),您将需要使用某种我尚未完全掌握的编组。想想 JSON 或 MsgPack 或其中之一的字节数组。

      下一步是看看这是否适用于 Linux 下的 .Net Core。

      最后,我不会用 39.5 英尺 (12.04m) 的杆子接触 COM,主要是为了避免供应商 schlock。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多