代码之家  ›  专栏  ›  技术社区  ›  Martin Delille

在C/C++中编写一个用于.NET互操作性的DLL

  •  12
  • Martin Delille  · 技术社区  · 14 年前

    在我的C应用程序中,我想用C编写代码的一部分。 我计划写一个可以与.NET互操作的dll开关。 我该怎么做?

    4 回复  |  直到 6 年前
        1
  •  20
  •   Ben Voigt Caesar    6 年前

    基本上有三种正确的方法:

    • 使用C++/CLI。如果此dll仅由.NET使用,这是最佳方法。
    • 使用“ extern "C" “兼容的API,就像Windows API本身一样。这是最可移植的,但是对于调用者来说并不像使用类模型来表示对象那样方便。
      • 这是最好的选择,如果你真的打算写在ANSI C(不是C++)。
      • 对于此路径,将函数编写为 extern "C" returntype __stdcall __declspec(dllexport) func(params) { ... }
      • 您还应该使用“调用者提供缓冲区”内存模型,而不是返回库中分配的缓冲区。在您确实需要为内部状态分配内存的情况下,调用者应该将其视为一个不透明的句柄,并且您应该为调用者提供访问函数来提取数据。在任何情况下,都不应期望调用者取消分配库中分配的内存,但是调用者可以要求库执行取消分配。
    • 使用COM或类似COM的API。这里返回(通常通过out参数)一个指向接口的指针,该接口是一个具有纯虚拟函数、无非虚拟函数和无数据的类。
      • 实现是在从这个抽象接口派生的具体类中实现的,它们可以拥有大量的数据和助手函数,因为这不会影响二进制接口。
      • 这在库中的工作要多得多,但是非常便携,而且便于消费者使用。

    有一件事绝对不能做:

    • 使用 __declspec(dllexport) 关于C++类。

    编辑:我也想解释一些选项2的好实践,它将最大化可移植性,并使原生C/C++组件也可以从非托管应用程序中使用。

    你可以用一个宏来简化这个过程,通常的方法是:

    在头文件中,所有函数声明看起来都像

    MYPROJECTAPI(returntype) PublicFunc(params);
    

    在您的项目中,定义是

    #define MYPROJECTAPI(returntype) \
                       extern "C" returntype __stdcall __declspec(dllexport)
    

    在消费项目中

    #define MYPROJECTAPI(returntype) \
                       extern "C" returntype __stdcall __declspec(dllimport)
    

    然后,您可以为其他编译器(如不使用GCC的编译器)不同地定义宏。 __declspec .

    完整的解决方案如下(在公共头文件中 myproject.h ):

    #if _WIN32
    #  if BUILDMYPROJECT
    #    define MYPROJECTAPI(returntype) \
             extern "C" returntype __stdcall __declspec(dllexport)
    #  else
    #    define MYPROJECTAPI(returntype) \
             extern "C" returntype __stdcall __declspec(dllimport)
    #  endif
    #else
    #  define MYPROJECTAPI(returntype) extern "C" returntype
    #endif
    

    然后你的VisualC++项目会引起 BUILDMYPROJECT 在生成myproject.dll时定义

        2
  •  4
  •   Heinzi    14 年前

    简而言之:

    (1)创建一个新的C++/CLI库项目。

    (2)写下你的代码。对于需要从C项目访问的类,请确保将其创建为clr类:

    public ref class R {/*...*/};       // CLR class
    public value class V {/*...*/};     // CLR struct
    public interface class I {/*...*/}; // CLR interface
    

    (3)编译项目并在您的C项目中添加对它的引用。

        3
  •  1
  •   Adi    14 年前
        4
  •  1
  •   dandan78 Tom Cool    14 年前

    下面是一个应用程序的示例,我必须这样做。在我的例子中,我需要一个dll来包装对仅在.lib中可用的函数的调用。关键部分是 extern "C" __declspec (dllexport) 在声明中。这基本上就是你所需要的。其余的只是使用 dllimport 在C应用程序中,使编组正确。

    extern "C" __declspec (dllexport) LONG EstablishContext(DWORD dwScope, 
                                                        LPCVOID pvReserved1, 
                                                        LPCVOID pvReserved2, 
                                                        LPSCARDCONTEXT phContext)
    {
        return SCardEstablishContext(dwScope, pvReserved1, pvReserved2, phContext);
    }