Visual Fortran ハンドラがアプリケーションにどのように取り込まれるか,そして,自分独自のハンドラをどのように取り込むかを理解するためには,各アプリケーション・タイプがどのように構成されているかを理解する必要があります。以下の節では,様々なアプリケーション (プロジェクト) タイプに対するハンドラを説明しています。
Fortran Console アプリケーションは,実際には,C main() 関数を提供する Visual Fortran 実行時システムを持つ,フードの下の C アプリケーションのようです。
Fortran Console アプリケーションのエントリ・ポイントは,C ライブラリーの mainCRTStartup() として指定されています (C 実行時ソースのモジュール crt0.c を参照)。これは,C 実行時システムを初期化し,C 実行時例外フィルタ (_XcptFilter()) を使用して Try/Except コンストラクトに Fortran 実行時システム main() をラップし,そして,実行時モジュール for_main.c の Fortran 実行時システム main() を呼び出します。簡単な書式では,以下のようになります。
mainCRTStartup() { C initialization code here __try { more initialization code here mainret = main() /* calls Fortran run-time main() */ exit(mainret) } __except ( _XcptFilter() ) { _exit ( GetExceptionCode() ) } }
Fortran 実行時システムでは,main() は Fortran 実行時システムを初期化し (もし初期化されていなければ),例外で Fortran 実行時システムの基本ハンドラを呼び出すフィルタ式で MAIN__ (Fortran コードへのエントリ・ポイント) で Try/Except コンストラクトをラップし,そして,MAIN__ を呼び出します。Try/Finally コンストラクトをこれのすべてでラップします。そのため,実行時システムのクリーンアップは,プログラムが終了した時に (FOR_RTL_FINISH_ で) 行われます。簡単な書式では,以下のようになります。
main() { __try { __try { for_rtl_init() MAIN__ } __except ( expression-invoking-fortran-default-handler ) { } } __finally { for_rtl_finish() } }
Fortran コードでは,シンボル MAIN__ は実行時システムの main() ルーチンが呼び出すエントリ・ポイントです。MAIN__ は,更なる実行時初期化と検証を行うコードを持っています。たとえば,ユーザーが非基本の /fpe:0 オプションでコンパイルした場合,浮動小数点例外の設定/動作方法を実行時システムに伝えるために,FOR_SET_FPE の呼び出しが行われます。
Fortran QuickWin および Standard Graphics アプリケーション
(Fortran Standard Graphics を含む) Fortran QuickWin アプリケーションは,Visual Fortran が WinMain() 関数を提供する特殊化された Windows アプリケーションです。
QuickWin アプリケーションのエントリ・ポイントは,C ライブラリー・ルーチン WinMainCRTStartup() として指定されます (C 実行時ソースのモジュール crt0.c を参照)。これは,C 実行時初期化を行い,C 実行時例外フィルタ (_XcptFilter()) を使って Try/Except コンストラクトで Visual Fortran 定義の WinMain() をラップし,そして,Visual Fortran 定義の WinMain() ルーチンを呼び出します。簡単な書式では,以下のようになります。
WinMainCRTStartup() { C initialization code here __try { more initialization code here mainret = WinMain() /* calls CVF qwin library WinMain() */ exit(mainret) } __except ( _XcptFilter() ) { _exit ( GetExceptionCode() ) } }
QuickWin ライブラリーでは,WinMain() は QuickWin に特化した初期化を行い,QWINForkMain で実行が開始される新しいスレッドを作成し,そして,動作を行うメッセージ・ループに入ります。メッセージ・ループは,例外が発生すると,Fortran 実行時システムの基本ハンドラを呼び出す Try/Except/Finally コンストラクトにラップされ,終了時に FOR_RTL_FINISH_ を呼び出します。他のスレッドで実行されている QWINForkMain は,順番に MAIN__ を呼び出す Fortran 実行時システム main() を呼び出します。簡単な書式では,以下のようになります。
WinMain() { Initialization code here BeginThreadEx (..., QWINForkMain, ... ) __try { __try { the message loop... for_rtl_finish() return (msg.wParam) } __except ( expression-invoking-default-fortran-handler ) { } } __finally { for_rtl_finish() return (msg.wParam) } }
QWINForkMain は以下に似ています。
QWINForkMain() { main() :/* calls the CVF rtl main() which calls MAIN__ */ cleanup and exit... }
ルーチン main() と MAIN__ は,Fortran Console アプリケーションで説明したものと同じです。
Fortran DLL は,一般的に他の主プログラムから呼び出されれる 1 つ以上のルーチンの集合です。そのため,DLL を呼び出すコードが作成した構造と環境で,ルーチンが実行されます。DllMain() 関数を通して DLL を初期化することができますが,主プログラムからアプリケーション全体の初期化を制御した方がよいでしょう。
DLL では,例外ハンドラを自動的に提供しません。プログラマが自分で提供するものを除いて,環境初期化も行いません。もちろん,主アプリケーションも Fortran で書かれている場合,そのアプリケーション・タイプで提供される Fortran 基本ハンドラを得ることができます。
Fortran Windows アプリケーションは,エントリ・ポイントとして WinMainCRTStartup() を持ちます。各ユーザーは,「Fortran Windows アプリケーションのコーディング要件」の説明に従ってコードを書きます。Fortran コードでの例が提供されているので,書き方をそれから知ることができます。コンパイラは,初期化コードを持つシンボル MAIN__ を生成しますが,MAIN__ を呼び出しません。実行時システムの main() に接続しないので,Visual Fortran 基本ハンドラにフックする Try/Except コンストラクタがありませんし,実行時システムの初期化とクリーンアップもありません。簡単な書式では,以下のようになります。
WinMainCRTStartup() { C initialization code __try { more initialization code mainret = WinMain() /* calls the user's WinMain() */ exit(mainret) } __except ( _XcptFilter() ) { _exit ( GetExceptionCode() ) } }
Fortran コードは以下のようになります。
integer(4) function WinMain( HANDLE, HANDLE, LPSTR, int ) ... ! whatever Fortran the user codes here... ... end