プログラミングのメモ帳(C/C++/HSP)

日々のプログラミングで気づいた点や小技集を紹介します。(Windows 10/XP/Vista、VC2017、HSP)

ウインドウの作成

2011年05月22日 14時36分00秒 | ウインドウ関連

Windows OS がどのようにしてワープロソフトや表計算ソフトのアプリケーション(以後プログラムと呼ぶ)を処理するか簡単に説明します。まず最初に人間がマウスなどで実行ファイル(*.exe)をダブル・クリックします。この動作によって Windows OS は実行ファイル(*.exe)を起動させてプログラム内部にある特殊な名前の WinMain 関数を最初に呼び出します。この関数にはアプリケーションであるワープロソフトや表計算ソフト、またはゲームソフトのウインドウを表示するまでの一連の手順を記述します。記述方法はアプリケーションの種類によって微妙に異なりますが、基本的にはウインドウ・クラスを登録する処理、ウインドウを作成する処理、Windows OS から常に届く動作指示メッセージ(WM_xxxxx)を処理するためのループ構造を組みます。今日は、このスタートアップ・ルーチンの手順を解説します。また、ウインドウ型とダイアログ・アプリケーション型の雛型ソースを5種類紹介します。この雛型ソースを使って自作ソフトを製作してみて下さい。

Windows OS の最初の呼び出し

  1. 実行ファイル(*.exe)が起動されると Windows OS はプログラムの WinMain 関数を最初に呼び出します。
  2. WinMain 関数内でウインドウ・クラスを登録する funcWindowClass 関数を呼び出します。
  3. WinMain 関数内でウインドウを作成する funcCreateWindow 関数を呼び出します。
  4. WinMain 関数内で GetMessage 関数によるメッセージ・ループを処理します。
WinMain()
├─funcWindowClass()
│ ├─LoadIcon()
│ ├─LoadCursor()
│ ├─GetStockObject()
│ └─RegisterClassEx()
│
├─funcCreateWindow()
│ ├─CreateWindowEx()
│ ├─ShowWindow()
│ └─UpdateWindow()
│
└─GetMessage()
  ├─TranslateMessage()
  └─DispatchMessage()

具体的なソースは次のようになります。

//------------------------------------------------
// メイン関数
//------------------------------------------------
extern int WINAPI _tWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow )
{
    LPCTSTR lpClassName = TEXT("XXXX_WndClass");
    LPCTSTR lpTitleName = TEXT("キャプション");
    MSG Msg;
    
    if ( funcWindowClass(hInstance,lpClassName) == 0 ){
        return -1;
    }
    if ( funcCreateWindow(hInstance,lpClassName,lpTitleName,nCmdShow) == NULL ){
        return -2;
    }
    while ( GetMessage(&Msg,NULL,0,0) > 0 ){
        TranslateMessage( &Msg );
        DispatchMessage( &Msg );
    }
    UNREFERENCED_PARAMETER( hPrevInstance );
    UNREFERENCED_PARAMETER( lpCmdLine );
    return Msg.wParam;
}
  • funcWindowClass 関数でウインドウ・クラスを登録します。
  • funcCreateWindow 関数でウインドウを作成します。
  • GetMessage 関数でメッセージ・ループを構成します。
//------------------------------------------------
// ウインドウ・クラスの登録
//------------------------------------------------
static ATOM funcWindowClass( HINSTANCE hInstance, LPCTSTR lpClassName )
{
    WNDCLASSEX wcex = { 0 };
    
    wcex.cbSize         = sizeof(WNDCLASSEX);
    wcex.style          = (CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS);
    wcex.lpfnWndProc    = mainWindowProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon( NULL, IDI_APPLICATION );
    wcex.hIconSm        = LoadIcon( NULL, IDI_APPLICATION );
    wcex.hCursor        = LoadCursor( NULL, IDC_ARROW );
    wcex.hbrBackground  = (HBRUSH)GetStockObject( WHITE_BRUSH );
    wcex.lpszMenuName   = NULL;
    wcex.lpszClassName  = lpClassName;
    return RegisterClassEx( &wcex );
}
  • WNDCLASSEX 構造体に適切なパラメータをセットします。
  • lpszMenuName メンバにメニュー・リソースの識別文字列をセットするとウインドウにメニュー・バーが表示されます。
  • その後、RegisterClassEx 関数でウインドウ・クラスを登録します。
