Нарушение защищенной памяти при вызове библиотеки DLL FORTRAN из C#

StackOverflow https://stackoverflow.com/questions/229362

Вопрос

Я пытаюсь вызвать устаревшую библиотеку dll, скомпилированную из кода FORTRAN.Я новичок в Interop, но я прочитал несколько статей об этом, и мне кажется, что мой случай должен быть довольно простым.

Метод, который я действительно хочу вызвать, имеет сложную сигнатуру метода, но я не могу даже вызвать этот простой метод GetVersion без нарушения защищенной памяти.

Вот мой код DllImport:

[DllImport("GeoConvert.dll", 
            EntryPoint="_get_version@4", 
            CallingConvention=CallingConvention.StdCall)]
public static extern void GetGeoConvertVersion([MarshalAs(UnmanagedType.LPStr, SizeConst=8)]
                                                    ref string version);

Вот код FORTRAN:

SUBROUTINE GetVer( VRSION )
C
!MS$DEFINE  MSDLL 
!MS$IF DEFINED (MSDLL)
        ENTRY Get_Version (VRSION)  
      !MS$ATTRIBUTES DLLEXPORT,STDCALL :: Get_Version
      !MS$ATTRIBUTES REFERENCE :: VRSION
!MS$ENDIF
!MS$UNDEFINE  MSDLL 
C
  CHARACTER*8  VRSION
C
  VRSION = '1.0a_FhC'                                        
C
  RETURN
  END

Вот мой модульный тест, который завершается неудачей:

[Test]
public void TestGetVersion()
{
    string version = "";
    LatLonUtils.GetGeoConvertVersion(ref version);
    StringAssert.IsNonEmpty(version);
}

Вот сообщение об ошибке, которое я получаю:

System.AccessViolationException
Message: Attempted to read or write protected memory. 
         This is often an indication that other memory is corrupt.

Другие вещи, которые я пробовал:

  • Использование сортировки по умолчанию
  • Передача символа[] вместо строки (вместо этого получаем ошибки сигнатуры метода)
Это было полезно?

Решение 2

Хорошо, у меня получилось, проблема заключалась в том, что я проходил по ссылке.Я не уверен почему, но это работает:

[DllImport("GeoConvert.dll", 
                EntryPoint="_get_version@4", 
                CallingConvention=CallingConvention.StdCall)]
    public static extern void GetGeoConvertVersion([MarshalAs(UnmanagedType.LPArray)]
                                                    byte[] version);

С помощью этого теста:

[Test]
    public void TestGetVersion()
    {
        //string version = "";
        byte[] version = new byte[8];
        LatLonUtils.GetGeoConvertVersion(version);
        char[] versionChars = System.Text.Encoding.ASCII.GetChars(version);

        string versionString = new string(versionChars);
    }

Другие советы

...снип...Хорошо, у меня получилось, проблема заключалась в том, что я проходил по ссылке.Я не уверен почему, но это работает:...снип...

Вам нужно передавать по ссылке, потому что это семантика, используемая кодом FORTRAN.Клиентский код передается в буфер, в который код FORTRAN собирается записать вместо использования возвращаемого значения.

...снип...!ССЫЛКА НА АТРИБУТЫ MS$ ::ВРСИОН ...отрывок...

Этот атрибут в вашем коде FORTRAN указывает, что этот параметр передается по ссылке.Это означает, что код FORTRAN будет записывать данные на этот адрес.Если DllImport также не объявит его как значение ref, вы получите нарушение доступа.

Вы пробовали использовать StringBuilder?

Создайте свою строку в качестве StringBuilder и передайте ее в dll-функцию.

Я не уверен относительно того, какой оператор Marashlling использовать, возможно, значение по умолчанию может сработать.

Взгляните на: Маршалировать “строковый” класс C ++ в C # P/Invoke

Вот хорошая статья, которая тоже может помочь: Сортировка взаимодействия

Я не могу попробовать это решение, так как у меня нет компилятора FORTRAN, но я думаю, что это сработало бы для вас:

    [DllImport("GeoConvert.dll", 
            EntryPoint="_get_version@4", 
            CallingConvention=CallingConvention.StdCall,
            CharSet=CharSet.Ansi)]
    public static extern void GetGeoConvertVersion(StringBuilder version);

Спасибо всем вам, ребята, я пытался передать строку из c # в подпрограмму из библиотеки DLL fortran, и этот метод был единственным работающим среди множества других

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top