Visual C/C++でPROPATHを使う


もし,同一のマシンにVisualC/C++(以下VC)とVisual Fortran(以下VF)が両方インストールされて いるのなら,VFでコンパイルしたオブジェクトファイル(.OBJ)および スタティックライブラリ(.LIB)を,VCのプロジェクトに追加し,Cのコードとリンクさせる ことができる.

さらに,VCとVFのバージョンが整合していれば,すなわち,両方とも5.0あるいは6.0ならば, Developer Studioが共用され,一つのプロジェクトにFortranとCのソースコードを混在させることができる.

しかしながら,VCのみの環境では,VFで作成したOBJやLIBを利用することはできない. VFで作成されたOBJおよびLIBは,メインプログラムにリンクされるときに, VFが提供するdfor.lib,dfconsol.lib,dfport.libなどのライブラリを必要とする. これらのスタティックライブラリはCompaq社が再配布を認めていないので,

VFがインストールされていない環境では VFで作成したOBJやLIBを利用することができない

のである. ここにも書いたが, VFのDeveloper Studioで作成したプログラムを実行するには, VFが提供するランタイムライブラリが必要である. こちらの方はCompaq社のサイトから ダウンロードすることができる.

VCのみの環境では,他の言語と同じく,E-PROPATHが提供するDLLを利用することになる. なお,E-PROPATHが提供するDLLは単独で使用できるようにコンパイルされているので, 上で述べたランタイムライブラリは必要はない.

以下,三つの場合について,VCからの利用法をまとめておく.

Developer Studioが共用できる場合
VCとVFが両方インストールされている場合
PROPATH DLLをVCから利用する方法


Developer Studioが共用できる場合

この場合はVCのプロジェクトにFortranのソースコードを直接追加することができる. 例えば,アンモニアPROPATHのKPAMESとPSTをCで書かれたメインプログラムから 呼び出す場合,JNH3.FORをプロジェクトに追加し,メインプログラムは 以下のように書く.

#include <stdio.h>

extern "C" void _stdcall KPAMES( int* kpa, int* mes );
extern "C" float _stdcall PST( float* t );

void main()
{
   float t, ps;
   int kpa = 1, mes = 1;

   KPAMES( &kpa, &mes );

   t = 1e2;
   ps = PST( &t );
   printf( "ps = %10.5f\n", ps );	

}

関数名のKPAMESとPSTは必ず大文字で宣言する. この場合も呼出し規約として_stdcallを指定するが, ソースコードレベルでは関数への引数の渡し方がその関数を記述している言語に依存する. したがって,Fortranで記述された 関数およびサブルーチンを呼び出す際は, 呼出し側で引数をすべてポインタとして宣言しなければならない.

通常通りメイクすれば実行ファイルができあがる.


VCとVFが両方インストールされている場合

この場合は,まずVFでOBJファイルかLIBファイルを作っておき,これを VCのプロジェクトに追加すればよい. Cのコードの書き方はDeveloper Studioが共用できる場合と同じである.

コマンドラインでやる場合は以下のようになる.

  1. まず,次のような C のコードを書き,main.c として保存する.

    #include <stdio.h>
    
    void _stdcall KPAMES( int* kpa, int* mes );
    float _stdcall PST( float* t );
    float _stdcall HPT( float* p, float* t );
    
    void main(){
    
        float t, ps, p, h;
        int kpa = 1, mes = 1;
    
        KPAMES( &kpa, &mes );
    
        t = 2e2;
        p = 1e0;
        ps = PST( &t );
        h = HPT( &p, &t );
        printf( "ps = %10.5f\n", ps );	
        printf( "h  = %10.5f\n", h * 1e-3 );	
    
    }
    

    PROPATH 側の関数の引数はすべてポインタとして宣言する.

  2. cl.exe を使って main.c をコンパイルする.

    cl /c main.c
    

  3. 次に,fl32.exe を使って JH2O.FOR をコンパイルする.

    fl32 /c jh2o.for
    

  4. 同じディレクトリに main.obj と jh2o.obj ができているのを確認し,

    link main.obj jh2o.obj
    

    とすれば,main.exe が出来上がる.これを実行すれば,

    ps =   15.54880
    h  = 2875.35725
    

    と表示される. なお,スタティックライブラリ(.lib)をリンクする場合も,

    link main.obj jh2o.lib
    

    とすればよい. 関数宣言の注意点を以下にまとめておく.


