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