【发布时间】:2017-01-23 13:59:46
【问题描述】:
我正在尝试动态加载 Fortran dll 并将字符串从 fortran 传回 C#。在 fortran 代码中一切看起来都很好,但是当返回到 C# 时,字符串的值会丢失。相反,在 C# 中设置的初始值又回来了。我尝试使用“ref”关键字来获取要通过引用传递的字符串,但随后出现如下错误。我做错了什么?
运行时遇到致命错误。错误地址位于线程 0x2ac4 上的 0x709ce248。错误代码为 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);
}
}
}
【问题讨论】:
-
直接
[DllImport("FortLib.dll")]可以吗? -
是的,它有效。问题是我需要动态加载它。
-
嗯,实际上。它之所以有效,是因为我可以添加 [in, out]。如果我忽略它,我会得到与动态调用相同的行为。
-
好的,我自己解决了。刚刚添加了 [In, Out],瞧!就像“私人委托 void TypeGetStrInfo([In, Out] char[] str);”。几个小时就付诸东流了。
-
现在说得通了。字符串是一个
char数组,这种情况类似于this question and accepted answer,它需要[Out]属性来检索Fortan 值。