Вызов FORTRAN dll из C # и присвоение значений массиву структур

#c# #interop #struct #fortran

#c# #взаимодействие #структура #fortran

Вопрос:

Я могу передать C# структуру в FORTRAN просто отлично. Я даже могу передать массив C# структуры как массив TYPE() в FORTRAN . Где я столкнулся с проблемой, так это когда я попытался вернуть значения обратно в C# . Вот пример:

Библиотека DLL fortran является:

 MODULE TESTING

   TYPE VALUEREF
     INTEGER*4 :: A
   ENDTYPE VALUEREF

CONTAINS

   SUBROUTINE TEST_REF(T,N)
   !DEC$ ATTRIBUTES DLLEXPORT :: TEST_REF
   !DEC$ ATTRIBUTES ALIAS:'TEST_REF' :: TEST_REF
   !DEC$ ATTRIBUTES VALUE :: N
   IMPLICIT NONE
     INTEGER*4 :: A,I,N   
     TYPE(VALUEREF) :: T(N)      
     A = 100
     DO I=1,N
        T(I)%A = A   I
     END DO

   END SUBROUTINE
END MODULE
  

и C# вызывающая функция, которая ожидает результатов, является:

 [StructLayout(LayoutKind.Sequential)]
public struct ValueRef
{
    public int a;
}

[DllImport("mathlib.dll")]
static extern void TEST_REF(ValueRef[] t, int n);

void Main()
{
    ValueRef[] T = new ValueRef[4];
    for (int i = 0; i < T.Length; i  )
    {
        T[i].a = i;
    }
    Console.WriteLine("Initialize");
    for (int i = 0; i < T.Length; i  )
    {
        Console.WriteLine("  A={0}", T[i].a);
    }
    Console.WriteLine("Call Fortran");
    TEST_REF(T, T.Length);
    for (int i = 0; i < T.Length; i  )
    {
        Console.WriteLine("  A={0}", T[i].a);
    }
}
  

С результатами:

 Initialize
  A=0
  A=1
  A=2
  A=3
Call Fortran
  A=0
  A=1
  A=2
  A=3
  

Отлаживая код FORTRAN, я вижу, что начальные значения передаются из C# в FORTRAN просто отлично. Значения переопределяются новыми значениями, и управление передается обратно в C# где старые значения все еще содержатся в ValueRef экземплярах.

Почему я могу передавать и возвращать массив float или int аналогичным образом, просто отлично. и я могу передавать и возвращать единичные структуры с ref ключевым словом, и я могу передавать, но не возвращать и массив struct ?

PS. Я использую Compaq Visual Fortran 6.5 и .NET 3.5
PS2. Я ценю любые комментарии / идеи по этому поводу. Я на 95% закончил свой проект, и теперь я сталкиваюсь с этой проблемой. Весь смысл этого проекта в том, чтобы максимально использовать структуры, чтобы уменьшить количество аргументов, передаваемых функциям, и сохранить определенные аспекты проектирования ООП.

Комментарии:

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

2. примечание форматирование обратной ссылки, к сожалению, недоступно в заголовках

3. Реальность такова, что современный FORTRAN прост и быстр. Я не вижу причин, по которым не только сохранять устаревший код, но и разрабатывать новый код на FORTRAN. Конечно, для графического интерфейса и тому подобного я оставляю это C # / OpenTK.

Ответ №1:

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

 [DllImport("mathlib.dll")]
static extern void TEST_REF(ValueRef* t, int n);
  

Вам нужно будет закрепить свой массив перед вызовом метода.

 fixed (ValueRef* pointer = t)
{
  TEST_REF(pointer, n);
}
  

Редактировать:
На основе комментариев решение состоит в том, чтобы объявить внешний как

 [DllImport("mathlib.dll")]
static extern void TEST_REF([Out] ValueRef[] t, int n);
  

Вот ссылка MSDN на маршалинг массивов и то, как они используются по умолчанию [In] .

Комментарии:

1. Я как раз собирался предложить, чтобы … убедитесь, что вы скомпилировали свой код с флагом unsafe и пометили свои методы и область действия ключевым словом unsafe, иначе вы получите кучу ошибок компилятора.

2. Когда я передаю единственную структуру по ссылке, она не копируется, но когда я передаю массив, она копируется!?

3. Вторая вещь, которую вы можете попробовать, — это использовать атрибут [Out] в подписи P / Invoke.

4. [Out] Атрибут сработал. поэтому, если вы отредактируете свой ответ, я присужу его.

5. Я отредактировал ответ с правильным решением и добавил соответствующую ссылку от Microsoft.