よる関数定義の原則これまで説明してきたように、関数の呼び出しには「命令形式」と「関数形式」の2通りの方法がありました。API関数のパラメータに文字列やメモリブロックのアドレスを渡したい場合にも、その方法が何通りもありました。これでは、API関数を呼び出すプログラムを書くたびに定義方法・呼び出し方法が異なり、まったく統一されていない書き方になってしまう可能性があります。そこで、ある程度、関数定義や呼び出し時のパラメータ指定方法の方針を決めておくべきです。HSPのドキュメント内では、実数型などの特殊なパラメータが含まれる場合を除き、原則として以下の方針にしたがっていきます。API関数は、戻り値が重要であるもの(ウィンドウハンドルを取得するなど)と、そうでないもの(戻り値なしのものや、単にBOOL型で関数の成否のみを返すもの)に分類することができます。戻り値が重要な関数に対して命令形式の定義をした場合、システム変数statに格納された戻り値を参照しなければなりませんが、その戻り値を意図せず使用しないままになってしまう可能性があります。関数形式で書くことによって、そのような危険性を少なくすることができるでしょう。API関数一括定義ファイル(後述)ではすべて#funcで定義されているため、一括定義ファイルを用いる場合には常に命令形式で記述し、statを参照して戻り値を取得しなければなりません。一部の関数では、使用目的によって戻り値が重要である場合とそうではない場合があり(例:SendMessage関数など)、そういった関数を使用する場合には状況に応じて関数形式と命令形式を使い分けることにします。次の点として、API関数に変数アドレスを渡すのにvar型指定を使わないことを推奨します。理由の一つは、前回にも述べましたが、varを使うとパラメータにNULLポインタを渡せなくなるためです。アドレスを渡すパラメータの中には、NULLポインタを渡せるものが存在しますが、var型指定ではNULLポインタを含め任意の数値を渡すことができません。一つの理由は、API関数のリファレンスにおけるパラメータの説明との整合性が取れなくなってしまうからです。HSP内での関数の説明など、多く場合は関数パラメータの説明として「~のアドレスを渡す」「~へのポインタを渡す」という説明がされているはずです。それに対しては、スクリプト側でもvarptrを使って、(変数に格納されている値ではなくて)変数のアドレスを渡しているのだということをはっきりと示した方が分かりやすくなります。var型指定を多用してしまうと、変数に格納されている値を渡しているのか、それとも変数のアドレスを渡しているのかがあいまいになってしまう恐れがあります。関数に文字列を渡す場合には、その文字列を直接記述できるようにしても問題はないと思われます。いうのは、パラメータに文字列(または文字列型変数)を指定した場合、引数として渡すのは文字列のアドレス以外にありえないからです。このような場合には、sptrを使うことでNULLポインタの問題も解決できますね。関数に文字列を渡す場合でなく、関数から文字列を受け取る場合には、明示的にvarptrを使って文字列変数のアドレスを指定しなければいけません。ここでは、var型指定を使わないことを推奨していますが、禁止しているわけではありません。モジュール内でAPI関数を呼び出す場合、var型指定でも問題ないと判断できる場合には、var型指定を使用してもよいと思います(HSPのモジュール機能については後述)。モジュール空間内での#func定義は(global指定子を付けない限り)モジュールの外に影響を与えませんので、上で述べたようなパラメータのあいまいさは、さほど現れないでしょう。varptrを介さないぶん、ほんのわずかでも速度が向上するかもしれませんし。グローバル空間(モジュールの外)や大きなモジュール空間では、混乱を避けるためにvar型指定の使用を控えた方がよいと思います。そのほか、オリジナルのAPI関数名とは異なる名前を新しく付ける場合には、var型指定を使っても問題ないでしょう。OK?#func命令のsptr型指定は、渡されたパラメータが数値の場合はそのまま、文字列の場合はそのアドレスを渡すというものでしたね。いうことは、(実数型などを除けば)パラメータ定義を全部sptrで指定しても問題ない、ということになりますよね。実際に、前回のメッセージボックス表示の例において、MessageBox関数の定義で第1パラメータから第4パラメータまですべてsptrを指定したとしても問題なく動作します。0関数のパラメータ型指定にすべてsptrを指定するという手法は、関数のパラメータ数さえ分かると簡単に書くことができますし、割と常套的な手段といえます。API関数一括定義ファイルの中には、そのような定義方法を用いているものもあります。sptrとintを区別して記述しても、すべてsptrと記述しても、関数呼び出し時の記述は同じになりますので、どちらの形式で定義するかは各自で決めてよいと思います。それぞれ付けられているのでしたね。付けて定義するかどうか、と考えますよね。付けていない関数名の方で書かれています。付けるというのは面倒ですよね。付けない名前で定義していくことにします。intとすることにします。付けてた名前で記述したい場合があるかもしれません。付けたものと付けないもので同じ結果になるようにしておく方が望ましいと思います。付けた関数名と付けていない関数名の両方を用いることができます。API関数の定義を一括で行うためのヘッダファイルがcommonフォルダ内にあらかじめ含まれています。API関数を提供するシステムDLLごとに分けて準備されています。「user32.as」ファイルには「user32.dll」が提供するすべてのAPI関数の#func定義が含まれています。これにより、「user32.as」をインクルードすることによって、自分で#func定義を記述することなくuser32.dllが提供する関数を呼び出すことができるようになります。付けたものと付けていないものの両方が定義されます。したがって、例えば「user32.as」をインクルードするとMessageBox関数とMessageBoxA関数の両方が定義され、どちらを使っても同じように動作させることができます。この標準添付の一括定義ファイルでは、上でも述べたような「引数型としてすべてsptrを指定する」という方針で記述されています。(実際には、Unicode版関数ではsptrではなくwptrが使用され、文字列が自動的にUnicode文字列に変換されるようになっています。0この一括定義ファイルを使用する際に注意しておくべきことは、この一括定義ファイルでは#funcによる定義のみで、#cfuncによる定義はされていないため、API関数の呼び出しは「命令形式」でのみ行うことができるということです。1つ注意しておくべきこととして、一括定義ファイルをインクルードすると、含まれているAPI関数の定義情報があまりにも多いために、コンパイル時の処理にやや時間がかかってしまう可能性があるということです。初期のHSP3.0では、一括定義された関数の登録情報がすべてオブジェクトファイル(.ax)に記録されてしまうために、最終的な実行ファイルのサイズが大きくなってしまうというデメリットがあります。最新バージョンのHSPでは、コンパイル時の最適化により、一括定義された関数のうち実際にプログラム中で使用されたものだけがオブジェクトファイルに記録されるようになっています。関数検索(apifunc)』が公開されています。このツールは非常に強力で、膨大な数のAPI関数の定義をデータベース化して保持しており、関数名から#uselibと#func(または#cfunc)の組を検索することが可能になっています。global」から選択することができるという高機能ぶりです。出力結果をクリップボードにコピーすることが可能で、あとは、そのままスクリプトに貼り付けてしまえば、スクリプト中でAPI関数を使用することができるようになります。API関数を呼び出す方法についても、ある程度は理解できたことでしょう。APIを扱っていくのに困ることがないかというと、必ずしもそうではないのです。APIを使いこなすには、いくつもの困難が待ち構えています。APIを使うには、必要な関数や構造体の知識を手に入れる必要があります。Web検索で関数名や構造体名を探すことで、主要なAPIの使い方が見つかることでしょう。詳細な情報が必要であれば、Microsoftが公開しているMSDNのオンラインライブラリを参照してみましょう。(英語)http://msdn.microsoft.com/en-us/library/MSDNライブラリのドキュメントはもともと英語で書かれているものですが、現在はかなり日本語への翻訳が進んでいます。そのため、日本語のドキュメントだけでも、それなりの情報が得られるかもしれません。それでもまだ多くの関数や構造体に関するリファレンスや解説ドキュメントが日本語に翻訳されておらず、場合によっては英語のドキュメントを読まなければならなくなることがあります。英語版ドキュメントに書かれていることが日本語版の方には書かれていないこともあります。誤訳なのでしょうが、英語のドキュメントと日本語のドキュメントで記述が違っていることすらあります。Web上の翻訳サイトや辞書サイトの力を借りながらでもよいですので、ある程度は英語のドキュメントを読む力を付けておいた方がよいでしょう。定数名はどう調べる?次に問題として挙げられるのが、定数名の値をどのようにして知るのかということです。APIでは、いくつかの値が定数名という形で定義されています。以前にも出てきましたが、定数名「NULL」は0という値で定義されています。そのほか、最も簡単なところでは、定数名「FALSE」は0、「TRUE」は1という値を持った定数名として定義されています。0という形で定義することで、これらの定数名を使用することができます。実際にAPIを使っていくと、定数名として定義されたさまざまな値が関数のパラメータとして使われることになります。いったものには、特定の関数の特定のパラメータのみで使われるようなものも数多く存在しています。APIプログラミングを行う場合には、これらの定数名が定義されたヘッダファイルがあらかじめ準備されています。他の言語ではそのようなヘッダファイルがないため、必要な定数名の値を何らかの方法で調べなければいけません。APIを使う際の面倒な部分の1つでしたが、現在では簡単に定数名の値を調べる方法も存在します。その方法を紹介していきましょう。検索(apiconst)』が公開されています。このツールもまた、膨大な数の定数定義をデータベース化して保持しており、定数名から値を検索することが可能になっています。global」から選択することができます。API定数の検索ツールが公開されています。APIで使用される主要な定数名を網羅しており、定義を知りたい定数名を入力すると、その#defineによる定義を表示し、クリップボードにもコピーしてくれます。API一括定義マクロ『MA_MACRO』のアーカイブに同梱されていたものです。API呼び出しでも簡単に利用できるよう、ツールのみ独立させたアーカイブとして公開されています。APIを扱っている多くのWebサイトではC/C++言語が使用されていますが、他のプログラミング言語を使用している所も存在します。APIを扱っている所は割と多いようです。そのような言語でもやはり定数名を定義したヘッダファイルが存在しないので、ソースプログラムに直接書かれていることが多いです。そこで、それらの値を引用してくるのも1つの手です。関数の解説も載っていれば、一挙両得ですね。以下のサイトではVBプログラマ向けにAPI関数が解説されていますが、解説されている関数の数が豊富なので役に立つことでしょう。SDKをインストールしC/C++用のヘッダファイルを検索する最も確実な方法は、Windowsプログラミングが可能なC/C++言語開発ツールに含まれているWindows用のヘッダファイルを参照することです。最新のWindowsでしか使用できないAPIで必要となる定数定義のなかには、上記の検索ツールでもヒットしないものがある可能性があります。SDK』をインストールし、それに含まれているC/C++のヘッダファイルの中を検索しなければならないでしょう。APIに関するドキュメントも手に入ります。インストールに必要なディスク容量が非常に大きいので、注意が必要です。APIを扱う上で注意すべきことは、関数の呼び出しが常に成功するとは限らないということです。したがって、関数を呼び出した後は、成功しているかどうかを判断し、もし呼び出しに失敗していた場合には、適切なエラー処理をしなければなりません。API関数が呼び出されると、関数はそれぞれで決められた処理を行います。このとき、API関数を呼び出したプログラムが無効な引数を渡したり、何らかの理由で処理を行うことができなかったりした場合には、そのAPI関数は、戻り値を通して、エラーが発生した(関数呼び出しが失敗した)ことを呼び出し側プログラムに知らせます。API関数を呼び出したプログラムが、エラーが発生したかどうかを判断してそれに応じた処理を行わずに、関数が成功したとみなして処理を続けていってしまうと、最悪の場合、プログラムが暴走するという危険性さえ出てきます。エラーが起こることはないと分かっている場合には必要ありませんが、そうでない場合には適切なエラー処理を行うべきです。API関数がどのようなエラー値を返すのかを見ていきましょう。関数のデータ型によってエラーを示す値はさまざまです。いくつか例をあげてみましょう。戻り値なしのAPI関数VOID型の関数は、戻り値を持ちません。これらの関数は、呼び出し側に返す情報はなく、また、ほとんどエラーを起こす可能性もないものです。したがって、これらの関数の後でエラー処理を行う必要はほとんどありません。(というより、エラーかどうかの判断を行うこと自体ができませんが。)ブール型を返すAPI関数ブール型(BOOL型)の戻り値を返す関数の多くは、関数が正常に処理を行った場合に0以外の値を返します。関数がエラーを起こした場合、戻り値として0を返す増す。本来、ブール型とは真か偽かを表す型のことで、0以外の値である場合を真とみなし、0の場合を偽とみなします。Windowsでは、便宜上、真(TRUE)を1と定義し、偽(FALSE)を0と定義していますが、実際に真偽を判断する(エラーかどうかを判断する)には、「0か1か」ではなく、「0か、それとも0以外の値か」で判断しなくてはなりません。ブール型を返すすべてのAPI関数が、エラー時に0を返すわけではありません。EnableWindow関数の戻り値の型はBOOL型ですが、戻り値はエラーが発生したかどうかには関係ありません。このような関数は、エラーが起こっていないかどうかを確認しておかないと、返されたアドレスのメモリ領域にアクセスしようとした時に、アドレス0x00000000の領域にアクセスしようとしてアクセス違反が発生し、プログラムが強制終了してしまう可能性があります。返します(Windowsオブジェクトについては後述)。