C# 从C回来时撞车:为什么(当然)?

C# 从C回来时撞车:为什么(当然)?,c#,c,interop,C#,C,Interop,在C#中,我填充一个二进制缓冲区(1.5到2kb),我在C DLL中引用它。一切都很顺利(按C的说法),直到我不得不回到C。在最后一刻,程序崩溃(没有异常抛出,只是一个崩溃:“停止工作”)。 Cr是DLL中的C例程。 我在Visual Studio社区2017工作。 早些时候,我通过C中的字符串和sscanf_s传递数据,这很好,但希望加快速度(并在途中学习不同的东西)。 缓冲区包含所有类型的浮点数、整数和双精度数,它们在C端正确拾取(stepping这样说)。 这是第一段C代码: 下面是DLL

在C#中,我填充一个二进制缓冲区(1.5到2kb),我在C DLL中引用它。一切都很顺利(按C的说法),直到我不得不回到C。在最后一刻,程序崩溃(没有异常抛出,只是一个崩溃:“停止工作”)。 Cr是DLL中的C例程。 我在Visual Studio社区2017工作。 早些时候,我通过C中的字符串和sscanf_s传递数据,这很好,但希望加快速度(并在途中学习不同的东西)。 缓冲区包含所有类型的浮点数、整数和双精度数,它们在C端正确拾取(stepping这样说)。 这是第一段C代码:

下面是DLL导入:

[DllImport(@"Cr.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "Cr", 
        CharSet = CharSet.Ansi, BestFitMapping =false,ThrowOnUnmappableChar =true)]


    public static extern int Cr([In] ref byte[] buffer,
        [In] int n, 
        float[] eigenfreq, 
        ref double error, 
        ref double rms_resid,            
        double[,] force,
        double[,] defl);
那么:为什么?我做错了什么?如果C形部分有问题,它会比最后一个大括号显示的更早,不是吗?C代码的最后一部分会释放大量malloc-ed块(而不是缓冲区!)。

根据MSDN,在调用外部函数时多维数组不会被封送,因此必须将数组转换为一维数组

正如我所看到的,这些数组是输出缓冲区,因此对于调用,可以执行以下操作:

double[] MemberEndforces = new double[mbCount * 12];
double[] Deflection = new double[(mbCount + 1) * 6];

//...

info = NativeMethods.Cr(
                    ref buffer, NrOfMod, Eigenfreqs, ref error,
                    ref rms_resid, MemberEndforces, Deflection);
调用函数后,需要将这些数组转换为多维数组:

double[,] mMemberEndforces = new double[mbCount, 12];
double[,] mDeflection = new double[mbCount + 1, 6];

for(int x = 0; x < mbCount; x++)
{
    for(int y = 0; y < 12; y++)
        mMemberEndforces[x,y] = MemberEndforces[x * 12 + y];
}

for(int x = 0; x < mbCount + 1; x++)
{
    for(int y = 0; y < 6; y++)
        mDeflection[x,y] = Deflection[x * 6 + y];
}
double[,]mmemberndforces=新的double[mbCount,12];
double[,]mDeflection=新的double[mbCount+1,6];
对于(int x=0;x
我找到了一个解决方案: 我移除了不安全的{}。没必要。 然后我在调用C例程时“取消引用”ref buffer:

 using (BinaryWriter binWriter = new BinaryWriter(new MemoryStream()))
 {
     BuildExportBuffer(binWriter); // fill the buffer with doubles and floats ant ints
     var buffer = ((MemoryStream)binWriter.BaseStream).GetBuffer(); // get the buffer's address
     info = NativeMethods.Cr( buffer, NrOfMod, Eigenfreqs, ref error, ref rms_resid,
 MemberEndforces, Deflection);
  .....
    etc.
当然,在德林波特也一样

在C函数中,我还做了一些小改动:

extern "C"
{
char ** buffer;

__declspec(dllexport) int __cdecl Cr(
    char *_buffer,  // <== here and
    int n,
    float * eigenFreq,
    double * error,
    double * rms_resid,
    double * endforces,
    double * deflection
     )
 {

    buffer = &_buffer; // <== here.

工作起来很有魅力。我仍然需要找出原因。

在没有看到dllImport的情况下,任何人都很难帮助你,具体的例外情况就是dllImport。我将数组元素一个元素一个元素地写入缓冲区。因此,缓冲区中没有数组的线索。在C端,我将数组一个元素一个元素地读到C数组中,确切地知道缓冲区中的内容。我返回的数组(偏转和MemberEndForces,定义C#side,填充C-side)在我有字符串缓冲区时恢复正常,所以这不是问题,是吗?@Erik我看不出你的外部函数在做什么,我的水晶球正在修复中。。。在任何情况下,C#都无法正确封送多维数组,因此它将失败,添加您收到的异常可能会有所帮助,在堆栈溢出方面,我们是程序员而不是水晶观察家……当然问题可能出在C函数的某个地方,但问题是,在返回C#之前,该函数似乎运行良好。单步执行显示C部分工作,从二进制缓冲区正确读取数据。此外,使用StringBuilder缓冲区的效果非常好,可以使C#数组偏转和MemberEndForces返回到良好的状态。这并不奇怪,因为我只传递指针,。从你所说的,我现在只能得出结论,我所做的没有错,我必须去别处看看。这也有帮助。@Erik再次强调,C#无法正确处理多维数组。如果您发布您收到的异常,我可以确认这是否是问题。正如我之前所说:没有异常,只是:“我的程序已停止工作一个问题导致程序停止正常工作。Windows将关闭程序并通知您解决方案可用”和一个按钮:“关闭程序”。当然没有后续通知。
 using (BinaryWriter binWriter = new BinaryWriter(new MemoryStream()))
 {
     BuildExportBuffer(binWriter); // fill the buffer with doubles and floats ant ints
     var buffer = ((MemoryStream)binWriter.BaseStream).GetBuffer(); // get the buffer's address
     info = NativeMethods.Cr( buffer, NrOfMod, Eigenfreqs, ref error, ref rms_resid,
 MemberEndforces, Deflection);
  .....
    etc.
extern "C"
{
char ** buffer;

__declspec(dllexport) int __cdecl Cr(
    char *_buffer,  // <== here and
    int n,
    float * eigenFreq,
    double * error,
    double * rms_resid,
    double * endforces,
    double * deflection
     )
 {

    buffer = &_buffer; // <== here.
double  readd(char **buffer)
{
   double *f = (double *) *buffer;
   *buffer += 8;
   return *f;
}