Передача структуры с массивом другой структуры из C # в C (P / Invoke) - PullRequest
2 голосов
/ 09 сентября 2011

У меня есть следующая структура:

[StructLayout(LayoutKind.Sequential)]
public struct TCurve
{
    public int fNumItems;             /* Number of TRatePts in fArray */
    public IntPtr fArray;          /* Dates & rates */ // pointer to an array of TRatePt[]
    public long fBaseDate;            /* Discount date */
    public double fBasis;         //ZERO_CURVE_BASIS in capvoll.c which is #defined as ANNUAL_BASIS 1   /* Number compounding periods / year */
    public long fDayCountConv;   //ZERO_CURVE_DAY_COUNT_CONV in capvoll.c which is #defined as GTO_ACT_365F; = 2L /* How the year fraction is computed */
    public IntPtr     fClassHandle;  /* C++ class handle implementation */
};
[StructLayout(LayoutKind.Sequential)]
public struct TRatePt
{
    public long fDate;
    public double fRate;
};

TRatePt определяется следующим образом:

[DllImport("alib.dll", EntryPoint = "GtoCapFloorAvgVol")]
    public static extern int CapFloorAvgVol(
        long capStartDate,                  /* (I)  */
        long capExpiryDate,                 /* (I) */
        double[] strikeRates,                /* (I) */
        int numStrikeRates,                  /* (I) */
        double[] principles,                 /* (I) */
        int numPrinciples,                   /* (I) */
        int moneymarketDen,                  /* (I) # days/year */
        ref TDateInterval resetPeriod,       /* (I) Time Between caplets */
        int optionType,                      /* (I) Cap or Floor */
        char stubPosition,                   /* (I) 2/16/94 GG 'F'ront or 'B'ack */
        [In] IntPtr zeroCurve,                /* (I) For discounting Pointer to TCurve*/
        double price,                        /* (I) Price */
        double avgVolGuess,                  /* (I) Average Volatility guess */
        out double avgVol);                  /* (O) Average Volatility */

Декларация C:

GTO_EXPORT(int )  GtoCapFloorAvgVol(
TDate capStartDate,                  /* (I)  */
TDate capExpiryDate,                 /* (I) */
double *strikeRates,                 /* (I) */
int numStrikeRates,                  /* (I) */
double *principles,                  /* (I) */
int numPrinciples,                   /* (I) */
int moneymarketDen,                  /* (I) # days/year */
TDateInterval *resetPeriod,          /* (I) Time Between caplets */
int optionType,                      /* (I) Cap or Floor */
char stubPosition,                   /* (I) 2/16/94 GG 'F'ront or 'B'ack */
TCurve *zeroCurve,                   /* (I) For discounting */
double price,                        /* (I) Price */
double avgVolGuess,                  /* (I) Average Volatility guess */
double *avgVol)                      /* (O) Average Volatility */

Заранее спасибо!

Хорошо, вот структуры C:

typedef struct _TCurve{
int       fNumItems;     /* Number of TRatePts in fArray */
TRatePt  *fArray;        /* Dates & rates */
TDate     fBaseDate;     /* Discount date */ 
double    fBasis;        /* Number compounding periods / year */
long      fDayCountConv; /* How the year fraction is computed */
void     *fClassHandle;  /* C++ class handle implementation */ } TCurve;

и:

typedef struct{
TDate  fDate;
double fRate;} TRatePt;

Кстати, если вы знаете, как обращаться с пустотой * помощь будет приветствоваться ...

PS: TDate - это просто typedef long int TDate;

А вот как я это использую:

