3

C# から C++ dll の関数を使用しようとしていますが、「保護されたメモリを読み書きしようとしています。これは多くの場合、他のメモリが破損していることを示しています」というエラーが表示されました。

誰でも修正方法を知っていますか?

C++ 関数は次のとおりです。

typedef void *DGNHandle;

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

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; 

以下の変換されたコードは 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)

テスト用のコード:

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

2 に答える 2

3

C# コードでの宣言DGNElemCoreが間違っています。C 構造体 (特にサイズ) と正確に一致する必要があります。そうしないと、マーシャリング コードがメモリを正しくマーシャリングしようとします。(マーシャリング中に問題が発生しないように) 機能する定義の例は次のとおりです。

[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;
}

特に注意

  • C# クラスのメンバーの順序は、C 構造体のメンバーの順序と一致します (ただし、関数を呼び出すときにエラーが発生することはありませんが、マーシャリングされた構造体のメンバーにアクセスするときに誤った値が返されます)。
  • char*フィールドは s としてマーシャリングされますIntPtr- 配列として配列へのポインタをマーシャリングしようとすると、配列はポインタよりも大きいため、デフォルトでは機能しません。その結果、マーシャラーは利用可能なメモリよりも多くのメモリをマーシャリングしようとします。

また、あなたの P/Invoke メソッドの宣言が間違っていることに気付きました。このDGNOpen関数は (ポインターではなく) 構造体自体を返すため、次のようになります。

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

関数は構造体 (ポインターではない) を受け入れ、そのDGNReadElement構造体 (構造体ではない) へのポインターを返すため、次のようになります。

public static extern IntPtr DGNReadElement(DGNHandle handle);

属性は、マーシャラーの動作方法を変更するために使用できます。これは、これらのメソッドのシグネチャを変更するために使用できます。ただし、これを行う場合、マーシャリングが C++ 関数と一致するように注意する必要があります。宣言。

于 2012-10-22T11:00:12.160 に答える
2

問題は、#include ヘッダーに、C++/CLI コンパイラによって誤って解釈される可能性のある宣言が含まれている可能性があることです。たとえば、C 関数宣言。最善の方法は、コンパイラに明示的に伝えることです。

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

その後、C++ アプリの場合と同様に、C++/CLI アプリケーション内から C++ ライブラリを使用できます。私がいつもやろうとしている唯一のことは、クライアントが常にマネージ クラスで動作するように、Proxy または Facade デザイン パターンの背後にある 3 番目のライブラリをラップすることです。これは、C++/CLI アプリが他の .NET アプリで使用されるライブラリである場合に特に重要です。

さらに、通常、DLL のパブリック API クラス (または関数) は、次の構成を使用して公開する必要があります。

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

class YOUR_API ClassToExpose {};

この助けを願っています

于 2012-10-22T07:36:52.820 に答える