如何在 DLL 之间传递对象指针?
Posted
技术标签:
【中文标题】如何在 DLL 之间传递对象指针?【英文标题】:How to pass an object pointer from and to a DLL? 【发布时间】:2012-02-15 21:09:14 【问题描述】:我是一位经验丰富的软件工程师,但对 C# 有点陌生。我有一个 DLL,它由具有 C 接口的 C++ 对象组成,如图所示。我使用这个 C 接口是因为我不确定是否有办法从我的 C# 应用程序访问 DLL 中的 C++ 入口点。
__declspec(dllexport) void *Constructor();
__declspec(dllexport) void Destructor(void *pObj);
__declspec(dllexport) int Method(void *pObj, char *pSrcDst, int len);
这是上面接口的C代码。
extern "C" void *Constructor()
return (void *)new Object;
extern "C" void Destructor(void *pObj)
delete (Object *)pObj;
extern "C" int Method(void *pObj, char *pSrcDst, int len)
if (!pObj) return 0;
return ((Object *)pObj)->Method(pSrcDst, len);
到目前为止一切顺利。现在,我需要能够从 C# 应用程序访问此接口。据我所知,我已经实现了以下 C# 接口。
unsafe public class Wrapper
[SuppressUnmanagedCodeSecurityAttribute()]
[DllImport("MyDLL.dll")]
public static extern
IntPtr Constructor();
[SuppressUnmanagedCodeSecurityAttribute()]
[DllImport("MyDLL.dll")]
public static extern
void Destructor(IntPtr pObj);
[SuppressUnmanagedCodeSecurityAttribute()]
[DllImport("MyDLL.dll")]
public static extern
int Method(IntPtr pObj, [In,Out] byte[] pSrcDst, int len);
这是使用上述接口的 C# 代码。
private IntPtr pObject;
public object()
pObject = Wrapper.Constructor();
~object()
Wrapper.Destructor(pObject);
public override byte[] method()
byte[] bytes = new byte[100];
int converted = Wrapper.Method(pObject, bytes, bytes.length);
return bytes;
代码在调用 Wrapper.Method 和 Wrapper.Destructor 时都断言。我假设我没有正确处理指向对象的指针。有什么建议吗?
【问题讨论】:
“代码断言”是什么意思?你收到一些错误信息吗? 是的,“检测到 PInvokeStackImbalance”。 请记住,大多数编译器假定extern "C"
函数不会引发异常(尤其是在 C 代码调用它们的情况下),因此您需要确保包装 new Object()
位在异常块中以防止任何异常(特别是std::bad_alloc
)转义。
旁注:您不需要为每个函数重复 extern "C"。您可以将它们全部包装在 extern "C" /*functions here*/ 的范围内
【参考方案1】:
最可能的问题是您的代码没有使用正确的calling convention。在 C++ 中默认为__cdecl
,但对于DllImport
,默认为__stdcall
。
要解决这个问题,specify the calling convention explicitly:
[DllImport("MyDLL.dll", CallingConvention = CallingConvention.Cdecl)]
【讨论】:
如果 OP 不知道,Visual Studio 中的默认调用约定是 compiler setting。可以改为__stdcall
,以匹配默认的[DllImport()]
约定。
@RobertKirnum,如果这个答案解决了你的问题,你应该accept it。【参考方案2】:
我的印象是,做这类事情的最佳方法是使用托管 c++/CLI 包装器。
Creating simple c++.net wrapper. Step-by-step
和
http://devmaster.net/forums/topic/7357-how-to-build-a-net-wrapper-for-a-c-library/
看起来很有希望。
【讨论】:
如果你只需要调用几个非托管函数,PInvoke 可能更容易。但是,是的,C++/CLI 肯定是一个替代方案。 没错,但那些少数非托管函数甚至存在的唯一原因是缺乏 C++/CLI 知识。如果有办法“做对”,为什么不使用它。你真的愿意使用一个名为“void * Constructor”的函数吗? 只要它没有公开暴露给其余的 C# 代码,我对此没有任何问题。如果您了解 C#,那么学习使用 PInvoke 比学习使用 C++/CLI 容易得多。以上是关于如何在 DLL 之间传递对象指针?的主要内容,如果未能解决你的问题,请参考以下文章
Python 和 ctypes:如何正确地将“指针对指针”传递给 DLL?
如何将 Stucture 的地址传递给 C# 中的 Void 指针 [void*] 到 VC++ Dll