Вызов FORTRAN dll из C # и присвоение значений массиву структур - PullRequest
4 голосов
/ 03 июня 2011

Я могу передать 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, и я могу передавать, но не return и массив struct?

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

1 Ответ

4 голосов
/ 03 июня 2011

Я делал это раньше, используя указатель, а не массив.Я думаю, что ваши структуры копируются для вызова 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].

...