Visual C#在调用包装的C++CLI dll中的Lapack时引发System.AccessViolation

System.AccessViolationException thrown by Visual C# on call to Lapack inside wrapped C++CLI dll

本文关键字:Lapack AccessViolation System 中的 dll 调用 包装 C++CLI Visual      更新时间:2023-10-16

我用本机C++编写了一些代码,它调用blas和lapack库的fortran例程(链接为dll(。本机代码运行良好,没有编译器或运行时错误或警告。

现在,我正试图将本机C++封装到一个dll中,以便在.NET框架中使用,所以我启动了一个Visual C++项目,编写了一个包装器引用类,将其编译到一个dll中,并将该dll包含到一个C#项目中。

在我终于设法编译了C#项目后,我试着运行它。但我在第一次调用lapack例程时遇到了运行时错误!(即在Test.cpp中的dpbtrf_( &LOWER, &n, &izero, D.data(), &ione, &info );线上(

错误显示:

System.AccessViolationException was unhandled
Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
 Source=DotNetTest

我是否缺少某些编译器选项?或者真的存在本地C++编译器\运行时没有看到的损坏内存吗?有关于如何调试的提示吗?

非常感谢!

这是一个微小的复制,它产生了与原始代码相同的问题(太过广泛,无法在这里发布(:

  1. 本机C++测试.h:

    #ifndef TEST_H_INCLUDED
    #define TEST_H_INCLUDED
    #include <vector>
    namespace NativeTest
    {
        class Test
        {
            public:
                Test( int size );
                ~Test();
                void set( int i, double d );
                double get( int i ) const;
                int chol();
            private:
                std::vector<double> D;
                int n;
        }; // class Test
    } // namespace NativeTest
    #endif // TEST_H_INCLUDED
  1. 原生C++测试.cpp(包含在VC++项目中((!用__cdecl编辑(:

    #include "Test.h"
    using namespace NativeTest;
    const int ione = 1;
    const int izero = 0;
    const char LOWER = 'L';
    extern "C"
    {
        // factorization for banded matrix
        void __cdecl dpbtrf_( const char *UPLO, const int *N, const int *KD,
                              double *AB, const int *LDAB, int *INFO );
    }
    Test::Test( int size ) : n( size )
    { D.resize( n ); }
    Test::~Test() { }
    void Test::set( int i, double d ) { D[ i ] = d; }
    double Test::get( int i ) const { return D[ i ]; }
    int Test::chol()
    {
        int info = 0;
        dpbtrf_( &LOWER, &n, &izero, D.data(), &ione, &info );
        return info;
    }
  1. C++\ CLI包装程序:

    // TestNet.h
    #pragma once
    #include "Test.h"
    using namespace System;
    namespace DotNetTest {
        public ref class TestNet
        {
            public:
                TestNet( int size ) { test = new NativeTest::Test( size ); }
                ~TestNet() { this->!TestNet(); }
                !TestNet() { delete test; test = NULL; }
                void set( int i, double d ) { test->set( i, d ); }
                double get( int i ) { return test->get( i ); }
                int chol() { return test->chol(); }
            protected:
                NativeTest::Test * test;                
        };
    }
  1. C#调用:

    DotNetTest.TestNet t = new DotNetTest.TestNet(2);
    t.set(0, 2);
    t.set(1, 3);
    int info = t.chol();

我修复了它,至少在这里发布的测试代码中是这样。我错误地添加了gcc编译的lapack\blast二进制文件,与我在原始项目中使用的相同(也使用了gcc(。

今天,我从这里下载了windows的预编译二进制文件,将它们放在我的C#项目的bin文件夹中(以及3个MinGW dll:libgcc_s_dw2-1.dll、libgfortran-3.dll和libquadmath-0.dll(,并确保Visual C++\CLI项目使用了相同的库进行链接(通过将Additional link Directory设置为C#bin文件夹(。这修复了它,我得到了我想要的结果(没有访问冲突,计算是正确的(。

我还删除了Test.cpp文件的编译选项中的/clr标志,并关闭了该文件的"使用预编译头"。