DOBON.NET DOBON.NETプログラミング掲示板過去ログ

C# VC++ DLL間のマーシャル

環境/言語:[C#2008 VC++2008]
分類:[.NET]

お世話になっております。
C#とVC++で作成したDLL間でデータを渡したいんですが

ネスティングされた構造体へのデータのやり取りがうまくいきません。
ご教授お願いします。

----------------------------------------------
C#側サンプル

using System;
using System.Runtime.InteropServices;

namespace @struct
{
    class Program
    {
        [StructLayout(LayoutKind.Sequential)]
        public struct ST1
        {
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
            public string name1;
            public int flg1;

            [StructLayout(LayoutKind.Sequential)]
            public struct ST3
            {
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
                public string name3;
                public int flg3;

                [StructLayout(LayoutKind.Sequential)]
                public struct ST2
                {
                    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
                    public string name2;
                    public int flg2;
                }//ST2
            }//ST3
        }//ST1


        //---------------------------------------------------------------------------
        // DllImport属性
        [System.Runtime.InteropServices.DllImport("dllStruct.dll")]

        private static extern void dllStruct(ref ST1.ST3 st1);

        //---------------------------------------------------------------------------
        // main
        static void Main(string[] args)
        {
            string msg = string.Empty;

            ST1 st1 = new ST1();
            ST1.ST3 st3 = new ST1.ST3();
            ST1.ST3.ST2 st2 = new ST1.ST3.ST2(); 
                
            dllStruct(ref st2);

            msg = "st1: " + st1.flg1 + " " + st1.name1;
            Console.WriteLine(msg);

            msg = "st2: " + st2.flg2 + " " + st2.name2;
            Console.WriteLine(msg);

            msg = "st3: " + st3.flg3 + " " + st3.name3;
            Console.WriteLine(msg);

        }
    }
}


----------------------------------------------
VC++側サンプル

#include <windows.h>
#include <stdio.h>

//---------------------------------------------------------------------------
//構造体
//---------------------------------------------------------------------------
typedef struct _ST2{

    char name2[1024];
    int flg2;

}_ST2;

typedef struct _ST3{

    char name3[1024];
    int flg3;
    _ST2 pat_st2;

}_ST3;

typedef struct _ST1
{
    char    name1[1024];
    int     flg;
    _ST3 pat_st3;

}_ST1;

typedef struct _ST1*  ST1;
typedef struct _ST2*  ST2;
typedef struct _ST3*  ST3;

//---------------------------------------------------------------------------
//プロトタイプ宣言
//---------------------------------------------------------------------------
#ifdef  __cplusplus
extern "C"
{
#endif  /*  __cplusplus */
void __declspec(dllexport) __stdcall dllStruct( ST1 st1) ;
#ifdef  __cplusplus
}
#endif  /*  __cplusplus */

//---------------------------------------------------------------------------
//エントリーポイント
//---------------------------------------------------------------------------
BOOL WINAPI DllMain( HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved )
{
    return TRUE;
}


//---------------------------------------------------------------------------
// DLL関数
//---------------------------------------------------------------------------
void __declspec(dllexport) __stdcall dllStruct(ST1 st1)
{

    st1->flg = 1;
    sprintf(st1->name1 ,"%s","test");
    st1->pat_st3.pat_st2.flg2 = 2; 
    st1->pat_st3.flg3 = 3; 

}
とりあえず、C++ 側の構造体定義も別にネストしてるわけではないんですから、
C# 側の構造体定義も C++ の記述に合わせてネストなしでやれば分かりやすいと思います。

あと dllStruct の引数が、C# の関数宣言・呼び出し時に渡してるもの・C++ の関数でことごとく違ってますが。
返信ありがとうございます。
現在ここを参考に書き直しております。
http://www2u.biglobe.ne.jp/~kaduhiko/csharp_05.html

C#の構造体部分を

[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct ST1
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
public string name1;
public int flg1;
public IntPtr pat_st3;

}

[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct ST3
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
public string name3;
public int flg3;
public IntPtr pat_st2;

}

[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct ST2
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
public string name2;
public int flg2;
}

> あと dllStruct の引数が、C# の関数宣言・呼び出し時に渡してるもの・C++ の>関数でことごとく違ってますが。
どの部分のstructを渡せばいいのかわからなかったので曖昧になっていました。

DLLコール部分

ST1 result = new ST1();
IntPtr lst_p;

//メモリ確保(ST3)
lst_p = Marshal.AllocCoTaskMem(Marshal.SizeOf(new ST3()) * (int)result.cnt);
result.pat_st3 = lst_p;


// 外部 DLL 関数コール
dllStruct(ref result);

まだ作成中のため試行錯誤中ですが
アドバイスもらえるとうれしいです。
C++ 側の構造体定義を見る限り、_ST3::pat_st2 や _ST1::pat_st3 はポインタ型ではないですけど。
// _ の有無でポインタ型かどうか分けるってのはどうかと思います。
■No25312に返信(Hongliangさんの記事)
> C++ 側の構造体定義を見る限り、_ST3::pat_st2 や _ST1::pat_st3 はポインタ型ではないですけど。
> // _ の有無でポインタ型かどうか分けるってのはどうかと思います。

そうなると・・
1つの構造体(中に別の構造体あり)で
C++に渡すにはどうしたらよいのでしょうか?
http://msdn.microsoft.com/ja-jp/library/eshywdt7.aspx
普通にフィールドに配置するだけです。
■No25317に返信(Hongliangさんの記事)
> http://msdn.microsoft.com/ja-jp/library/eshywdt7.aspx
> 普通にフィールドに配置するだけです。

以下のように修正しました。
ありがとうございました。

****C++
#include <windows.h>
#include <stdio.h>

//---------------------------------------------------------------------------
//構造体
//---------------------------------------------------------------------------
typedef struct _ST2{

char name2[1024];
int flg2;

}_ST2;

typedef struct _ST1
{
char name1[1024];
int flg;
_ST2 pat_st2;

}_ST1;

typedef struct _ST1* ST1;
//typedef struct _ST2* ST2;

//---------------------------------------------------------------------------
//プロトタイプ宣言
//---------------------------------------------------------------------------
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
void __declspec(dllexport) __stdcall dllStruct( ST1 st1) ;
#ifdef __cplusplus
}
#endif /* __cplusplus */

