2010-05-27 3 views
0

У меня есть подпрограмма, написанная в fortran, которую мне нужно вызвать из VB.NET, где написаны все мои другие функции. Я не написал фортран и почти не знаю фортран. Я получаю следующее исключение в вызове функции dll и не знаю, как это исправить. Интересно, связано ли это из-за неконгруэнтной переменной длины?AccessViolationException был необработанным, вызывая fortran dll из vb net

У меня есть источник для моего fortran и скомпилирован с помощью компилятора g95. Я попытался скомпилировать его с флагом, на котором предполагается, что все реалы будут вынуждены 32 бита (-r4). Это странно, что вам не требуется инициализировать переменные перед использованием в fortran. Я думал, что это должен быть ребристый язык.

Во всяком случае, ниже исключение я получаю:

System.AccessViolationException был необработанное Сообщение = Попытка чтения или записи в защищенную память. Это часто указывает на то, что другая память повреждена. Источник = PTPWrapper
StackTrace: в PTPWrapper.Module1.pointtopoint (Single & IELEVAT, Одиночный & IDIST, Одиночный & FREQ, Одно & HTAMSL, Одиночный & DLOSS, Одиночный & загромождать) в PTPWrapper.Module1.Main () в C: \ Documents и Settings \ SGoldman \ мои документы \ Visual Studio 2010 \ Projects \ PTPWrapper \ PTPWrapper \ Module1.vb: линия в System.AppDomain._nExecuteAssembly (RuntimeAssembly сборки, String [] арг) на System.AppDomain.ExecuteAssembly (String assemblyFile, Evidence assemblySecurity, String [] арг) на Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() в System.Threading.ThreadHelper.ThreadStart_Context (Объект состояние) в системе .Threading.ExecutionContext.Run (ExecutionContext ExecutionContext, ContextCallback обратного вызова, состояние объекта, логическое ignoreSyncCtx) в System.Threading.ExecutionContext.Run ( исполнения ExecutionContext ExecutionContext, ContextCallback обратного вызова, объект состояния) в System.Threading.ThreadHelper .ThreadStart() Внутренний Исключение:

вот мой VB объявление функции и вызов функции:

Declare Sub pointtopoint Lib "diff5z11.dll" (ByRef IELEVAT As Single, ByRef IDIST As Single, ByRef FREQ As Single, ByRef HTAMSL As Single, ByRef DLOSS As Single, ByRef CLUTTER As Single) 

pointtopoint(elevation(0), distance, freq, height, dlo, clut) 

все переменные определены как 32-битных синглов здесь, в VB.

и вот первые несколько строк кода FORtran:

subroutine pointtopoint(IELEVAT, IDIST, FREQ, HTAMSL, DLOSS, CLUTTER) 

     real ielevat(*) 
     dimension oblim(2) 

     dd  = 0.1 
     EK  = 1.333   ! Earth curvature (4/3 earth) 
     HR  = 9.1    ! Rcvr Ant ht (m), for 30 feet 
     HRAMSL = IELEVAT(IDIST) + HR 
     DIST = float(idist)*dd 
     FRESMIN = HR + 1.0 
     DLOSS = 0.0 
     TDLOSS = 0.0 
     RDLOSS = 0.0 
     ADJ = 0.0 

любые идеи, как я могу получить вызов на работу и получить обратно свои данные? Благодаря!

ответ

1

Похоже, вы почти там.

Во-первых, я хочу указать, что вы можете принудительно потребовать объявления в Фортране, и это рекомендуется.Для этого добавьте IMPLICIT NONE после объявления подпрограммы:

subroutine pointtopoint(IELEVAT, IDIST, FREQ, HTAMSL, DLOSS, CLUTTER) 
    IMPLICIT NONE 
    [variable declarations] 
    ... 
end subroutine pointtopoint 

Это может быть хорошей идеей в вашем случае, потому что это выглядит как есть некоторая переменная путаница типа. Если IMPLICIT NONE не используется, компилятор Fortran делает предположения относительно того, какой тип переменной является первым символом имени переменной. Любая переменная, начинающаяся с I, J, K, L, M или N, считается INTEGER, а все остальные - REAL. Итак, первая проблема, которую я вижу, это IDIST - вы отправляете Single из VB, и это, вероятно, вызывает нарушение доступа к памяти, которое вы видите. Независимо от того, какое число отправляется, поскольку Single интерпретируется как INTEGER и, скорее всего, выходит за пределы массива IELEVAT.

Кроме того, еще одна вещь, которую я замечаю (и это может быть не ошибка - я не могу сказать, потому что вся подпрограмма не отображается), так это то, что подпрограмма получает переменную HTAMSL, а затем использует HRAMSL. Это похоже на возможную опечатку, где программист действительно хотел использовать HTAMSL. HTAMSL и HRAMSL - две совершенно разные переменные. Это еще один побочный эффект от использования IMPLICIT NONE - опечатки остаются незамеченными, и вы получите неожиданные результаты.

+0

спасибо, я должен буду бардак вокруг с подпрограммой и посмотреть, не могу ли я устранить некоторые из этих двусмысленностей. HTAMSL - высота передатчика выше среднего уровня моря HRAMSL - высота приемника выше среднего уровня моря так, по крайней мере, это не то, что нарушает это. Я дам всем знать, если я получу работу. Еще раз спасибо. –

0

Re «Это странно, что вам не требуется инициализировать переменные перед использованием в fortran». - вы должны в Fortran инициализировать переменные перед их использованием. Инициализация и декларация различны. Старый FORTRAN часто использовал «неявное типирование», в котором переменные были неявно напечатаны первой буквой их имени. Современная практика заключается в том, чтобы явно вводить каждую переменную, но разрешить устаревший код для компиляции старого метода. Как уже ответил @brady, вы можете заставить компилятор требовать явных деклараций каждой переменной, включив «implicit none». Большинство компиляторов также имеют параметр компилятора для такого же эффекта.

Как писал @brady, из неявной типизации IDIST является целым числом и используется как индекс массива. IELEVAT должен быть достаточно большим для ценности IDIST, которую вы передаете. Если этого недостаточно, чтобы заставить его работать, вы можете получить больше контроля над вызовом, используя привязку ISO C для Fortran 2003, которая широко доступна в компиляторах Fortran 95. Это позволит Fortran использовать соглашения о вызове C для подпрограммы, которые, скорее всего, будут соответствовать ожиданиям VB. И вы можете контролировать, передается ли аргумент по значению или по ссылке.

Что-то вроде:

subroutine pointtopoint (IELEVAT, IDIST, FREQ, HTAMSL, DLOSS, CLUTTER) bind (C, name="pointtopoint") 

implicit none ! optional 
real (c_float), dimension (*) :: IELEVAT 
integer (c_int) :: IDIST 
real (c_float) :: FREQ, HTAMSL, DLOSS, CLUTTER 

gfortran руководства имеет некоторую документацию: http://gcc.gnu.org/onlinedocs/gfortran/Mixed_002dLanguage-Programming.html Для MS Windows, возможно, потребуется расширение для выбора между призывающими конвенциями: http://gcc.gnu.org/onlinedocs/gfortran/GNU-Fortran-Compiler-Directives.html#GNU-Fortran-Compiler-Directives

Смежные вопросы