将一个结构与另一个结构的数组从 C# 传递到 C (P/Invoke)

发布于 2024-12-03 17:55:02 字数 5055 浏览 1 评论 0原文

我有以下结构:

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

顺便说一句,如果您知道如何处理 void* ,我们将欢迎您的帮助...

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;

I have the following structure:

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

The TRatePt is defined as follows:

[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 */

The C declaration is:

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 */

Thanks in advance!

Ok so here are the C structs:

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;

and :

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

By the way if you know how to handle the void* help would be welcome...

PS: TDate is just a
typedef long int TDate;

And here is how I use it:

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;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

别想她 2024-12-10 17:55:03

好的,这就是我认为你的意思的方法,很抱歉我花了这么长时间才解决这个问题。您需要对指向 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 在 C# 中是 64 位,但 long intlongint 都是 Windows 上 C++ 的 32 位。

最后,void* 参数是一个不透明指针,您应该在 C# 结构中将其声明为 IntPtr

OK, here's how to do what I think you mean, and I'm sorry it took me so long to work it out. You will need to use manual marshalling for the pointer to TCurve.

I've simplified your struct for convenience.

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

I doubt that the Pack = 1 is correct. It's pretty rare to pack structs in C.

Another problem is that long is 64 bits in C# but long int, long, int are all 32 bits in C++ on Windows.

Finally, the void* parameter is an opaque pointer and you should declare it as IntPtr in your C# struct.

蔚蓝源自深海 2024-12-10 17:55:03

它不是与不安全的结构一起使用吗?

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

Isnt it working with unsafe structs ?

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

And then, in your code :

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
     }
 }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文