我有一个关于从C#调用fortran DLL的问题(使用VS 2010)。
我无法运行此程序。当从C#进入Fortran代码时,在计算z
的行(x
和y
的总和)处,会弹出一个消息框:
An unhandled exception of type 'System.AccessViolationException' occurred in WinApp_FortranDLLStruct2.exe
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt"
我该如何解决这个问题?
Fortran DLL被称为" TestDLL.DLL"
Fortran代码:
MODULE TESTING
TYPE Point
REAL*8 :: x(10)
REAL*8 :: y(10)
REAL*8 :: z(10)
ENDTYPE Point
end module
!DEC$ ATTRIBUTES DLLEXPORT::CalcPoint
!DEC$ ATTRIBUTES ALIAS : "CalcPoint" :: CalcPoint
SUBROUTINE CalcPoint(myPts)
use TESTING
IMPLICIT NONE
INTEGER*4 I,J,NPTS
REAL*8 Sum_Out
TYPE(Point) :: myPts
do i = 1,10
myPts.z(i) = myPts.x(i) + myPts.y(i)
enddo
END SUBROUTINE CalcPoint
C#代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace WinApp_FortranDLLStruct2 {
public partial class Form1 : Form {
[StructLayout(LayoutKind.Sequential)]
public unsafe struct myPoint {
public fixed double x[10];
public fixed double y[10];
public fixed double z[10];
}
public class FortranCall {
[DllImport("TestDLL.dll")]
public unsafe static extern void CalcPoint([Out] myPoint t);
}
public Form1()
{
InitializeComponent();
}
private unsafe void button1_Click(object sender, EventArgs e) {
int i;
double d1 = 1.0;
myPoint T = new myPoint();
for (i = 0; i < 10; i++) {
T.x[i] = (i+1)*d1;
T.y[i] = (i+2)*d1;
}
FortranCall.CalcPoint(T);
}
}
}
答案 0 :(得分:3)
添加C
调用约定解决了我的堆栈不平衡问题。同时将[Out]
更改为ref
以指向相同的内存,而不是复制值。这是我的代码
MODULE TESTING
INTEGER, PARAMETER :: SIZE = 10
TYPE Point
SEQUENCE
REAL*8 :: x(SIZE), y(SIZE) , z(SIZE)
ENDTYPE Point
end module
SUBROUTINE CalcPoint(myPts)
!DEC$ ATTRIBUTES DLLEXPORT::CalcPoint
!DEC$ ATTRIBUTES ALIAS : 'CalcPoint' :: CalcPoint
use TESTING
IMPLICIT NONE
! Arguments
TYPE(Point), INTENT(INOUT) :: myPts
! Local variables
INTEGER*4 I
do i = 1,SIZE
myPts%z(i) = myPts%x(i) + myPts%y(i)
enddo
END SUBROUTINE CalcPoint
[StructLayout(LayoutKind.Sequential)]
public unsafe struct myPoint
{
public const int size = 10;
public fixed double x[size];
public fixed double y[size];
public fixed double z[size];
public void Initialize(double d1)
{
fixed (double* x_ptr=x, y_ptr=y, z_ptr=z)
{
for (int i=0; i<size; i++)
{
x_ptr[i]=(i+1)*d1;
y_ptr[i]=(i+1)*d1;
z_ptr[i]=0.0;
}
}
}
}
class Program
{
[DllImport(@"FortranDll1.dll", CallingConvention=CallingConvention.Cdecl)]
public unsafe static extern void CalcPoint(ref myPoint t);
unsafe Program()
{
double d1=1.0;
var T=new myPoint();
T.Initialize(d1);
Program.CalcPoint(ref T);
// T.z = {2,4,6,...}
}
static void Main(string[] args)
{
new Program();
}
}
要将固定数组转换为托管数组,反之亦然,请使用以下代码
public unsafe struct myPoint
{
public const int size=10;
public fixed double x[size];
...
public double[] X
{
get
{
double[] res=new double[size];
fixed (double* ptr=x)
{
for (int i=0; i<size; i++)
{
res[i]=ptr[i];
}
}
return res;
}
set
{
if (value.Length>size) throw new IndexOutOfRangeException();
fixed (double* ptr=x)
{
for (int i=0; i<value.Length; i++)
{
ptr[i]=value[i];
}
}
}
}
}
答案 1 :(得分:0)
尝试:
[DllImport("TestDLL.dll")]
public unsafe static extern void CalcPoint(ref myPoint t);
如果这不起作用,请尝试创建一个非常简单的FORTRAN方法,该方法接受X / Y值并将它们加在一起并返回总和。这将允许您诊断整个过程是否正常工作。从那里开始工作,增加了更多的复杂性,直到它中断。这会告诉你是否有其他错误。