Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Fortran > Dll из фортрана в c#


Автор: Jon89 27.2.2012, 19:58
Здравствуйте всем)) Сразу говорю что я новичок и прошу не  кидаться камнями за глупые вопросы.
Проблема: Надо сделать dll в fortran. Подключить ее к c#. И из с# вызвать функцию написанную в фортране.
Может кто нить на пальцах объяснить как это сделать. Был бы очень признателен за примеры кода и в Fortran и в c#))))

Заранее спасибо за ответы и потраченное на меня время)

Автор: FCM 9.3.2012, 08:34
Какой компилятор фортрана используется?

Автор: Jon89 11.3.2012, 08:11
Стандартный. Не знаю как называется))

Автор: FCM 12.3.2012, 11:25
Стандартных компиляторов не бывает. Компиляторы конкретных производителей в той или иной степени соответсвуют стандарту Фортрана, а также предлагают расширения.

Уж выясни как-нибудь, что за компилятор. 

Примерно - это выглядит так:
Вот простейшая функция, возвращающая удвоенное значение целого аргумента для компилятора из линейки Visual Fortran.
Код

INTEGER FUNCTION TWICE (X)
!DEC$ ATTRIBUTES DLLEXPORT ::  TWICE
    IMPLICIT NONE
    INTEGER, INTENT(IN) :: X
    TWICE = 2*X
END FUNCTION TWICE
 
Чтобы оформить ее в DLL, нужно создать соответствующий проект.

При построении DLL-проекта будут, в частности,  созданы файлы с расширением .lib и .dll.

Как вызывать DLL в C# спроси на форуме по С#.

А чтобы использовать DLL в С++ проекте (например, консольном проекте Microsoft Visual С++) следует обеспечить доступ С++ окружению .lib-файла на этапе компиляции, .dll-файла - на этапе выполнения.
Что касается текста С++ программы, то это может быть что-то вроде:
Код

#include <iostream>
using namespace std;
extern "C" __declspec(dllimport)  int TWICE(const int& x);         // прототип фортран-функции
int main() {             
   cout << TWICE(1) << endl;               // 2
   return 0;
}

(Обеспечить доступ к .lib-файлу можно вставив в С++ исходник директиву #pragma comment(lib, "путь_к_lib-файлу"))

Автор: Jon89 13.3.2012, 16:32
Попробовал сделать на с++. Пишет ошибку: Запуск программы невозможен, т.к. на компе отсутствует MSVCRTD.dll
Как посмотреть какой компилятор в Fortran у меня?

Код в Fortran:
INTEGER FUNCTION TWICE (X)
!DEC$ ATTRIBUTES DLLEXPORT ::  TWICE
    IMPLICIT NONE
    INTEGER, INTENT(IN) :: X
    TWICE = 2*X
END FUNCTION TWICE

Код в С++:
#include <iostream>
#pragma comment(lib, "Optim")
using namespace std;
extern "C" _declspec(dllimport)  int TWICE(const int& x);
void main()
{
cout<<10<<endl;
cout << TWICE(1) << endl;
system("pause");
}


Автор: FCM 14.3.2012, 10:43
Для начала, скажи, построил ли ты DLL по фортран-исходнику. Если да, то ругался ли (возможно в  виде предупреждения) компилятор на директиву
!DEC$ ATTRIBUTES DLLEXPORT 
 
Цитата(Jon89 @  13.3.2012,  16:32 Найти цитируемый пост)
Как посмотреть какой компилятор в Fortran у меня?

А как ты вообще с ним работаешь в Visual Studio или как-то по-другому?
Если в Visual Studio, то при создании любого проекта видны все возможные компиляторы, интегрируемые в Studio.
Можно также попhобовать в фортран-исходник добавить вывод специфического для компилятора макроса.
Например, в консольном проекте для Intel Fortran 
Код

PROGRAM DETECT_COMPILER
    WRITE(*,*)  __INTEL_COMPILER
END


PS. В современном С++ функций main должна иметь тип int (а не void) и возвращать целое
Код

...
int main() {
   ...
   return 0;
}


Автор: Jon89 14.3.2012, 17:43
Как я понимаю, я работаю через Developer Studio (хотя в Program files программа лежит в Microsoft Visual Studio). На исходники Fortran не ругался. все нормально откомпилил. получил .dll, .lib и еще несколько  файлов на выходе.

На код:
PROGRAM DETECT_COMPILER
    WRITE(*,*)  __INTEL_COMPILER
END

он ругается так:
Compiling Fortran...
C:\Program Files\Microsoft Visual Studio\MyProjects\Optim\Optim.f90
C:\Program Files\Microsoft Visual Studio\MyProjects\Optim\Optim.f90(3) : Error: Lead underscore not allowed
    WRITE(*,*)  __INTEL_COMPILER
--------------------------------^
C:\Program Files\Microsoft Visual Studio\MyProjects\Optim\Optim.f90(3) : Error: This name does not have a type, and must have an explicit type.   [__INTEL_COMPILER]
    WRITE(*,*)  __INTEL_COMPILER
----------------^
Error executing df.exe.


Прикрепляю скрин из пуска. может может чем нибудь помочь в определении компилятора)))

