在我的C#应用程序中,我想在C中编写一部分代码。我计划编写一个可与.Net互操作的DLL。我怎样才能做到这一点?
基本上有三种正确的方法:
extern "C"
”兼容API,如Windows API本身。这是最便携的,但对于您的调用者而言,使用类模型来表示对象并不方便。
如果您真的打算用ANSI C(而不是C ++)编写,这是最好的选择。
对于此路径,您将函数编写为extern "C" returntype __stdcall __declspec(dllexport) func(params) { ... }
您还应该使用“caller-provide-the-buffer”内存模型,而不是返回库中分配的缓冲区。在您需要为内部状态分配内存的情况下,调用者应将其视为不透明句柄,并且应为调用者提供访问器函数以提取数据。在任何情况下都不应该要求调用者释放在库中分配的内存,但是调用者可以要求库进行重新分配。并且有一件事绝对不要做:
__declspec(dllexport)
。编辑:我还想解释选项#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
然后你的Visual C ++项目将导致在构建myproject.dll时定义BUILDMYPROJECT
简而言之:
(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#项目中添加对它的引用。
通过P / Invoke层。
下面是一个应用程序的示例,我必须这样做。在我的例子中,我需要一个DLL来包装对仅在.lib中可用的函数的调用。关键部分是宣言中的extern "C" __declspec (dllexport)
。这基本上就是你所需要的。其余的只是在C#应用程序中使用dllimport
并使编组正确。
extern "C" __declspec (dllexport) LONG EstablishContext(DWORD dwScope,
LPCVOID pvReserved1,
LPCVOID pvReserved2,
LPSCARDCONTEXT phContext)
{
return SCardEstablishContext(dwScope, pvReserved1, pvReserved2, phContext);
}