【WIN 32の旅】WINDOWSエラー処理と参考(三)


転載は元の出典を説明してください.ありがとうございます. http://blog.csdn.net/seven_1992/articale/detail/44487785
    WINDOWSのプログラミングの中で、私達はどうしても“間違い”とつきあうことができなくて、しかし私達の“北を見つけられません”のは、私達はどんな誤り(What's Errror?)ですかを知らないで、あるいはシステムが誤ったコード(Err Code)を提供しました.(What's mean?) 次に登場するのは、エラー情報に関するいくつかのシステムAPI関数です.エラー情報の処理と参照について、これらの関数を見てみましょう.
一、エラーコードの設定と取得
   コードの実行中にエラーが発生しました.エラー情報を取得したり設定したりするには、この関連の2つの関数GetLastError()とSetLastErr()を使います.これは兄弟関数です.関数の名前はいつもこのようにしています.Get関数とSet関数はいつもペアで現れます.実は私たちは普段コードと付き合っている日には日常的なものです.この二つの関数についてはこれから調べてみましょう.
1、GetLastErr()関数:
DWORD WINAPI GetLastError(void); //           
    これはMSDNの関数のプロトタイプであり、戻り値はDWORD(ダブルワード)であり、関数呼び出しはマクロWINAPI(すなわち、__stdcall標準呼出)と約束されています.入力パラメータはvoid(空パラメータタイプ)であり、MSDNではこの関数について説明します.(簡単に言えば、エラーコードはスレッドレベルが持っています.この関数を使って取得したエラーコードはスレッドのものです.)
2、SetLastErr()関数:
void WINAPI SetLastError(_In_ DWORD dwErrCode);  //       
    名前の通り、この関数の役割は最後のエラーコード(Last-error Code)を設定します.実はその兄弟関数GetLastError()を理解しました.この関数の理解と運用はそんなに難しくないと思います.
    SetLastError関数についても、拡張関数(Extension Function)が同じである.
void WINAPI SetLastErrorEx(
  _In_  DWORD dwErrCode,
  _In_  DWORD dwType
);
    MSDNは現在、SetLastErr()に相当する第二のパラメータが一時的に無視されているため、説明を与えている.
PS.エラーコード(Error Code)について、MSDNにはこんなコメントがあります.
    エラーコードは32ビットの値で、最上位の31ビットは最も重要なビットです.29位はアプリケーションにエラーを定義するための専用ビットです.アプリケーションにエラーを定義するには、このビットを1として設定してください.このエラーコードはアプリケーションによって定義されています.システム定義のエラーコードと競合しないことを保証してください.
    
二、フォーマットエラー情報
    もちろん、GetLastError()とSetLastError()の2つの関数は、間違ったコードを設定して取得することです.コードである以上、このコードの意味はどう分かりますか?大丈夫です.次に登場するのはFormaMessage()関数です.
    DWORD WINAPI FormatMessage(     //    DWORD          
    _In_      DWORD dwFlags,        //        ,        lpSource
    _In_opt_  LPCVOID lpSource,     //         ( dwFlags    )
    _In_      DWORD dwMessageId,    //     ID(  dwFlags   FORMAT_MESSAGE_FROM_STRING       )
    _In_      DWORD dwLanguageId,   //     ID(  dwFlags   FORMAT_MESSAGE_FROM_STRING       )
    _Out_     LPTSTR lpBuffer,      //      
    _In_      DWORD nSize,          //               (     128K,     GetLastError()   ERROR_MORE_DATA)
    _In_opt_  va_list *Arguments    //               
    );
    FormatMessage()関数について、MSDNはその解釈に対して:
    フォーマット出力のメッセージ列を出力します.この関数が出力するメッセージ列は、着信するバッファポインタによって指し示すフォーマット文字列(すなわちlpSourceはフォーマット文字列ポインタ、パラメータは可変パラメータテーブルAgmentsから来ています.)から来ても良いし、ロードされたリソースモジュールのメッセージテーブルから来てもいいです.(すなわち、lpSourceはモジュールのハンドルである)またはシステムリソースに定義されているメッセージテーブル(このとき、lpSourceはNULL空である)から来たもので、いずれもフォーマットオプションに依存します.この関数はメッセージ識別子(dwMessageId)と言語識別子(dwLanguageId)に基づいて、メッセージソーステーブル(Message Tabel Resource)にあります.に対応するメッセージ定義を検索します.この関数はフォーマットされたメッセージを出力バッファにコピーします.
   dwFlagsパラメータの識別(上の説明からその指導的役割がわかる):

意味
FOREMATUMESSAGEUALLOCATEU BUFFER
0 x 0000010
 関数は、フォーマットメッセージ列(nSizeパラメータ指定割り当て出力バッファの最小長さ)に十分な空間を割り当て、lpBufferを介してアドレスを指す(LPTSTRに変換しなければならない). ,すなわち(LPTSTR)&lpBuffer, LocalFree )
