从 C# 调用 FORTRAN DLL 的受保护内存冲突
我正在尝试调用从 FORTRAN 代码编译的遗留 dll。 我是 Interop 的新手,但我读过一些关于它的文章,看来我的情况应该相当简单。
我真正想要调用的方法具有复杂的方法签名,但我什至无法在不发生受保护内存冲突的情况下调用这个简单的 GetVersion 方法。
这是我的 DllImport 代码:
[DllImport("GeoConvert.dll",
EntryPoint="_get_version@4",
CallingConvention=CallingConvention.StdCall)]
public static extern void GetGeoConvertVersion([MarshalAs(UnmanagedType.LPStr, SizeConst=8)]
ref string version);
这是 FORTRAN 代码:
SUBROUTINE GetVer( VRSION )
C
!MS$DEFINE MSDLL
!MS$IF DEFINED (MSDLL)
ENTRY Get_Version (VRSION)
!MS$ATTRIBUTES DLLEXPORT,STDCALL :: Get_Version
!MS$ATTRIBUTES REFERENCE :: VRSION
!MS$ENDIF
!MS$UNDEFINE MSDLL
C
CHARACTER*8 VRSION
C
VRSION = '1.0a_FhC'
C
RETURN
END
这是我失败的单元测试:
[Test]
public void TestGetVersion()
{
string version = "";
LatLonUtils.GetGeoConvertVersion(ref version);
StringAssert.IsNonEmpty(version);
}
这是我收到的错误消息:
System.AccessViolationException
Message: Attempted to read or write protected memory.
This is often an indication that other memory is corrupt.
我尝试过的其他操作:
- 使用默认编组
- 传递 char[] 而不是字符串(获取方法签名错误)
I am trying to call out to a legacy dll compiled from FORTRAN code. I am new to Interop, but I've read some articles on it and it seems like my case should be fairly straightforward.
The method I really want to call has a complex method signature, but I can't even call this simple GetVersion method without getting a protected memory violation.
Here's my DllImport code:
[DllImport("GeoConvert.dll",
EntryPoint="_get_version@4",
CallingConvention=CallingConvention.StdCall)]
public static extern void GetGeoConvertVersion([MarshalAs(UnmanagedType.LPStr, SizeConst=8)]
ref string version);
Here's the FORTRAN code:
SUBROUTINE GetVer( VRSION )
C
!MS$DEFINE MSDLL
!MS$IF DEFINED (MSDLL)
ENTRY Get_Version (VRSION)
!MS$ATTRIBUTES DLLEXPORT,STDCALL :: Get_Version
!MS$ATTRIBUTES REFERENCE :: VRSION
!MS$ENDIF
!MS$UNDEFINE MSDLL
C
CHARACTER*8 VRSION
C
VRSION = '1.0a_FhC'
C
RETURN
END
Here's my unit test that fails:
[Test]
public void TestGetVersion()
{
string version = "";
LatLonUtils.GetGeoConvertVersion(ref version);
StringAssert.IsNonEmpty(version);
}
Here's the error message I get:
System.AccessViolationException
Message: Attempted to read or write protected memory.
This is often an indication that other memory is corrupt.
Other things I've tried:
- Using the default marshalling
- Passing a char[] instead of a string (get method signature errors instead)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
...剪断...
好的,我成功了,问题是通过引用传递的。 我不知道为什么,但这有效:
...snip...
您需要通过引用传递,因为这是 FORTRAN 代码使用的语义。 客户端代码传入一个缓冲区,FORTRAN 代码将写入该缓冲区,而不是使用返回值。
...剪断...
!MS$属性参考::VRSION
...snip...
FORTRAN 代码中的此属性指定此参数通过引用传递。 这意味着 FORTRAN 代码将写入该地址。 如果 DllImport 也没有将其声明为引用值,您将遇到访问冲突。
...snip...
OK, I got it to work, the problem was passing by ref. I'm not sure why, but this works:
...snip...
You need to pass by reference because that is the semantic being used by the FORTRAN code. The client code is passing in a buffer that the FORTRAN code is going to write to in lieu of using a return value.
...snip...
!MS$ATTRIBUTES REFERENCE :: VRSION
...snip...
This attribute in your FORTRAN code specifies that this parameter is passed by reference. That means the FORTRAN code is going to write to this address. If the DllImport doesn't declare it as a ref value also, you will get an access violation.
好的,我成功了,问题是通过引用传递的。 我不知道为什么,但这有效:
通过这个测试:
OK, I got it to work, the problem was passing by ref. I'm not sure why, but this works:
With this test:
您尝试过使用 StringBuilder 吗?
创建 String 作为 StringBuilder 并将其传递到 dll 函数中。
我不确定要使用什么 Marashlling 语句,也许默认的可能会起作用。
看一下:C# P/Invoke 中的 Marshal C++“string”类
这是一篇好文章,可能也会有所帮助:Interop Marshalling
Have you tried using a StringBuilder?
Create your String as a StringBuilder and pass that into the dll function.
Im unsure as to what Marashlling statement to use, perhapse the default might work.
Have a look at: Marshal C++ “string” class in C# P/Invoke
Heres a good article the might help as well: Interop Marshalling
我无法尝试这个解决方案,因为我没有 FORTRAN 编译器,但我认为这对你有用:
I cannot try this solution since I do not have a FORTRAN compiler, but I think this would work for you:
谢谢大家,我一直在尝试将字符串从 c# 传递到 fortran dll 的子例程,这个方法是许多其他方法中唯一有效的方法
Thank you all guys, I've been trying to pass a string from c# to a subroutine from fortran dll and this method was the only working one among lots of others