//---------------------------------------------------------------------------
//エントリーポイント
//---------------------------------------------------------------------------
BOOL WINAPI DllMain( HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved )
{
return TRUE;
}


//---------------------------------------------------------------------------
// DLL関数
//---------------------------------------------------------------------------
void __declspec(dllexport) __stdcall dllStruct(ST1 st1)
{

st1->flg = 1;
sprintf(st1->name1 ,"%s C++側st1",st1->name1);

st1->pat_st2.flg2 = 2;
sprintf(st1->pat_st2.name2 ,"%s C++側st2",st1->pat_st2.name2);

}


****C#

using System;
using System.Runtime.InteropServices;


namespace @struct
{
class Program
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct ST2
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
public string name2;
public int flg2;
}


[StructLayout(LayoutKind.Sequential)]
public struct ST1
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
public string name1;
public int flg1;
public ST2 st2;
}


//---------------------------------------------------------------------------
// DllImport属性
[System.Runtime.InteropServices.DllImport("dllStruct.dll")]
private static extern void dllStruct(ref ST1 st1);

//---------------------------------------------------------------------------
// main
static void Main(string[] args)
{
string msg = string.Empty;
ST1 st1 = new ST1();

st1.flg1 = 9;
st1.name1 = "C#側st1";
st1.st2.flg2 = 9;
st1.st2.name2 = "C#側st2";

dllStruct(ref st1);

msg = "st1: " + st1.flg1 + " " + st1.name1;
Console.WriteLine(msg);

msg = "st2: " + st1.st2.flg2 + " " + st1.st2.name2;
Console.WriteLine(msg);


}
}
}
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板