//------------------------------------------------
// ウインドウの作成
//------------------------------------------------
static HWND funcCreateWindow( HINSTANCE hInstance, LPCTSTR lpClassName, LPCTSTR lpTitleName, int nCmdShow )
{
    HWND hWnd = CreateWindowEx(
        0,                      // 拡張ウインドウのスタイル
        lpClassName,            // ウインドウのクラス名
        lpTitleName,            // ウインドウのタイトル名
        WS_OVERLAPPEDWINDOW,    // ウインドウのスタイル
        CW_USEDEFAULT,          // ウインドウの横軸位置
        CW_USEDEFAULT,          // ウインドウの縦軸位置
        CW_USEDEFAULT,          // ウインドウの横サイズ
        CW_USEDEFAULT,          // ウインドウの縦サイズ
        NULL,                   // 親ウインドウのハンドル
        NULL,                   // メニューのハンドル
        hInstance,              // インスタンスのハンドル
        NULL );                 // ウインドウ作成のデータ
    
    if ( hWnd != NULL ){
        ShowWindow( hWnd, nCmdShow );
        UpdateWindow( hWnd );
    }
    return hWnd;
}
  • CreateWindowEx 関数でウインドウを作成します。
  • その後、ShowWindow 関数でウインドウを表示します。
  • UpdateWindow 関数でウインドウの再描画を行います。

ウインドウ・プロシージャの処理

  1. WM_CREATE メッセージでウインドウの作成時処理を行います。
  2. WM_PAINT メッセージでウインドウの再描画処理を行います。
  3. WM_CLOSE メッセージでウインドウの終了処理を行います。
  4. WM_DESTROY メッセージでウインドウの破棄処理を行います。
WindowProc()
├─[WM_CREATE]
│
├─[WM_CLOSE]
│ └─DestroyWindow()
│
├─[WM_DESTROY]
│ └─PostQuitMessage()
│
├─[WM_PAINT]
│ ├─BeginPaint()
│ └─EndPaint()
│
└─DefWindowProc()

具体的なソースは次のようになります。

//------------------------------------------------
// break付きのキーワード
//------------------------------------------------
#define CASE        break;case
#define DEFAULT     break;default

//------------------------------------------------
// ウインドウ・プロシージャの関数
//------------------------------------------------
extern LRESULT CALLBACK mainWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
    switch ( uMsg ){
        CASE WM_CREATE:
        {
            HINSTANCE   hInstance   = ((LPCREATESTRUCT)lParam)->hInstance;
            LPVOID      lpParam     = ((LPCREATESTRUCT)lParam)->lpCreateParams;
            /*
            初期化の処理
            */
        }
        CASE WM_CLOSE:
            /*
            後始末の処理
            */
            DestroyWindow( hWnd );
        CASE WM_DESTROY:
            PostQuitMessage( 0 );
        CASE WM_PAINT:
        {
            PAINTSTRUCT     ps;
            HDC             hDC;
            
            hDC = BeginPaint( hWnd, &ps );
            /*
            描画の処理
            */
            EndPaint( hWnd, &ps );
        }
        CASE WM_ERASEBKGND:
            return 1;       /* 何も処理しない⇒塗り潰した */
        DEFAULT:return DefWindowProc( hWnd, uMsg, wParam, lParam );
    }
    return 0;
}

関連記事



コメント    この記事についてブログを書く
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする
« ダイアログアプリ3(ウインド... | トップ | 九九一覧の描画 »
最新の画像もっと見る

ウインドウ関連」カテゴリの最新記事