2017-01-23 4 views
1

Я пытаюсь динамически загрузить dll Fortran и передать строку обратно из fortran в C#. Все выглядит нормально, когда внутри кода fortran, но при возврате на C# значение строки теряется. Вместо этого возвращается начальное значение, установленное на C#. Я попытался использовать ключевое слово ref, чтобы передать строку по ссылке, но затем я получаю ошибку, как показано ниже. Что я делаю не так?Передача строки из dll фортрана в C#

Среда выполнения столкнулась с фатальной ошибкой. Адрес ошибки был равен 0x709ce248, на потоке 0x2ac4. Код ошибки: 0xc0000005. Эта ошибка может быть ошибкой в ​​CLR или в небезопасных или не поддающихся проверке частях кода пользователя. Общие источники этой ошибки включают ошибки маршалинга пользователя для COM-interop или PInvoke, которые могут повредить стек.

Fortran код:

module FortLibInterface 
implicit none 

integer, parameter :: STR_LENGTH = 256 

contains 

subroutine GetString(Str) 
    !DIR$ ATTRIBUTES DLLEXPORT::GetString 
    !DIR$ ATTRIBUTES ALIAS: 'GetString' :: GetString 
    !DIR$ ATTRIBUTES REFERENCE:: Str 

    character(len=STR_LENGTH), intent(inout) :: Str 

    Str = 'bcdef...' 

end subroutine 

end module 

C# код:

using System; 
using System.Runtime.InteropServices; 

namespace FortranCSTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      string dllPath = "C:\\Temp\\FortLib.dll"; 

      FortLibTest lib = new FortLibTest(dllPath); 

      lib.MakeTestCall(); 
     } 
    } 

    public class FortLibTest 
    { 
     public const int STR_LENGTH = 256; 

     public const string FortranFuncName = "GetString"; 

     private string pathToDll = null; 

     [DllImport("kernel32.dll", SetLastError = true)] 
     private static extern IntPtr LoadLibrary(String DllName); 

     [DllImport("kernel32.dll")] 
     private static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName); 

     [DllImport("kernel32.dll")] 
     private static extern bool FreeLibrary(IntPtr hModule); 

     public FortLibTest(string FullPathToDll) 
     { 
      pathToDll = FullPathToDll; 
     } 

     [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 
     private delegate void TypeGetStrInfo(char[] str); 

     void GetStrInfo(char[] str) 
     { 
      IntPtr pDll = LoadLibrary(pathToDll); 
      if (pDll != IntPtr.Zero) 
      { 
       IntPtr pFunc = GetProcAddress(pDll, FortranFuncName); 
       if (pFunc != IntPtr.Zero) 
       { 
        TypeGetStrInfo func = (TypeGetStrInfo)Marshal.GetDelegateForFunctionPointer(pFunc, typeof(TypeGetStrInfo)); 

        func(str); 
       } 
       else 
       { 
        //Something 
       } 

       FreeLibrary(pDll); 
      } 
      else 
      { 
       //Something 
      } 
     } 

     public void MakeTestCall() 
     { 
      char[] str = new char[STR_LENGTH]; 

      str[0] = 'a'; 

      GetStrInfo(str); 
     } 
    } 
} 
+0

Это работает, если вы прямо '[DllImport (" FortLib.dll ")]'? – ja72

+0

Да, это работает. Проблема в том, что мне нужно загружать ее динамически. – JesperW

+0

Ну, на самом деле. Это работает, потому что я могу добавить [in, out]. Если я оставлю это, я получаю то же поведение, что и в динамическом вызове. – JesperW

ответ

0

Для дальнейшего использования. Я добавил [In, Out], и все работает.

[DllImport(_dllName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] 
public static extern void GetString([In, Out] char[] str);