Error: Calling C++ dll function in C#

China☆狼群 提交于 2020-01-24 09:29:33

问题


I am trying to use functions in C++ dll from C#, but I got an error: "attempt to read or write protected memory. This is often indication that other memory is corrupt"

Anyone know how to fix ?

Here is C++ functions:

typedef void *DGNHandle;

 __declspec(dllexport) DGNHandle CPL_DLL    DGNOpen( const char *, int );
 __declspec(dllexport) DGNElemCore CPL_DLL *DGNReadElement( DGNHandle )

Here is structure in C++:

typedef struct {
    int         offset;
    int         size;

    int         element_id;     /*!< Element number (zero based) */
    int         stype;          /*!< Structure type: (DGNST_*) */
    int         level;          /*!< Element Level: 0-63 */
    int         type;           /*!< Element type (DGNT_) */
    int         complex;        /*!< Is element complex? */
    int         deleted;        /*!< Is element deleted? */

    int         graphic_group;  /*!< Graphic group number */
    int         properties;     /*!< Properties: ORing of DGNPF_ flags */
    int         color;          /*!< Color index (0-255) */
    int         weight;         /*!< Line Weight (0-31) */
    int         style;          /*!< Line Style: One of DGNS_* values */

    int         attr_bytes;     /*!< Bytes of attribute data, usually zero. */
    unsigned char *attr_data;   /*!< Raw attribute data */

    int         raw_bytes;      /*!< Bytes of raw data, usually zero. */
    unsigned char *raw_data;    /*!< All raw element data including header. */
} DGNElemCore; 

And below converted codes are in C#:

[StructLayout(LayoutKind.Sequential )]
    public class DGNElemCore
    {
        public int attr_bytes;
        public byte[] attr_data;
        public int color;
        public int complex;
        public int deleted;
        public int element_id;
        public int graphic_group;
        public int level;
        public int offset;
        public int properties;
        public int raw_bytes;
        public byte[] raw_data;
        public int size;
        public int style;
        public int stype;
        public int type;
        public int weight;

    }

[DllImport("DgnLib.dll", EntryPoint = "DGNOpen")]
        public static extern IntPtr  DGNOpen(string fileName, int bUpdate);
[DllImport("DgnLib.dll", EntryPoint = "DGNReadElement")]
        public static extern DGNElemCore DGNReadElement(IntPtr DGNHandle)

Codes for testing:

DGNElemCore element = new DGNElemCore();
element = DgnFile.DGNReadElement(dgnFile.oDgnFile) **//Throw error**

回答1:


Your declaration of DGNElemCore in your C# code is wrong - it needs to exactly match your C structure (especially in size) as otherwise the marshalling code will attempt to marshal memory incorrectly. An example definition which will work (as in not cause problems during marshalling) would be the following

[StructLayout(LayoutKind.Sequential )]
public class DGNElemCore
{
    int offset;
    int size;
    int element_id;
    int stype;
    int level;
    int type;
    int complex;
    int deleted;

    int graphic_group;
    int properties;
    int color;
    int weight;
    int style;

    int attr_bytes;
    IntPtr attr_data;

    int raw_bytes;
    IntPtr raw_data;
}

Note in particular

  • The order of members in the C# classes match those in the C struct (although this wont cause an error when calling your function it will give you incorrect values when accessing the members of the marshalled struct)
  • The char* fields are marshalled as IntPtrs - attempting to marshal pointers to arrays as arrays won't work by default as arrays are larger than pointers, resulting in the marshaller attempting to marshal more memory than is available.

Also I've noticed that your P/Invoke method declarations are wrong. The DGNOpen function returns the structure itself (not a pointer) and so should look more like the following.

public static extern DGNElemCore DGNOpen(string fileName, int bUpdate);

The DGNReadElement function accepts a struct (not a pointer) and returns a pointer to that strucut (not a struct) and so should look more like this

public static extern IntPtr DGNReadElement(DGNHandle handle);

Attributes can be used to change the way that the marshaller works, which can in turn be used to alter the signature of these methods, however if you do this you need to be careful to ensure that the marshalling will still match up to your C++ function declarations.




回答2:


The problem is that the #include headers might contain declarations that can be misinterpreted by the C++/CLI compilers. C function declarations for example. Best thing to do is to the tell the compiler explicitly about it.

#pragma managed(push, off)
#include "c_include.h"
#pragma managed(pop)

Then you can use C++ libraries from within C++/CLI application like you do with C++ apps. The only thing I always try to do is to wrap 3rd library behind Proxy or Facade design pattern, so that the client would always work with managed classes. This is especially important if your C++/CLI app is a library used by other .NET apps.

Moreover, normally public API classes (or functions) of your DLL should be exposed using following construction:

#ifdef YOUR_DLL_EXPORTS
#define YOUR_API __declspec(dllexport)
#else
#define YOUR_API __declspec(dllimport)
#endif 

class YOUR_API ClassToExpose {};

Hope this help



来源:https://stackoverflow.com/questions/13006580/error-calling-c-dll-function-in-c-sharp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!