Translate

2016/04/18

作ってみようTRNSYSコンポーネント C/C++編(6) ヘッダーファイル

だいぶ間が空いてしまいましたが、「作ってみようTRNSYS.JPコンポーネント C/C++編」シリーズの続きです。

 

TRNSYS16 vs TRNSYS17

TRNSYS16までのコンポーネント開発では、INFO()配列のデータを使って処理の制御やデータの設定を行っていました。TRNSYS17以降では専用の関数が用意されたため、ソースコードの可読性が非常に高くなりました。ただし、残念ながらこれはFORTRANのみのサポートになります。とはいえ関数自体はC/C++からも呼び出すことが可能です。ヘッダーファイルへ適切な宣言を行うことで利用可能です。(これTRNSYSに限らず、FOTRANのサブルーチンや関数をC/C++から利用するお話です。FOTRANの資産をC/C++でご利用になりたい向きも当てはまる話です)

という訳で、ヘッダーファイルの作り方など解説してみたいと思います。

 

1.TRNSYSの関数名を取得する

公開されているTRNSYSの関数名を取得します。TRNSYSの関数はTRNDLL.DLL(C:TRNSYS17\Exe\TRNDLL.DLL)にすべて含まれていますが、FORTRANで利用する際とは異なる名前で公開されている関数が複数存在します。C/C++から呼び出すため、関数名をTRNDLL.DLLより直接取得します。関数名の取り出しはVisual Studioに含まれる開発ツールを使用して行います。

はじめに、開発ツールを使用するための準備を行います。キーボーから[Win]+[R]をクリックして表示されるダイアログで"cmd"と入力してコマンドプロンプトを起動します。

2016-04-18_17h51_48

コマンドプロンプトから以下のバッチファイルを実行して、開発ツールの利用環境を整えます。以下、Visual Studio 2013がインストールされたPCの作業例です。

> "C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\Tools\vsvars32.bat"

つづいて、dumpbin.exeを使って、TRNDLL.DLLから関数名のリストを取得します。

> cd C:\TRNSYS17\Exe

> dumpbin /exports TRNDLL.DLL > trnsysfunctions.txt

これでtrnsysfunctions.txtに関数名がすべて書き出されました。

image

 

2.関数定義の確認

関数の引数や戻り値を調べるためFORTRANの関数定義を確認します。TRNSYSのすべて関数のソースコードは「C:\TRNSYS17\SourceCode\Kernel」フォルダに格納されています。これらのソースコードから、関数を定義しているソースコードを特定、定義内容を確認します。

ここでは、C/C++のソースコードの以下の箇所(コンポーネントのバージョン宣言処理の判定)に対応する関数getIsVersionSigningTime()を例に定義箇所を探してみます。(info配列と関数の対応はドキュメント「7.2. Updating TRNSYS 16 Components to the TRNSYS 17 Coding Standard」を参考にして調べます。)

//    SET THE VERSION INFORMATION FOR TRNSYS
      if (info[6]== -2) ←この部分をTRNSYS17形式の関数にします。
    {
       info[11]=16;
     // add additional initialisation code here, if any
       return 1;
    }

コマンドプロンプトから次のように入力して定義箇所を検索します。

> cd c:\Trnsys17\SourceCode\Kernel

> findstr /i "getIsVersionSigningTime" .\*.f90 | findstr /i "DLLEXPORT"

.\TrnsysFunctions.f90: !dec$ attributes dllexport :: getIsVersionSigningTime

>

image

実行すると、関数を含むファイルの名前と定義されている行が表示されます。この例では「TrnsysFunctions.f90」に関数が含まれていることが分かります。

ソースコード調べると引数なし、戻り値はIntegerで定義されていることが分かります。

image

さらに、1.で作成したリストから公開されている関数名を確認します。メモ帳などでtrnsysfucntions.txtを開いて、"getIsVersionSigningTime" を検索してみると。。。

2016-04-18_18h39_35

"TRNSYSFUNCTIONS_mp_GETISVERSIONSIGNINGTIME"という名前で公開されている事が分かります。(なんでこんな長い名前で公開されているかは謎ですが。。。)

3.ヘッダーファイルへ定義する

必要な情報が整ったので、いよいよ関数の定義を追加します。ここで目的の関数「getIsVersionSigningTime」の情報を整理すると。。。

  • 引数:なし
  • 戻り値:Integer
  • 名前:"TRNSYSFUNCTIONS_mp_GETISVERSIONSIGNINGTIME"

ここまで分かればC/C++の関数として定義できます。

具体的には、戻り値は整数(int)、引数はなし(void)として次のような定義になります。

extern "C" __declspec(dllimport) int _cdecl TRNSYSFUNCTIONS_mp_GETISVERSIONSIGNINGTIME(void);

しかし、これだと関数名が長くて、しかも大文字だらけで読みにくいので別名を定義します。

#define getIsVersionSigningTime            TRNSYSFUNCTIONS_mp_GETISVERSIONSIGNINGTIME

これでC/C++のソースコードから"getIsVersionSigningTime()"として呼び出すことができるようになります。次のようなイメージでソースコードを書き換える事ができるようになります。

//    SET THE VERSION INFORMATION FOR TRNSYS
   if (getIsVersionSigningTime())
   {
       info[11]=16;
     // add additional initialisation code here, if any
       return 1;
    }

でも、これたぶんエラーになります。TRNSYS17形式に書き換える場合、他の関数も同じように書き換える必要があります。この例ではinfo[11]へ値を設定していますが、これも関数に置き換える必要があります。

今回はヘッダーファイルを準備する基本的な流れと言うことで、たぶん次回へつづく。

----------------------------------------------------

以下、このシリーズの目次

作ってみようTRNSYSコンポーネント C/C++編
(1) 基本情報
(2) ソースコードの生成
(3) ソースコードを読んでみよう
(4) Simulation Studioで実行してみよう
(5) コンポーネントが呼び出されるタイミング
(6) ヘッダーファイル・基本編
(7) ヘッダーファイル・実践編

0 件のコメント:

コメントを投稿