PROPATH DLLをVCから利用する方法

動的リンク

E-PROPATHにはVCからDLLを呼び出すためのインポートライブラリは含まれないので, VCでDLLを呼び出す場合は,必然的に動的呼出しになる.

以下にプログラム例を示す.この例では,水のDLLをロードして,KPAMES,PSTおよび HPT 関数へのアドレスを取得し,100degにおける飽和蒸気圧と200deg,10barにおける 比エンタルピーおよび比エントロピーを計算している.

#include <windows.h>
#include <stdio.h>

typedef void  ( CALLBACK* PROPATH_KPAMES )( int, int );    // KPAMESを呼び出すための関数ポインタ型
typedef float ( CALLBACK* PROPATH_FUNC1 )( float );        // PSTを呼び出すための関数ポインタ型
typedef float ( CALLBACK* PROPATH_FUNC2 )( float, float ); // HPTおよびSPTを呼び出すための関数ポインタ型

void main(){

   HINSTANCE hDLL;
   PROPATH_KPAMES kpames;
   PROPATH_FUNC1 func1;
   PROPATH_FUNC2 func2;
   float t, p, ps, h, s;
   int kpa = 1, mes = 1;

   hDLL = LoadLibrary( "jh2o.dll" );  // DLLをロード
   if ( hDLL != NULL ){

       kpames = ( PROPATH_KPAMES )GetProcAddress( hDLL, "KPAMES" ); // KPAMESのアドレスを取得
       kpames( kpa, mes );

       t = 1e2;
       func1 = ( PROPATH_FUNC1 )GetProcAddress( hDLL, "PST" ); // PSTのアドレスを取得
       ps = func1( t );
       printf( "ps = %10.5f [bar]\n", ps );	

       t = 2e2; p = 1e1;
       func2 = ( PROPATH_FUNC2 )GetProcAddress( hDLL, "HPT" ); // HPTのアドレスを取得
       h = func2( p, t );
       func2 = ( PROPATH_FUNC2 )GetProcAddress( hDLL, "SPT" ); // SPTのアドレスを取得
       s = func2( p, t );
       printf( "h  = %10.5f [kJ/kg]\n", h * 1e-3 );
       printf( "s  = %10.5f [kJ/kgK]\n", s * 1e-3 );

       FreeLibrary( hDLL ); // DLLを解放
    }
}

実行結果は,

ps =    1.01325 [bar]
h  = 2826.78775 [kJ/kg]
s  =    6.69216 [kJ/kgK]

となる.

Windows API を使うので,windows.hをインクルードし, GetProcAddress の戻り値を格納する適当な関数ポインタ型を最初に定義する. E-PROPATHが提供するDLLの関数の整数引数および実数引数はすべて値渡しで, 文字引数はヌル終端文字配列へのポインタである.

もう一つ例を示しておく. 以下のコードは水およびアンモニアのDLLをロードして,100degにおける 飽和蒸気圧を両方の物質に対して計算するものである.

#include <windows.h>
#include <stdio.h>

typedef void  ( CALLBACK* PROPATH_KPAMES )( int, int );
typedef float ( CALLBACK* PROPATH_FUNC1 )( float );
typedef float ( CALLBACK* PROPATH_FUNC2 )( float, float );

