Win32 APIは中でエラーが発生すると、以下のような方法で その結果を呼び出し元に通知します。
多くのAPIは、エラーが発生するとスレッド毎に特定の領域に
エラー番号を格納して呼び出し元に復帰します。呼び出し元は
GetLastError
APIを用いて
この番号を取得することができます。
API名 | 説明 |
---|---|
GetLastError |
もっとも最近のエラー番号を格納する領域に格納されている エラー番号を取得する。 |
ほとんどのAPIは正常終了したときにはエラー番号を設定しませんので、
APIが正常終了していた場合には、
GetLastError
API呼び出しの結果は不定です。
そこで、API呼び出し元は一般に以下のような処理を行わなければなりません。
SomeAPI();
if
(異常終了) {
DWORD errorno = GetLastError();
エラー処理;
}
さて、APIが異常終了したか否かはどのようにして判定すれば
よいのでしょうか。それはたいていの場合APIの戻り値で判定できます。
たとえば、CreateProcess
APIは
BOOL
値でAPIの結果を返します。
したがって、コードは以下のようになります。
BOOL result = CreateProcess(...);
if
(result == FALSE) {
DWORD errorno = GetLastError();
エラー処理;
}
もうひとつの例を出しましょう。CreateFile
APIは
HANDLE
の値を返しますが、失敗したときには
INVALID_HANDLE_VALUE
を返すことになっています
(APIの成功と失敗の判定方法は各APIのオンラインヘルプに掲載されています)。
したがって、エラー処理は以下のようにします。
HANDLE handle = CreateFile(...);
if
(handle == INVALID_HANDLE_VALUE) {
DWORD errorno = GetLastError();
エラー処理;
}
以上のような規則に当てはまらないAPIもあります。代表的なものは
CreateMutex
APIや
CreateSemaphore
APIです。
これらのAPIが失敗したときは上に挙げた他のAPIと同様の処理を
行うことができます。一方でこれらのAPIは成功したときにも
エラー番号を設定します。具体的にはAPIが成功しているときに
GetLastError
APIを呼び出すと以下のような値が戻ります。
値 | 説明 |
---|---|
ERROR_SUCCESS | ミューテクスまたはセマフォを作成した。 |
ERROR_ALREADY_EXISTS | 既に存在するミューテクスまたはセマフォをオープンした。 |
これらのAPIを利用する際にはたとえば次に示すように
成功しているにもかかわらずGetLastError
APIを
呼び出すコードを書く場合があることになります。
HANDLE handle = CreateMutex(...);if
(handle == NULL) { DWORD errorno = GetLastError(); エラー処理; } else { DWORD errorno = GetLastError();if
(errorno == ERROR_ALREADY_EXISTS) 既にミューテクスが存在していたときの処理;else
はじめてミューテクスを作成したときの処理; }
あるグループのAPIはエラー番号をAPI自体の戻り値として返します。
レジストリをアクセスするAPIはみなこのグループに含まれます。
たとえばRegCreateKeyEx
APIのエラー処理は
以下のように行うといいでしょう。
DWORD errorno = RegCreateKeyEx(...);
if
(errorno != ERROR_SUCCESS) エラー処理;
まれにAPIが構造化例外を発生することがあります。
APIが構造化例外を発生するというマニュアルの記述はないため、
一般にはAPIにバグがあるときであると推測されます。
たとえばlstrlen
の引数として
NULL
を渡すとWindows NT 3.51では
例外0xC0000005
が送出されました。
この現象はWindows 4.0では発生せず、
APIは0
を返します。
他の例として、USER32系APIの中のごく一部のものは、
HWND
の値が既に無効になっている
ウインドウハンドルである場合に例外を送出することがあります。
たとえば、GetWindowTextLength
APIは
無効なウインドウハンドルを渡されると例外0xC0000005
を
送出することがあります。アプリケーションはウインドウハンドルが
有効である期間を制限することができないため、
この問題を回避するうまい方法はありません。したがって、
このAPIを利用するアプリケーションは必ず例外を捕獲する
しくみを持たねばなりません。すなわち、たとえば下のようなコードを
書く必要があります。
HANDLE hwnd = あるウインドウのハンドル;__try
{ DWORD length = GetWindowTextLength(hwnd); }__except
(EXCEPTION_EXECUTE_HANDLER) { エラー処理; }