2012-02-15 98 views
1

我是一位经验丰富的软件工程师,但对C#来说有点新鲜。我有一个由C++对象组成的DLL,如图所示。我使用了这个C接口,因为我不确定是否存在从我的C#应用​​程序访问DLL中的C++入口点的方法。如何从DLL传递对象指针并传递给DLL?

__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的调用中都声明。我假设我没有正确处理对象的指针。有什么建议么?

+0

你是什么意思“代码断言”?你是否收到一些错误信息? – svick 2012-02-15 21:22:29

+0

是的,'检测到PInvokeStackImbalance'。 – 2012-02-15 21:28:59

+0

请记住,大多数编译器假定'extern“C”'函数不会抛出异常(尤其是如果C代码正在调用它们),所以您需要确保将'new Object()'位一个用于防止任何异常(特别是'std :: bad_alloc')转义的异常块。 – 2012-02-15 21:31:57

回答

3

最可能的问题是您的代码不使用正确的calling convention。在C++中,缺省值为__cdecl,但对于DllImport,缺省值为__stdcall

为了解决这个问题,specify the calling convention explicitly

[DllImport("MyDLL.dll", CallingConvention = CallingConvention.Cdecl)] 
+0

如果OP不知道,Visual Studio默认的调用约定是[编译器设置](http:// msdn.microsoft.com/en-us/library/46t77ak2.aspx)。它可以改为'__stdcall'以匹配默认的'[DllImport()]'约定。 – 2012-02-15 21:33:51

+0

看起来像这是问题,谢谢! – 2012-02-15 21:43:50

+1

@RobertKirnum,如果这个答案解决了你的问题,你应该[接受它](http://meta.stackexchange.com/a/5235/130186)。 – svick 2012-02-15 21:50:38

1

我的印象是,做这样的事情的最好方法是使用托管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/

看起来像希望的线索。

+1

如果你只需要调用一些非托管函数,PInvoke可能更容易。但是,C++/CLI肯定是一种选择。 – svick 2012-02-15 21:31:48

+0

的确如此,但这些非托管功能甚至存在的唯一原因是缺乏对C++/CLI的了解。如果有办法“做得对”,为什么不使用它。你真的会用一个叫做“void * Constructor”的函数吗? – Andrei 2012-02-15 21:50:40

+0

只要它没有公开地暴露给其余的C#代码,我就没有问题了。如果您了解C#,学习使用PInvoke比学习使用C++/CLI更容易。 – svick 2012-02-15 21:53:19