シャノンさん、こんばんは。
「FORTRAN」の場合、引数の渡し方が「C++」でいう
「ポインタ渡し」(=他の言語でいう「参照渡し」)
しかないと決め打ちしてしまいした。(汗)
提案ですが、
まず「C++」コードから、Win32のLoadLibrary(f77dll.dll);等を噛ませ
「DLL」なしの生の「FORTRAN」コードをコールしたらどうなりますか?
これだと「DLL」の問題が除外されるので、純粋に「FORTRAN」と「C」の
インターフェースの問題になりますが、もう、なさったでしょうか?
サイトの来訪者(私も含めて)も楽しみにしています。
皆さんおそろいのようでありがとうございます。
やはり問題は「参照渡し」のようですね。
教科書をひっくり返していたらC++では配列の場合は基本的に参照渡しである。
というような表現がありました。それで、配列の宣言時に*を使いサブルーチン
に渡す際に&を使うとエラーになるのかもしれません。配列は参照渡しという表現を信
用して
typedef void (*Dllsub)(double param[6]);
Dllsub dllsub1;
dllsub1 = (Dllsub)GetProcAddress(hm2,dllf3_);
double mparam[6];
(*dllsub1)(mparam);
CString sampleds;
sampleds.Format(%.2lf,mparam[2]);
pDC->TextOut(0,200,sampleds);
とするとコンパイルは通るのですが配列の中身に値が入っていません。
C++の文法が通ってもフォートランへは参照渡しになっていないということでしょうか。
(配列を明示的に参照渡しにするとエラーになる。)
ここら辺の結論を出すためにもエートリーぶさんの提案はいいかもしれませんね。
しかし、何をすればとなると具体的によくわかりません。とりあえず、この実験はVC++
ではできずにmingwなりのGCC環境でやるようになるのかとは思いますが
あくまでも、(「C++」の)「参照渡し」で行くつもりですネ?(微笑)
だとすると、かなり難しいかと思います。ご存知のように「FORTRAN」には
この機能がありませんので。
打開策として、(「C」でいうところの)配列の先頭アドレスを渡して勝負
かなと思いますが・・・(どうなる???)
いずれにしても、内部の実装に関連する「トリッキー」なコードになるかも。
サイトの来訪者としては楽しみではありますが、夜も更けました。
今は休息が最善かと思います、お体を大切に。おやすみなさい・・・。
> 教科書をひっくり返していたらC++では配列の場合は基本的に参照渡しである。
表現としては「値渡しができない」という方が適切な気が。
> 配列は参照渡しという表現を信用して
配列の名前は暗黙で先頭ポインタに変換されますし、
上のコードでも確かにポインタ渡し(=広義の参照渡し=変更可能)であってます。
> あくまでも、(「C++」の)「参照渡し」で行くつもりですネ?(微笑)
fortran使い さんにそういう拘りは見受けられないようですが.....。
他言語と結合する場合によく extern C 宣言したりしますが、
C++ としては C 以外との互換インターフェイスを特に用意していません。
この種の結合時には C 言語の機能をそのまま使うのが普通です。
そして、C 言語でいう参照渡しとはつまり、ポインタ渡しのことを指します。
相手も普通は C 言語用にインターフェイスを提供してきますし、
FORTRAN においてもおそらくそうなのではないかと思います。(FORTRAN は未経験...)
> 「パスカル型」か「C型」か、どちらになるか実験してください。
FORTRAN にしても C++ にしても、「Windows の DLL」として作成される設定なら
お約束として stdcall ではないかと推測しますが、このコードでは無指定ですね。
> typedef void (*Dllsub)(double param[6]);
> 一応__stdcallもつけてみましたが効果はありませんでした。
とはなってますが、C側は無指定時のデフォルト cdecl だったとして、
FORTRAN 側は(DLL用に?) stdcall になってたりしませんか。
BANさん こんにちは ちょっと混乱しています。C exterm..
を使えばいいのかななんとも思うのですが、基本的に勉強不足でして
試行錯誤がメインになっています。
fortranの方の仕様はよくわかりません。というのはdllhelperの構成が
fortranとCのプログラムとmakefileからなっていて私はfortranのところを
一般的な表現で書いているだけなので(そしてなんとなくやってみたら配列の引数問題
以外はうまくいってしまった。)インターフェースの部分はわかりません。
たぶん以下のCの部分がヒントにはなると思います。
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
#include <stdio.h>
BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason,
LPVOID reserved /* Not used. */ );
BOOL APIENTRY
DllMain (
HINSTANCE hInst /* Library instance handle. */ ,
DWORD reason /* Reason this function is being called. */ ,
LPVOID reserved /* Not used. */ )
{
switch (reason)
{
case DLL_PROCESS_ATTACH:
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
return TRUE;
}
こんな感じです。
もう自力では解決できない領域にきてしまった感じがします。
あと少しお力をお貸しください。
> たぶん以下のCの部分がヒントにはなると思います。
申し訳ありませんが、なりません。
で、今になって気づいたわけですが。
お使いの FORTRAN コンパイラは何です?
あるいは、呼び出したい関数の FORTRAN 側の定義を書くとよいかも。
シャノン さんこんにちは
開発環境は一番初めに書いたとおり
mingw環境でDLLfile を作成するdllhelperで作っています。サイズも小さいし
一見の価値はあると思いますのでダウンロードしてみてはいかがでしょうか。
中身は中核となるfortranとインターフェースのCコンパイルを指定したmakefile
でなっています。fortranの部分は以下のようにしました。
subroutine dllf1 ( mydim )
implicit real*8(a-h,o-z)
dimension mydim(0:5,0:10)
do 100 i = 0 , 5
do 100 j = 0 , 10
mydim(i,j) = 20.0
100 continue
mydim(4,3)=1.4142
return
end
c
subroutine dllf3 ( mydim )
implicit real*8(a-h,o-z)
dimension mydim(0:5)
mydim(0) = 0.0
mydim(1) = 1.0
mydim(2) = 2.0
mydim(3) = 3.0
mydim(4) = 4.0
mydim(5) = 5.0
return
end
c
c
subroutine dllf4 ( param )
implicit real*8(a-h,o-z)
param=4649.0
return
end
c
function dllf5 ( param )
implicit real*8(a-h,o-z)
dimension mydim(0:5)
dllf5=0.0
do 200 i = 0 , 5
dllf5 = dllf5 + mydim(i)
200 continue
return
end
c
c
function dllf2 ()
real dllf2
c
write (*,*) 'in dllf2.'
dllf2 = 3.14159
return
end
ここで間違っていたら恥ずかしいのですが
それから呼び出し規約についてはVC++の方で一通りは試してみたのですが
だめでした。
そっか、mingw だから gcc が標準でついてるのか。
FORTRAN はさっぱりわかりませんが、見よう見まねで…
> implicit real*8(a-h,o-z)
変数名の先頭が a ~ h と o ~ z ではじまるものは、暗黙的に double 型とする、か
な。
この場合、m で始まる mydim の型は何になるんでせう?
> mydim(0) = 0.0
倍精度型の場合、必ず 0.0d0 と書け、と言っているページをいくつか見かけます。
> この場合、m で始まる mydim の型は何になるんでせう?
んー…
i, j, k, l, m, n で始まる名前は、特に定義されていない限り整数型…か?
シャノンさん ありがとうございます。
痛いところをつかれました。fortranは目をつぶってでも書けるという
自負とVC++に対する必要以上の恐怖からとんでもないケアレスミスを
していました。ご指摘のとおり整数型の宣言を直した途端目的どおりの
動作を確認しました。
最終的な結果は以下のとおりです。
typedef void (*Dllsub)(double *param);
Dllsub dllsub1;
dllsub1 = (Dllsub)GetProcAddress(hm2,dllf3_);
double mparam[6];
(*dllsub1)(mparam);
CString sampleds;
sampleds.Format(%.2lf,mparam[2]);
pDC->TextOut(0,200,sampleds);
配列はもともと参照渡しなので&をつけなくてもよい(つけるとエラーになる)
というのが結果でした。
解決までお付き合いいただいた皆様本当にありがとうございました。
ただ、今回やってみて気づいたことはfortranの財産を持っている人が多い割には
情報が少ないということです。
この結果は個人的にまとめてネットで公開しようかと考えています。
今までお付き合いありがとうございました。