Автор: FCM 14.3.2012, 19:03
Цитата(Jon89 @  14.3.2012,  17:43 Найти цитируемый пост)
Прикрепляю скрин из пуска. может может чем нибудь помочь в определении компилятора))) 

В скрине же видно, что компилятор Compaq Visual Fortran 6. Это предшественник Intel Visual Fortran. 
Они оба поддерживают DEC-директивы.

Цитата(Jon89 @  14.3.2012,  17:43 Найти цитируемый пост)
На исходники Fortran не ругался. все нормально откомпилил. получил .dll, .lib и еще несколько  файлов на выходе.

Это хорошо.

Цитата(Jon89 @  13.3.2012,  16:32 Найти цитируемый пост)
Попробовал сделать на с++. Пишет ошибку: Запуск программы невозможен, т.к. на компе отсутствует MSVCRTD.dll

Точно не припомню, почему так бывает. Надо разбираться.
1) Посмотри Фортран-проект с DLL и С++ проект с консольным проектом  построены ли в одном и том же режиме (либо оба в Debug, либо оба в Release)?
2) После построения DLL, как ты обеспечиваешь доступность  .dll-файла использующему его С++ приложению?
3) по поводу #pragma comment(lib, "Optim") : Optim.lib находится ли в директории, автоматически просматриваемой С++ окружением в поисках lib-файлов? 

Автор: Jon89 15.3.2012, 13:32
1. Оба построены в режиме Debug
2. Я пока что в ручную копирую оба файла (lib и dll) в папку с исходниками и в Debug (Потом все прикручу к проекту)
3. Да

Скачал файл MSVCRTD.dll в инете,  положил в System32, но похоже он для не для моей ОС (Seven)
1. При регистрации dll в винде "regsvr32 msvcrtd.dll" вылазит:  Модуль "MSVCRTD.dll" загружен, но точка входа DllregisterServer не найдена. Проверьте, что "MSVCRTD.dll" является правильным файлом Dll или OCX и повторите попытку. 

2. Самое приятное что даже не регистрируя dll в системе, она работает, даже в консоли программы появляется ПРАВИЛЬНОЕ решение (умножение на 2), но в процессе запуска вылазит целая гора ошибок и предупреждений. 

Компиляция без ошибок. Запуск программы. Скриншот 1. Нажимаю продолжить. Скриншот 2. В консоли появляется ответ. Потом нажимаю Повтор. Скриншот 3. Нажимаю продолжить. Скриншот 4. 
 
http://imageshost.ru/photo/169495/id1768558.html
http://imageshost.ru/photo/170265/id1768557.html
http://imageshost.ru/photo/162667/id1768556.html
http://imageshost.ru/photo/164917/id1768555.html

Одно радует, что она хотя бы заработала))) Почитал в инете, данная dll связана с RunTime C++.
Пробовал на XP запустить, таже фигня вылазит((

Автор: FCM 15.3.2012, 17:33
По одной из приложенных картинок похоже в Compaq Fortran соглашение о вызове другое - надо бы посмотреть в свойствах проекта, если там есть такой пункт.
Попробуй в прототип фортран-функции в С++ исходнике  добавить спецификацию соглашения о вызове:  __stdcall
Код

...
extern "C" __declspec(dllimport)  __stdcall int TWICE(const int& x); 
...


Можно еще попробовать явно устанавливать соглашение о вызове в фортран-исходнике с помощью DEC-директив.

PS/
Вот еще тут посмотри
http://forum.sources.ru/index.php?showtopic=351171

Автор: Jon89 18.3.2012, 10:12
Огромное спасибо) в с++ заработало. кинул библиотеку MSVCRTD.dll прям в папку с исходниками, чтоб system32 не засорять
Только осталось 2 проблемки
- в x64 не робит данная библиотека. а в инете только такая версия. все перерыл уже
- когда в с# пытаюсь тоже самое сделать, он ругается (строка вызова Twice(2)): Попытка чтения или записи в защищенную память. Это часто свидетельствует о том, что другая память повреждена.

Исходники с#:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        [DllImport("Optim.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern int TWICE(int A);
        

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            
            int b;
            b = TWICE(2);
            int c = b;
        }
    }
}

Автор: FCM 20.3.2012, 12:39
По использованию DLL в C# лучше спроси в соответствующем форуме.

Если будет не лень, после того как заработает отпишись, как должна выглядеть соответствующая С# программа - пригодится кому-нибудь в будущем.  

Автор: Jon89 21.3.2012, 12:40
Рабочий код в С#:

using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsFormsApplication1
{
    
    public partial class Form1 : Form
    {
        [DllImport("Optim.dll")] public extern static int TWICE(ref int A);

        public Form1() {InitializeComponent();}

        private void button1_Click(object sender, EventArgs e)
        {
            int a = 3;
            textBox1.Text = TWICE(ref a).ToString();   
        }
    }
}



FCM, спасибо за помощь с кодом С++)))

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)