8

この話題がここで何度も議論されたことは知っていますが、私の特定の状況に対する答えを見つけることができませんでした.

C# で、構造体オブジェクトのポインターを受け取るアンマネージ C メソッドを呼び出す必要があります (私は C を流暢に話せません:

int doStuff(MYGRID* grid, int x);

しかし、構造体自体は他の構造体オブジェクトを参照しています:

struct MYGRID {

    int hgap;
    int vgap;

    MYIMAGE* image;

}

struct MYIMAGE {

    int res;
    int width;
    int height;

}

また、次のようにイメージ ポインターを直接設定する必要もあります。

MYGRID* pGrid = new MYGRID;
MYIMAGE* pImage = new MYIMAGE;
pGrid->image = pImage;

だから、私の質問は: C# コードでは、P/Invoke Interop Assistant が提案するように、「構造体」オブジェクトを使用して「ref」で渡す必要がありますか? つまり、次のコードを意味します。

MyGrid myGrid = new MyGrid();
MyImage myImage = new MyImage();

myGrid.image = Marshal.AllocHGlobal(Marshal.SizeOf(image)); // A IntPtr in my struct
myGrid.image = Marshal.StructureToPtr(image, myGrid.image, false);

doStuff(ref myGrid, 0);

または、非常に単純な次のコードを作成するために、「構造体」の代わりに「クラス」を使用できますか。

MyGrid myGrid = new MyGrid();
MyImage myImage = new MyImage();

myGrid.image = myImage;

doStuff(myGrid, 0);

最初のケースでは、構造体 MyGrid で "IntPtr" を使用し、2 番目のケースでは MyImage オブジェクトのみを使用します。

4

3 に答える 3

8

C# 構造体と C++ 構造体を混同しないでください。それらは同じものではありません。AC# 構造体は、値の型を宣言するために使用されます。値の型を別の型に集約する場合、ヒープに格納されたインスタンスへの参照を格納する代わりに、それを含むインスタンスに直接格納します。C++ 構造体は、デフォルトですべてのメンバーが public である単純なクラスです。

あなたの場合、MYGRIDへのポインターが含まれているため、 2番目の例で行っているようにMYIMAGE使用する必要があります。classただし、refパラメーターmyGridの は削除する必要があります。

以下は、私がテストしたサンプルコードです。C++ コード:

#include "windows.h"

struct MYIMAGE {

  int res;
  int width;
  int height;

};

struct MYGRID {

  int hgap;
  int vgap;

  MYIMAGE* image;

};

extern "C" __declspec(dllexport) int doStuff(MYGRID* grid, int x) {
  return 0;
}

C# クラスと外部関数を宣言します。

[StructLayout(LayoutKind.Sequential)]
class MyGrid {

  public int hgap;
  public int vgap;

  public IntPtr image;

}

[StructLayout(LayoutKind.Sequential)]
class MyImage {

  public int res;
  public int width;
  public int height;

}

[DllImport("MyDll")]
static extern int doStuff(MyGrid grid, int x);

外部関数の呼び出し:

MyImage image = new MyImage();

MyGrid grid = new MyGrid();
grid.image = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(MyImage)));
Marshal.StructureToPtr(image, grid.image, false);

doStuff(grid, 0);

C# プロジェクトでアンマネージ デバッグを有効にすると、デバッガーを使用して C++ 関数にステップ インし、クラスが正しくマーシャリングされていることを確認できます。

于 2013-01-14T10:26:26.983 に答える
0

以下は私のテストコードです。参考にしてください。

c# コード - 構造体

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
struct Items
{
    public double item1;
    public double item2;
}

c# コード - 呼び出し元クラス

class ItemManager
{
    [DllImport("CppLibrary.dll")]
    private static extern double Sum_(ref Items items);

    public static double Sum(Items items)
    {
        return Sum_(ref items);
    }
}

c++ cpp

double ItemManager::Sum(Items items)
{
    return items.item1 + items.item2;
}

c++ ヘッダー

class Items
{
public:
    double item1;
    double item2;
};

class ItemManager
{
public:
    static double Sum(Items items);
};

extern "C" __declspec(dllexport) 
    double Sum_(Items * items)
{
    return ItemManager::Sum( * items);
}
于 2014-06-19T07:09:22.727 に答える
-1

いいえ、MyImage がクラスの場合、MyGrid.image はマネージド参照であり、ポインターとは異なります。

于 2013-01-14T09:58:55.700 に答える