************************************************************************
                        TeX DLL for Windows 95/NT
                               TeX 3.14159
                             ASCII pTeX 2.1.7
                            Web2c version 7.0
                            DLL version 1.0.3
                Copyright (C) 1997-1998, Kazunori Asayama

                          アプリケーション開発

************************************************************************

1). はじめに

  TeX DLL を用いたアプリケーションプログラムの開発方法について説明しま
す。

  アプリケーションの開発に必要なヘッダファイルやインポートライブラリは
TeX DLL のインストール先のサブディレクトリ develop に含まれています。


2). TeX DLL を用いたプログラムの開発

  TeX DLL は、GUI の開発のために以下のような機構を用意しています。なお、
簡単のため、オリジナルの TeX についてのみ記してありますが、これらの関
数名の `TeX' の部分を必要に応じて PTeX 等に読み換えて下さい。

  a). 準備

      HTeX WINAPI TeXInitialize(LPFTeXCallbackProc lpfCallback,
	                        LPVOID lpCallbackData,
                                LPCSTR lpcszWorkDir)

      主処理のための準備を行ないます。主処理をおこなう前に「毎回」
      この関数を呼び出す必要があります。
      この関数が返すポインタは以降の関数呼びだしで使われますので
      どこかに記憶させておいて下さい。

      引数:

        ○ LPFTeXCallbackProc lpfCallback;

          DLL と UI との間の情報交換のために DLL が呼び出す関数です。
          詳細は後述します。この値が NULL の場合にはデフォルトの関数 (何もしない)
          が用いられます。このとき、次の引数 lpCallbackData は無視されます。

        ○ LPVOID lpCallbackData;

          lpfCallback を DLL が call する時に引数として渡します。
          この引数は TeX DLL では解釈しません。 lpfCallback で必要なデータの
          ポインタを与えて下さい。

          lpfCallback は、アプリケーションが TeXInitialize() を呼び出した
          スレッドと同じスレッドから呼ばれるとは限りません
          (TeX DLL が内部的に使用するスレッドを生成し、
          そこから呼ばれることがあります)。従って、lpCallbackData として
          有効なポインタを与える場合には、スタック上に確保された
          オブジェクトへのポインタは渡さないようにしてください
          (かならず Heap など、スレッドをまたいで有効な領域に確保しなければ
          ならないということです)。

        ○ LPCSTR lpcszWorkDir

           作業ディレクトリ。TeX DLL は主処理をおこなうときにカレント
           ディレクトリをここで指定された lpcszWorkDir に移動します (厳密には
           ディレクトリの移動はおこないません。あたかもカレントディレクトリが
           lpcszWorkDir に移動されたかのようにファイルの入出力をおこないます)。

           作業ディレクトリがプロセスのカレントディレクトリでよい場合には、
           lpcszWorkDir として NULL を渡してください。

      返値:

        実行コンテキスト。値は DLL が内部的に利用するだけですので
        その意味について知る必要はありません (意図的に、知ることが
        出来ないようにしてあります。とはいえ、ソースを公開していますので
        知ることは可能なのですが、TeX DLL のバージョン毎に構造が異なると
        考えてください)。

        初期化に失敗した場合には NULL を返しますのでそのチェックだけは
        忘れないようにして下さい。

  b). 主処理

      LONG WINAPI TeXMain(HTeX hTeX, LONG lArgc, LPCSTR lpcszArgv[])
      LONG WINAPI TeXVaMain(HTeX hTeX, LPCSTR lpcszProgName, ...)

      メイン関数です。TeXMain は C の main 関数と同様の引数をとります。
      TeXVaMain は可変引数版です。

      引数:

        ○ HTeX hTeX;

          TeXInitialize() 関数の返値を渡します。

        ○ LONG lArgc;
        ○ LPCSTR lpcszArgv[];

           CUI 版の TeX でいうところのコマンドライン引数を渡します。

           例えば、

             COMMAND-PROMPT> initex \input plain.tex \dump

           に相当する処理をする場合には、

             lArgc = 2;
             lpcszArgv[0] = "initex";
             lpcszArgv[1] = "\input plain.tex \dump";

           として、TeXMain() 関数を呼び出します。lpcszArgv[0] には、コマンド名
           (例えば "initex") を指定します。特に VirTeX では
           この lpcszArgv[0] によりデフォルトのフォーマットファイル名
           (&format が 指定されなかった場合のフォーマットファイル) が決定され
           ます。

           デフォルトでは lpcszArgv[0] が "initex" の場合には IniTeX として、
           それ以外のときには VirTeX として動作します。
           "initex" 以外の場合にも IniTeX として動作させたい場合には、
           lpcszArgv[1] に "--ini" という文字列を与えてください。

             lArgc = 3;
             lpcszArgv[0] = "myinitex";
             lpcszArgv[1] = "--ini";
             lpcszArgv[2] = "\input plain.tex \dump";

           IniTeX として動作させたい場合には常に "--ini" を指定するようにして
           おくのが無難です。

        ○ LPCSTR lpcszProgName;
        ○ ...

           lpcszProgName にはプログラム名 (argv[0] に相当) を指定します。
           可変部にはそれ以外の引数(文字列)を指定します。可変部の最後は
           NULL でターミネートします。

           たとえば、

             COMMAND-PROMPT> initex \input plain.tex \dump

           に相当する処理をする場合には、

             TeXVaMain(hTeX, "initex", "\\input plain.tex \\dump", NULL);

           のようにこの関数を呼び出します。

      返値:

          処理が正常に終了した場合には 0 を返します。
          それ以外の値が返された場合にはエラー終了です。

  c). 後処理

      必要な処理 (主に TeXMain() 関数) が終ったら後処理関数を呼び出します。

        void WINAPI TeXUninitialize(HTeX hTeX);

      処理が終ったら必ずこの関数を呼び出して下さい。
      TeXInitialize() が成功した場合には、他の関数の呼び出しの有無、成否に
      関わらず、必ず呼び出す必要があります。呼び出すのを忘れた場合、
      最悪の場合、(プロセス内で)デッドロックが起こります。特に、
      TeX を走らせているスレッドを強制終了するようなことは避けるように
      心掛けてください。もし、TeX の処理を中断したい場合には、
      後述の「インタラプション」の項目を参考に、TeX DLL に中断用の
      メッセージを送るようにしてください。

      実行コンテキスト (引数 hTeX) が有効なのは、前述の
      TeXInitialize() を呼び出してから、この TeXUninitialize() を
      呼び出すまでの間のみです。実行コンテキストを引数とする関数は
      この間に呼び出すようにしてください。また、これら実行コンテキストを
      引数とする関数が返すポインタもこの間だけ有効です。後々必要に
      なる場合には、値をアプリケーション側で確保した領域に
      コピーして使うようにしてください。

      引数:

        ○ HTeX hTeX;

           TeXInitialize() 関数の返値を渡します。

      返値:

        なし。

  d). コールバック

      DLL と UI 部の間の情報交換にはコールバックを用います。
      初期化関数の引数 lpfCallback です。この関数は以下の型を持ちます。

      LONG WINAPI CallbackFunction(TeXDLLMessage msg,
         DWORD dwParam1, DWORD dwParam2, LPVOID lpCallbackData)

      このコールバック関数の役割は大きく分けて次の 3 種類があります。

        i).   ターミナル I/O
        ii).  エディタやフォント生成プログラム (MakeTeX) の起動
        iii). METAFONT のオンラインディスプレイ

      コールバック関数が呼ばれた時、その関数内で行なうべき処理は
      引数 msg が示します。どのような msg の値があるかは texdll.h を
      ご覧下さい。ここではそのうち主なもののみを説明します。

      また、このコールバックの具体的な実装については付属の cuitex.c を
      ご覧下さい。

      コールバック関数のパラメータとしてポインタが渡されることがあります。
      このポインタは、「コールバック関数内でのみ有効」であることに注意
      して下さい。コールバック内でこのポインタを保存しておいて
      後でそのポインタを利用するということは「できません」。
      必要な場合にはデータのコピーをとっておくことで対処して下さい。

      コールバックルーチンは、メッセージを処理しない場合には 0 を
      返すようにしておいてください。処理をおこなった場合には
      各メッセージ毎に指定された値を返すようにしてください。

        i). 文字列の出力

         引数 msg が TeXDLL_CONSOLE_WRITE の場合にはターミナルへの文字列の
         出力をおこないます。ターミナルのフラッシュも同時におこなって
         ください。
         この時、引数 dwParam1 には文字列へのポインタ、dwParam2 には文字列の
         長さが渡されます。dwParam1 は LPCSTR 型にキャストして用います。
         渡される文字列の最後には C 言語の文字列の null 文字が付加されますが、
         dwParam2 で渡される文字列の長さには null 文字のぶんは含まれません。
         一度に渡される文字列の末尾はマルチバイト文字の 1 バイト目で途切れる
         ことはありません (必ず 2 バイト目までがまとめて一回の
         TeXDLL_CONSOLE_WRITE メッセージで送信されます)。
         返値は無視されます。

         TeXDLL_STDOUT_WRITE の場合には標準出力への出力です。引数の意味は
         TeXDLL_CONSOLE_WRITE と同じです。標準出力とコンソールの違いや扱いは
         この DLL を利用するアプリケーションに依存するでしょうから特に規定は
         していません。それぞれのアプリケーションに適した処理をしてください。

       ii). 1 文字取得

         引数 msg が TeXDLL_CONSOLE_GET の場合にはコンソールから 1 文字を
         取得します。取得した文字はコールバック関数の返値として返して下さい。
         通常はアプリケーション側で一行分まとめてユーザ入力を受け取りそれを
         バッファリングしておいて、そのうちの一文字を順に返すようにします。
         行末の改行文字も返す必要があります。改行文字は LF 一文字です (CR は
         付けないでください)。入力がない場合には -1 を返します。
         dwParam1 および dwParam2 の値は意味を持ちません。

      iii). エディタの起動

         引数 msg が TeXDLL_INVOKE_EDITOR の場合には、コンソールから
         'e' が入力されてエディタの起動が要求されたことを表します。
         dwParam1 にはファイル名へのポインタ、dwParam2 には 1 から始まる
         行番号が渡されます。dwParam1 は LPCSTR 型にキャストして用います。
         返値は無視されます。このメッセージは、(実際に外部エディタを起動する
         のではなく) GUI でエラー行にジャンプするような機能を実装するのにも
         用いることが出来ます。ただし、コールバックから復帰するまで
         TeX DLL は終了しませんので、通常は、このメッセージではファイル名と
         行番号を保存するだけにとどめ、DLL での処理が終了した時点で (Main
         関数が終了した時点で) 問題の個所へジャンプするのがよいでしょう。

       iv). MakeTeX* の起動

         ファイル探索ルーチン (Kpathsearch) から MakeTeXPK 等の起動が
         要求されたときには TeXDLL_BEGIN_MAKETEX メッセージが送られます。
         このメッセージは dwParam1 には kpathsea.dll の
         コールバックルーチンに渡される引数 (kpse_maketex_type 構造体への
         ポインタ) をそのまま渡します。dwParam2 は使われません。
         構造体の意味については桃薗版 Kpathsea.dll のドキュメントを
         ご覧ください。

         TeXDLL_BEGIN_MAKETEX メッセージに対して 0 を返すと、
         標準の MakeTeX* ルーチンが用いられます。アプリケーションにより
         独自の処理をする場合には、その処理をおこない、処理終了後に
         成否によって 1 (成功) または -1 (失敗) を返してください。

         TeXDLL_END_MAKETEX は標準の MakeTeX* ルーチン呼び出しが
         終了した場合に送られます。アプリケーション独自の処理を
         おこなった場合 (TeXDLL_BEGIN_MAKETEX に対して 0 以外の
         値を返した場合) にはこのメッセージは送られません。

        v). METAFONT のオンラインディスプレイ

         この種のメッセージは、MFMain() / MFVaMain() 関数のみです。
         オンラインディスプレイをサポートしないアプリケーションでは
         TeXDLL_MFDISPLAY_INITIALIZE を除いて単に無視してください。
         オンラインディスプレイ用のメッセージは全部で 6 種類あります。

         オンラインディスプレイは、デバイスコンテキストを用いて
         描画を任せてしまう方法と、すべてアプリケーション側で
         面倒を見る方法とがあります。

         ○ TeXDLL_MFDISPLAY_INITIALIZE

            画面の初期化をおこないます。パラメータ dwParam1 と dwParam2 は
            意味を持ちません。初期化に成功した時には 1、失敗した時には
            0 をコールバック関数の値としてそれぞれ返してください。

            オンラインディスプレイをサポートしない場合にはこのメッセージ
            に対して値 0 (失敗) を返してください。以後、TeXDLL_MFDISPLAY_*
            というメッセージは送られてこなくなります。

         ○ TeXDLL_MFDISPLAY_BEGINCHAR

            一文字の描画が始まる直前に呼び出されます。
            デバイスコンテキストを用いて描画をさせたい場合には返値として
            デバイスコンテキスト (HDC) を返してください。デバイスコンテキスト
            を用いない場合には 0 を返します。
            ここで渡すデバイスコンテキストは文字の描画が終わるまで
            (TeXDLL_MFDISPLAY_ENDCHAR メッセージが次回送信されるまで)
            有効なものでなければなりません。
            パラメータ dwParam1 と dwParam2 は意味を持ちません。

         ○ TeXDLL_MFDISPLAY_ENDCHAR

            一文字描画が終る毎に呼び出されます。パラメータ dwParam1 と
            dwParam2 は意味を持ちません。返値は無視されます。
            一文字描画を終える毎にポーズを入れるような場合にはここで
            その処理を行います。

         ○ TeXDLL_MFDISPLAY_CLEAR

            TeXDLL_MFDISPLAY_BEGINCHAR に対して、デバイスコンテキストを
            返さなかった場合にのみこのメッセージが送信されます。

            矩形領域を消去する時に呼び出されます。領域を表す座標は dwParam1 に
            RECT 構造体へのポインタとして渡されます。dwParam2 は意味を持ち
            ません。
            
            返値は無視されます。

         ○ TeXDLL_MFDISPLAY_PAINT

            TeXDLL_MFDISPLAY_BEGINCHAR に対して、デバイスコンテキストを
            返さなかった場合にのみこのメッセージが送信されます。

            1 ラスタラインを描画します。データは MFDisplayRaster 構造体と
            して与えられ、dwParam1 にそのポインタが渡されます。
            dwParam2 は意味を持ちません。

            MFDisplayRaster は texdll.h 内で定義されており、各フィールドは
            以下のような意味を持ちます。

              BOOL  bBlack  黒から始まる時は TRUE、白からの時は FALSE
              DWORD dwRow   ラスタ番号。最上のラスタラインが 0。
              DWORD dwVectorSize
                            データ配列の要素数
              LPDWORD lpdwVector
                            データ配列へのポインタ。
                            連続する黒または白の点の最左点の座標の配列。
                            ラスタラインの左端の座標が 0。
                            黒と白が交互に並ぶ。
                            最後の要素には、ラスタの最右点の座標 + 1 が
                            入る。

            返値は無視されます。

            例えば、第 50 行が次のようなラスタラインの場合...

             (0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 )
              ●●●●○○●○○○○○○○○●●●●●●●○○

            この場合、黒の点から始まるので bBlack は TRUE。
            dwRow はラスタ番号の 50。
            dwVectorSize は、黒と白の固まりが 6 個あるので 7。
            lpdwVector の配列は、黒または白の固まりが、順に

              0, 4, 6, 7, 15, 22

            から始まっているので、

              0, 4, 6, 7, 15, 22, 24

            という長さ 7 の配列 (7 番目の要素は、最右点の座標 + 1)。

         ○ TeXDLL_MFDISPLAY_UNINITIALIZE

            全ての表示が終了する時に呼び出されます。画面の後始末はここで
            行います。dwParam1 dwParam2 は意味を持ちません。返値は無視されます。

  e). インタラプション

      インタラプションは Windows メッセージによって実現しています。

       ※ この機能は TeX/pTeX/METAFONT/MetaPost/MFtoPK のみです。

       TeX DLL は、実行時にスレッドを新規に生成し、そのスレッドに属する
       不可視な window を作成します。この window へ SendMessage や
       PostMessage などを用いてインタラプションを意味するメッセージを
       送ることによって TeX や METAFONT のインタラプション機能が実現
       できます (単に スレッド + PostThreadMessage にしなかった理由は、
       スレッド間同期を簡単に SendMessage 関数の使用だけで実現したかった
       ためです)。

       メッセージの送り先となる window は、TeXGetWindow() 関数の返値として
       得ることができます。TeXGetWindow() の返値は TeXInitialize() 呼出しの
       後で有効です。

       今のところ、メッセージとしてはインタラプションと中断しか用意して
       ありませんが、将来的にメッセージの種類が増えることがあります。

       インタラプション等のメッセージは、texdll.h の中でその名前が定義して
       あります。実際にメッセージを使用するにはあらかじめ Win32 API 関数の
       RegisterWindowMessage() を用いて、名前に対応するメッセージ ID を
       取得してください。

          メッセージ名    TeXDLL_WM_TEXDLL

       TeX DLL への要求の内容は SendMessage / PostMessage の wParam の値で
       指定します。wParam の値は以下のとおりです。

          インタラプション   TeXDLL_MESSAGE_INTERRUPT
          中断               TeXDLL_MESSAGE_KILL

       インタラプションと中断との違いは、中断の場合にはユーザの入力待ちを
       しないという点だけです。

       lParam は今のところ使用されていませんが、上記メッセージに関しては
       0 を渡すようにしてください。
       
       例えば次のように用います。

       DWORD wm_texdll;
       
       void CallTeX(void)
       {
         HTeX hTeX = TeXInitialize(callback, callback_data, NULL);
         HWND hWnd = TeXGetWindow(hTeX);
         wm_texdll = RegisterWindowMessage(TeXDLL_WM_TEXDLL);
            :
         VaTeXMain(hTeX, "latex", "sample.tex", NULL);
            :
       }

       void InterruptTeX(HWND hWnd)
       {
         PostMessage(hWnd, wm_texdll, TeXDLL_MESSAGE_INTERRUPT, 0);
       }

  f). ジョブ名

        ※ この機能は TeX/pTeX/METAFONT/MetaPost/MFtoGF のみです。

      ジョブ名は、メイン関数終了後に TeXGetJobName() 関数を用いて
      取得できます。TeXGetJobName() の引数には TeXInitialize() 関数の
      返値を指定します。

        LPCSTR lpcszJobName = TeXGetJobName(hTeX);

      ジョブ名が得られないうちにメイン関数を終了した場合には NULL が
      返されます。

      この関数は、後処理関数 (TeXUninitialize() 関数) を呼び出す前に
      利用して下さい。

  g). 出力ファイル名

        ※ この機能は TeX/pTeX/METAFONT/MetaPost/MFtoGF のみです。

       ジョブ名と同様に取得できます。TeXGetJobName の代わりに
       TeXGetOutputFileName() を用いて下さい。

  h). バージョン

      DLL のバージョン、DLL とアプリケーション間の API のバージョン、
      及び TeX 等のバージョンは、DLL のバージョンリソースを参照する
      ことで得ることが出来ます。

      バージョンリソースを得るには、DLL のファイル名が必要ですが、
      これは以下の関数を使って知ることが出来ます。

        LPCSTR TeXGetLibraryFileName(void);

      バージョン情報は、VerQueryValue() API 関数によって得られる
      固定バージョン情報 (VS_FIXEDFILEINFO 構造体) のメンバに以下の形で
      格納されます。

        dwFileVersionMS
          上位ワード: DLL メジャーバージョン
          下位ワード: DLL マイナーバージョン
        dwFileVersionLS
          上位ワード: DLL パッチレベル
          下位ワード: API バージョン
        dwProductVersionMS
          上位ワード: プログラムメジャーバージョン
          下位ワード: プログラムマイナーバージョン
        dwProductVersionLS
          上位ワード: プログラムパッチレベル
          下位ワード: 予約

     TeX DLL とアプリケーションの間の API は予告なく変更されることが
     あります。この変更を検出するには、このバージョン情報の
     API バージョンを調べます。

     ヘッダファイル texdll.h に TeXDLL_API_VERSION マクロが定義されて
     いますので、これと バージョン情報中の API バージョンと比較することに
     よって、API の整合性を検査できます。

       ※ TeXGetLibraryFileName() 関数の API だけは将来的に変更されない
          ことが保証されています。

  i). フォーマットファイル・ベースファイルのチェックサムの取得

       ※ この機能は TeX/pTeX/METAFONT/MetaPost/MFtoPK のみです。

    フォーマットファイル・ベースファイルのチェックサム
    (*.fmt/*.base/*.mem の先頭 4 バイト) は使用する TeX 本体に固有のもの
    です (ASCII pTeX と オリジナルの TeX とでも異なります)。
    使用する DLL 固有のチェックサムは以下の関数で取得できます。

      DWORD WINAPI TeXGetChecksum(VOID);

  j). 関数ポインタテーブルの取得

    ここまで説明した DLL の関数のアドレスを DLL の動的ロードの際に
    いちいち取得するのは面倒な作業です。そこで、TeX DLL では
    これら関数のポインタを一気に取得することができるように、
    関数ポインタを収めた構造体を取得するための関数を用意しています。

      LPCTeXProcedures TeXGetProcedures(VOID);

    この関数を用いれば、例えば次のように GetProcAddress 呼び出しは一回で
    済みます。

      LPFTeXGetProceduresProc lpfGetProcs =
        (LPFTeXGetProceduresProc)GetProcAddress(hDLL, "TeXGetProcedures");
      LPCTeXProcedures lpProcs = (*lpfGetProcs)();
      HTeX hTeX = (*lpProcs->Initialize)();
      if (hTeX) {
        LONG lResult = (*lpProcs->Main)(hTeX, ...);
        (*lpProcs->Uninitialize)(hTeX);
      }

    関数テーブルの構造体のメンバについては texdll.h 内の TeXProcedures の
    定義をご覧ください。

    TeXGetProcedures() 関数の返値の TeXProcedures 構造体は、
    実装されていない関数のポインタについては NULL がセットされます。
    TeXProcedures 構造体の表す関数を呼び出す前に、必ず関数へのポインタが
    有効かどうかをチェックしてください。ただし、最低限、以下の関数については
    実装されていることが保証されますので、これらのメンバについてはチェックの
    必要はありません。

      GetLibraryFileName, Main, Initialize, Uninitialize

    また、TeXProcedures 構造体の中の GetLibraryFileName の位置は API が
    変更されたとしても必ず固定位置 (先頭) にあることが保証されますので、
    API のバージョンチェックについては TeXGetProcedures() 関数の返値を用いて
    GetLibraryFileName() を呼び出してもかまいません。
      

3). TeX DLL の使用の流れ

  簡単のためにエラー処理は省いてあります。ここでは動的な DLL のロード
をおこなう例を示していますが、静的なロードをおこなう場合でも(エントリ
ポイントの解決を除いて) 手順は同じです。

  また、TeX DLL 用の型や定数を用いますので、それらが定義されているヘッ
ダファイル texdll.h をインクルードして下さい。

       a). DLL の Load
       ｜
       ｜  HINSTANCE hDLL = LoadLibrary("tex");
       ↓
       b). 関数テーブルの取得
       ｜
       ｜  LPFTeXGetProceduresProc lpfGetProcs =
       ｜    (LPFTeXGetProceduresProc)GetProcAddress(hDLL, "TeXGetProcedures");
       ｜  LPCTeXProcedures lpProcs = (*lpfGetProcs)();
       ↓
       c). API のバージョンチェック
       ｜
       ｜  LPCSTR lpszDllFileName = (*lpProcs->GetLibraryFileName)();
       ｜  DWORD dwReserved;
       ｜  DWORD dwVerInfoSize = GetFileVersionInfoSize(lpszDllFileName, &dwReserved);
       ｜  LPVOID verInfo = HeapAlloc(GetProcessHeap(), 0, dwVerInfoSize);
       ｜  VS_FIXEDFILEINFO *fileInfo;
       ｜  UINT uFileInfoSize;
       ｜  GetFileVersionInfo(lpszDllFileName, 0, dwVerInfoSize, verInfo);
       ｜  VerQueryValue(verInfo, "\\", &fileInfo, &uFileInfoSize);
       ｜  if (fileInfo->dwFileVersionLS & 0xffff != TeXDLL_API_VERSION) {
       ｜    /* API version mismatch */
       ｜  }
       ↓
  −→ d). 初期化
 ｜    ｜
 ｜    ｜  HTeX hTeX;
 ｜    ｜  hTeX = (*lpProcs->Initialize)(lpfCallbackFunc, lpCallbackData, NULL);
 ｜    ↓
Loop   e). メイン関数
 ｜    ｜
 ｜    ｜  LONG lExitCode;
 ｜    ｜  lExitCode = (*lpProcs->VaMain)(hTeX, "latex", "\\input testpage", NULL);
 ｜    ↓
  −− f). 後処理
       ｜ 
       ｜  (*lpProcs->Uninitialize)(hTeX);
       ↓
       g). DLL の解放
 
           FreeLibrary(hDLL);

4). レジストリの設定

  以下の記述について具体的なイメージがわかない場合には、レジストリエディ
タを用いて、実際の様子を確認しながら読んでください。

  a). TeX DLL のパス

     TeX DLL のセットアッププログラムはインストール時に、レジストリの
     キー 「HKEY_LOCAL_MACHINE\Software\Kazunori Asayama\TeX DLL」 に
     値 「Path」 を設定します。これは、TeX DLL がインストールされた
     ディレクトリです。

     TeX DLL を利用するプログラムは、以下のいずれかの方法で、DLL を
     正しく読み込めるようにしてください。

     i). 動的に (LoadLibrary() API を用いて) TeX DLL をロードする場合

       前述の値をまず調べて、DLL の名前 ("ptex.dll" など) の前にその
       値を付加することによって、フルパスで DLL を指定する。

     ii). 任意の場合

       インストーラを実行するときに、レジストリのキー
      「HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\
                                    CurrentVersion\App Paths\<<AppName>>」
       に「Path」という値のエントリを作り、その値に、前述の DLL が
       インストールされたディレクトリを追加する。
         c.f.) 「Windows ユーザインターフェースデザインガイド」(MS-Press)
                                 ---- 「アプリケーションパスの情報の登録」

5). MakeTeX

TeX 本体のほかに MakeTeXPK、MakeTeXTFM、MakeTexMF 及び MakeTeXls-Rも
DLL として実装されています。DLL の名前は MakeTeX.dll で、この DLL は
内部で mf.dll 及び mftopk.dll を利用します。

TeX DLL が既に利用可能になっていれば、MakeTeX.dll の使用は簡単です。以
下のように引数を指定して、エントリポイント MakeTeXPKMain() などを
呼び出すだけです。

  BOOL WINAPI MakeTeXPKMain(LPSTR lpszFileName,
                            DWORD dwFileNameLen,
                            LPFTeXCallbackProc lpfCallback,
                            LPVOID lpCallbackData,
                            LPCSTR lpszFontName,
                            LPCSTR lpszMag,
                            DWORD dwModeDpi,
                            LPCSTR lpszMode);

    指定された名前のフォントを指定された拡大率で指定されたモードを
    使って生成します。

    引数:

      ○ LPSTR lpszFileName

         生成された PK フォントのファイル名 (フルパス) を返すための領域です。
         この関数を呼び出す前にあらかじめ確保しておき、そのサイズを
         dwFileNameLen で指定します。

      ○ DWORD dwFileNameLen

         バッファ lpszFileName の大きさ (バイト数) です。

      ○ LPFTeXCallbackProc lpfCallback
      ○ LPVOID lpfCallbackData

         コールバック関数およびその引数です。用途および実装方法は TeX DLL と
         同じです。

      ○ LPCSTR lpszFontName

         生成したいフォントの名前 (cmr10 など) です。

      ○ LPCSTR lpszMag

         拡大率を表す文字列です。METAFONT に与えるものと同じ表現を使います。
         たとえば magstep 1 (1.2 倍) であれば lpszMag = "magstep(1)" のように
         指定します。この引数が NULL であれば 1 倍と解釈されます。

      ○ DWORD dwModeDpi

         出力デバイス、つまり METAFONT の mode として指定するモードの
         解像度です。lpszMode として NULL が与えられた場合に限り、
         この値を基にモード名が推測されます。lpszMode を指定している場合には
         0 を指定してもかまいません。両方指定された場合には lpszMode が
         優先されます。

      ○ LPCSTR lpszMode

         PK フォントの生成に用いる METAFONT のモードの名前です。
         解像度 (dwModeDpi) を基にモード名を推測させる場合にはこの引数は
         NULL に指定してください。ただし、dwModeDpi と lpszMode の双方を
         未指定 (それぞれ、0, NULL) にすることはできません。

    返値:

        フォントの生成に成功した場合には 0 以外の値を返します。
        失敗した場合には 0 を返します。

  BOOL WINAPI MakeTeXTFMMain(LPSTR lpszFileName,
                             DWORD dwFileNameLen,
                             LPFTeXCallbackProc lpfCallback,
                             LPVOID lpCallbackData,
                             LPCSTR lpszFontName);

    指定された名前の TFM を生成します。

    引数及び返値:

      全て MakeTeXPKMain と同じ意味です。

  BOOL WINAPI MakeTeXMFMain(LPSTR lpszFileName,
                            DWORD dwFileNameLen,
                            LPFTeXCallbackProc lpfCallback,
                            LPVOID lpCallbackData,
                            LPCSTR lpszFontName);

    指定された名前の METAFONT ソースを生成します。
    METAFONT ソースの生成方法は MakeTeX.DLL と同じディレクトリに有る
    MakeTeXMF.cnf に記述します。

    引数及び返値:

      全て MakeTeXPKMain と同じ意味です。

  BOOL WINAPI MakeTeXlsRMain(LPCSTR lpszTopDir, LPCSTR lpszLSR);

    引数:

      ○ LPCSTR lpszTopDir

         ls-R データベースの内容のトップディレクトリ。作成される ls-R データ
         ベースはデフォルトでは (lpszLSR が NULL の場合には) このディレクトリに
         作られます。lpszTopDir が NULL のときには kpathsea 変数 
         (KpseCnfEdit.exe で閲覧・編集) の TEXMFLS_R、TEXMFMAIN が順に調べられ、
         先に見つかったものが用いられます。

      ○ LPCSTR lpszLSR

         ls-R データベースのファイル名。この値が NULL の場合には、
         トップディレクトリ下の "ls-R" というファイル名になります。

    返値:

        ls-R データベースの生成に成功した場合には 0 以外の値を返します。
        失敗した場合には 0 を返します。


6). 制限

  DLL はマルチスレッドには対応していません (web2c が吐くコードは大量の
グローバル変数を生成するので大幅な変更が必要なため)。これは 1 プロセス
内では同時に 1 つの TeX (*TeXMain 関数のみではなくDLL のすべての関数に
ついて) しか使えないという意味です。強引に、(TLS を用いるなどして) マ
ルチスレッド対応をおこなうことも出来るのですが、実行速度が大きく犠牲に
なるため対応は見合わせています (それに、TeX をマルチスレッドで動かした
いという要求も多くはないでしょうし...)。

  このための排他処理は DLL 内でおこなっていますので、この DLL を利用し
てマルチスレッドアプリケーション (たとえば MDI の TeX エディタなど) を
開発するプログラマは、この制限をプログラミングの際に意識する必要はあり
ません。ただし、排他処理は TeXInitialize 関数とTeXUninitialize 関数と
でクリティカルセクションを用いて行っていますので以下の例のように 
TeXInitialize ... TeXUninitialize のブロックが一つのスレッド内で入れ子
や交差するようなコーディングは行わないようにしてください (異なるスレッ
ド間でTeXInitialize と TeXUninitialize が交差することには問題はない)。

  /* 入れ子 */
  hTeXA = TeXInitialize(...);
    hTeXB = TeXInitialize(...); /* ここでデッドロック */
    TeXUninitialize(hTeXB);
  TeXUninitialize(hTeXA);

  /* 交差 */
  hTeXA = TeXInitialize(...);
  hTeXB = TeXInitialize(...); /* ここでデッドロック */
  TeXUninitialize(hTeXA);
  TeXUninitialize(hTeXB);

要は、あるスレッドで TeXInitialize を呼び出すときにはその前に、同じス
レッド内での前回のTeXInitialize の呼び出しに対応する TeXUninitialize 
を必ず呼び出しておくということです。

  ファイル名に空白や 2 バイト文字が含まれることには多少の制限がありま
す。サーチルーチン経由で渡されるファイル名に関しては大丈夫ですが、コマ
ンドラインや TeX / METAFONT のマクロ・ソース内では原則として使えないも
のと考えて下さい。

  また、コマンドラインから渡すファイル名ではそれに含まれるディレクトリ
の区切り文字の '\' は '/' に変更して下さい。誤動作の原因になります。

  この DLL の API は、予告なく変更されることがあります。

---
淺山 和典 (ASAYAMA Kazunori)
asayama@vid.cpg.sony.co.jp
GHF01532@niftyserve.or.jp
TPM03937@pcvan.or.jp
********************************** EOF *********************************