TCurve _zeroCurve = new TCurve()
                        {
                            fBaseDate = _tempValueDate,
                            fNumItems = _ratePoints.Length,
                            fBasis = 2L,
                            fDayCountConv = 1
                        };
        int _sizeOfTCurve = Marshal.SizeOf(typeof(TCurve));
        IntPtr p_zeroCurve = Marshal.AllocHGlobal(_sizeOfTCurve);
        Marshal.StructureToPtr(_zeroCurve, p_zeroCurve, false);

        int _status;
        _zeroCurve.fArray = Marshal.AllocHGlobal(_ratePoints.Length * Marshal.SizeOf(typeof(TRatePt)));
        try
        {
            IntPtr _ratePt = _zeroCurve.fArray;
            for (int _i = 0; _i < _ratePoints.Length; _i++)
            {
                Marshal.StructureToPtr(_ratePoints[_i], _ratePt, false);
                //_ratePt = new IntPtr(_ratePt.ToInt64() + Marshal.SizeOf(typeof(TRatePt)));
                IntPtr _nextRatePt = new IntPtr(_ratePt.ToInt64() + Marshal.SizeOf(typeof(TRatePt)));
                _ratePt = _nextRatePt;
                //_ratePt += Marshal.SizeOf(typeof(TRatePt));
            }
            _status = CapFloorAvgVol(_tempStartDate, _temPexpiryDate, strikeRates, strikeRates.Length, principles, principles.Length, moneymarketDen,
                                            ref _resetPeriod, optionType, stubPosition, p_zeroCurve, price, avgVolGuess, out avgVol);
        }
        finally
        {
            Marshal.FreeHGlobal(_zeroCurve.fArray);
        }

        Marshal.FreeHGlobal(p_zeroCurve);
        p_zeroCurve = IntPtr.Zero;

Ответы [ 2 ]

2 голосов
/ 09 сентября 2011

ОК, вот как сделать то, что, как я думаю, вы имеете в виду, и мне жаль, что мне понадобилось так много времени, чтобы решить это.Вам нужно будет использовать ручную сортировку для указателя на TCurve.

. Я упростил вашу структуру для удобства.

[StructLayout(LayoutKind.Sequential)]
public struct TCurve
{
    public int fNumItems;            
    public IntPtr fArray;//you need to marshal this manually
};
...
[DllImport("alib.dll", EntryPoint = "GtoCapFloorAvgVol")]
public static extern int CapFloorAvgVol(
    ...
    TCurve ref zeroCurve,
    ...
);
...
TCurve curve = new TCurve();
TRatePt[] items = new TRatePt[2];
//for example, but you'd have the items coming in as a parameter I guess

curve.fNumItems = items.Length;
curve.fArray = Marshal.AllocHGlobal(items.Length * Marshal.SizeOf(typeof(TRatePt)));
try
{
    IntPtr item = curve.fArray;
    for (int i = 0; i < items.Length; i++)
    {
        Marshal.StructureToPtr(items[i], item, false);
        item = new IntPtr(item.ToInt64() + Marshal.SizeOf(typeof(TRatePt))); 
    }
    //now call the function passing the curve struct
}
finally
{
    Marshal.FreeHGlobal(curve.fArray);
}

Я сомневаюсь, что Pack = 1 является правильным.Очень редко можно упаковать структуры в C.

Другая проблема заключается в том, что long - это 64 бита в C #, но long int, long, int - все 32 бита в C ++ в Windows.

Наконец, параметр void* является непрозрачным указателем, и вы должны объявить его как IntPtr в вашей структуре C #.

0 голосов
/ 09 сентября 2011

Разве это не работает с небезопасными структурами?

[StructLayout(LayoutKind.Sequential)]
public unsafe struct TCurve
{
    public TRatePt* fArray;          /* Dates & rates */ // pointer to an array of TRatePt[]
};
[StructLayout(LayoutKind.Sequential)]
public unsafe struct TRatePt
{
    public long fDate;
    public double fRate;
};

А потом, в вашем коде:

unsafe
{
     TCurve _zeroCurve = new TCurve();
     var arr = new TRatePt[]{new TRatePt(), new TRatePt()};
     fixed (TRatePt* pt = arr)
     {
          _zeroCurve.fArray = pt;
          // do sthing while your array is fixed
     }
 }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...