2017-01-23 125 views
1

我想动态加载一个Fortran dll并将字符串从fortran传回C#。在fortran代码中一切看起来都很好,但是当返回到C#时,字符串的值将丢失。相反,在C#中设置的初始值返回。我试图使用'ref'关键字来获取通过引用传递的字符串,但随后出现如下所示的错误。我究竟做错了什么?从Fortran 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

呃,其实。它的工作原理是因为我可以添加[进出]。如果我离开它,我会得到与动态调用中相同的行为。 – JesperW

回答

0

以供将来参考。我加了[In,Out],一切正常。

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