FOREMATUMESSAGEUARGUMENTギャラ
0 x 000000
メッセージ・列をフォーマットするAgmentsパラメータはva_ulist構造体を指すのではなく、保存パラメータを指す配列ポインタである(パラメータに64ビットの整数が含まれている場合、va_ulist構造体伝達パラメータを使用しなければならない).
FOREMATHMODLE
0 x 0000800
フォーマットメッセージ列は既にロードされているモジュールから来ています.lpSourceがNULLの場合、現在のプロセスモジュールのハンドルです.
FOREMATUMESSAGEuFROMUSTRING
0 x 0000400
フォーマットされたメッセージ列はフォーマットされた文字列から来ます. FOREMATHMODLE または FOREMATUMESSAGEuFROMUSYSTEMマークは同時に使用します.
FOREMATUMESSAG EuFROMUSYSTEM
0 x 000000
フォーマットメッセージ列は、システムメッセージリソーステーブルから来ます. FOREMATUMESSAGEuFROMUHMODLEグループは、まずlpSourceが指すモジュールの中から指定メッセージを探しています.見つけられないなら、システムで選択します. (このマークは FOREMATUMESSAGEuFROMUSTRINGを同時に使用します.
FOREMATHUMESSAG EuIGNOREHUINSERTS
0 x 000002
フォーマットされたメッセージ列の挿入シーケンスは無視され、直接に出力バッファに渡されます.このパラメータはメッセージの後付けフォーマットにとって非常に有用です.このフラグ設定ではパラメータテーブルAgmentsは無視されます.
    dwFlagsパラメータは、上記のパラメータの一つまたはそれらの組合せ(使用または|演算子)であってもよく、dwFlagsの下位値は、出力バッファ処理ラインの変換を関数でどのように処理するかを指定しています.また、出力文字列出力行の最大幅を指定することもできます.ステータス値の設定については、以下の表示を使って行うことができます.
Value
Meaning
0
出力の最大幅制限がないことを示します.
FOREMATUMESSAGEMAX HuMADHuMASK
0 x 000000 FF
最大出力幅制限があることを示します.
    Agmentsパラメータについては(上記の説明から、挿入値の転送口であることが分かります):
   Agmentsには、FOREMATUMESSAGEuARGUMENTARRAYによって決定された2つのタイプがあり、このマークを配列として識別すると、文字列の中で%nを挿入子として使用します.このフラグが指定されていない場合は、prnf()のようなフォーマット化挿入子(例えば%d、%s、%cなど)を使用します.
FormatMessage()関数については、いくつか列子を使って列子を挙げます.
一例(Agmentsパラメータ配列、幅と精度の使用例):
#ifndef UNICODE
#define UNICODE
#endif

#include 
#include 

void main(void)
{
    LPWSTR pMessage = L"%1!*.*s! %4 %5!*s!";
    DWORD_PTR pArgs[] = { (DWORD_PTR)4, (DWORD_PTR)2, (DWORD_PTR)L"Bill",  // %1!*.*s! refers back to the first insertion string in pMessage
         (DWORD_PTR)L"Bob",                                                // %4 refers back to the second insertion string in pMessage
         (DWORD_PTR)6, (DWORD_PTR)L"Bill" };                               // %5!*s! refers back to the third insertion string in pMessage
    const DWORD size = 100+1;
    WCHAR buffer[size];

    if (!FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
                       pMessage, 
                       0,
                       0,
                       buffer, 
                       size, 
                       (va_list*)pArgs))
    {
        wprintf(L"Format message failed with 0x%x
", GetLastError()); return; } // " Bi Bob Bill". wprintf(L"Formatted message: %s
", buffer); }
例二(Agments変長パラメータテーブルの使用例):
#ifndef UNICODE
#define UNICODE
#endif

#include 
#include 

LPWSTR GetFormattedMessage(LPWSTR pMessage, ...);

void main(void)
{
    LPWSTR pBuffer = NULL;
    LPWSTR pMessage = L"%1!*.*s! %3 %4!*s!";

    //                 pMessage          
    pBuffer = GetFormattedMessage(pMessage, 4, 2, L"Bill", L"Bob", 6, L"Bill");
    if (pBuffer)
    {
        //           "  Bi Bob   Bill".
        wprintf(L"Formatted message: %s
", pBuffer); LocalFree(pBuffer); } else { wprintf(L"Format message failed with 0x%x
", GetLastError()); } } // Formats a message string using the specified message and variable // list of arguments. LPWSTR GetFormattedMessage(LPWSTR pMessage, ...) { LPWSTR pBuffer = NULL; va_list args = NULL; va_start(args, pMessage); FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, pMessage, 0, 0, (LPWSTR)&pBuffer, 0, &args); va_end(args); return pBuffer; }
例3(フォーマットシステムエラー情報の使用例)
TCHAR* GetLastErrorText(DWORD nErrorCode)
{
    TCHAR* pMsgBuff;
    //   FormatMessage()  WINDOWS         
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                  NULL,
                  nErrorCode,
                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                  (LPTSTR)&pMsgBuff,
                  0,
                  NULL);
    //               
    if (!pMsgBuff)
        return("    !");
    else
        return(pMsgBuff);
    //   :     pMsgBuff   LocalFree()          
}
    PS.私たちは関数を使用して、その定義を明確に理解します.(各シンボルの代表の意味を含みます.)このように、私達はもっとよく理解して運用することができます.この一番いい方法はMSDNを調べることです.言語間の意味はやはり微妙に違っています.英語の角度からそれを理解したほうがいいと思います.これはもっと良い地理的な理解だけではなく、英語のレベルを上げるのにも役立ちますよね.
 
 
前編、『WINDOWSエラー処理と参考(二)』…
次の編では、引き続き『WINDOWSエラー処理と参考(四)』を補充します.
コメントと転載を歓迎して、転載して文章の出所を明記して下さい、私はこれに対して最も誠実な敬意を表します!