void main(){

    HINSTANCE hDLL_h2o, hDLL_nh3;
    PROPATH_KPAMES kpames_h2o, kpames_nh3;
    PROPATH_FUNC1 pst_h2o, pst_nh3;
    float t = 1e2, ps_h2o, ps_nh3;
    int kpa = 1, mes = 1;

        hDLL_h2o = LoadLibrary( "jh2o.dll" );
        hDLL_nh3 = LoadLibrary( "jnh3.dll" );

        if ( ( hDLL_h2o != NULL ) && ( hDLL_nh3 != NULL ) ){

           kpames_h2o = ( PROPATH_KPAMES )GetProcAddress( hDLL_h2o, "KPAMES" );
           kpames_nh3 = ( PROPATH_KPAMES )GetProcAddress( hDLL_nh3, "KPAMES" );
           kpames_h2o( kpa, mes );
           kpames_nh3( kpa, mes );

           pst_h2o = ( PROPATH_FUNC1 )GetProcAddress( hDLL_h2o, "PST" );
           pst_nh3 = ( PROPATH_FUNC1 )GetProcAddress( hDLL_nh3, "PST" );
           ps_h2o = pst_h2o( t );
           ps_nh3 = pst_nh3( t );
           printf( "water    ps = %10.5f [bar]\n", ps_h2o );
           printf( "ammnonia ps = %10.5f [bar]\n", ps_nh3 );

           FreeLibrary( hDLL_h2o );
           FreeLibrary( hDLL_nh3 );
        }

}

こちらの実行結果は,

water    ps =    1.01325 [bar]
ammnonia ps =   62.35048 [bar]

となる. この例のように,一度に二つ以上のDLLをロードすることも可能である.

静的リンク

VCのコードと静的リンクが可能なDLLの作成方法を示す. まず,DEFファイルに以下のような記述を追加する.

_PST@4    =  JH2O_PST
_HPT@8    =  JH2O_HPT

各PROPATH関数はALIAS指定によって"J+(物質名)_(関数名)"の名前でエクスポートされているが, これを"_(関数名)@(スタックのサイズ)"という名前でも呼び出せるようにする. Micrsoft系コンパイラ特有の関数名修飾のためにこのような操作が必要になる. このDEFファイルでDLLをメイクする. 次バージョンのE-PROPATHには,VCからも利用できるDLLとインポートライブラリを追加する予定である.

次に,以下の内容のヘッダファイルを作成する.

#define DLLIMPORT __declspec( dllimport )

#ifdef __cplusplus
extern "C" {
#endif

DLLIMPORT void __stdcall KPAMES( int, int );

DLLIMPORT float __stdcall HPT( float, float );
DLLIMPORT float __stdcall PST( float );

#ifdef __cplusplus
}
#endif

ここでは,__cplusplus指定を参照することによって,CとC++の両方のコードから利用できるようにしている. このヘッダファイルをppropath.hなどの名前で保存する. P-PROPATH,A-PROPATHおよびM-PROPATHの完全なヘッダファイルは,以下からダウンロードできる.

呼出し側は次のように書く.

#include <stdio.h>
#include "ppropath.h"

void main (int argc, char *argv[])
{
   int kpa = 1, mes = 1;
   float t, ts, p, h, hd, hdd, tc, pc;
   
   KPAMES( kpa, mes );

   t = 1e2;
   ps = PST( t );
   printf( "ps = %10.5f\n", ps );
}

このコードをmain.cppなどの名前で保存する. jh2o.dllのインポートモジュールであるjh2o.libとリンクするには,

cl main.c jh2o.lib

とする. Developer Studioを使う場合は,プロジェクトにjh2o.libを追加する. ただし,この場合はバージョンの整合性が必要になるようである. すなわち,例えば,VC5のDeveloper Studio上で用いることのはVF5で作成したLIBだけであり, VF6で作成したものはリンク時にエラーが発生する. Compaq社もバージョンが整合したVCとVFを使うことを推奨している.


お問い合わせはメールにて: akasaka@klc.ac.jp

戻る
SEO [PR] 爆速!無料ブログ 無料ホームページ開設 無料ライブ放送