ウィンドウのクラス化に成功?


院試の結果が出て,ほっと一息な今日この頃.
先日,ウインドウのクラスかに失敗したので,デバックすることにした.

前回の作戦(?)は,SetWindowLong を使って「拡張ウインドウメモリ」にウインドウのポインタを格納して, それからウインドウプロシージャで GetWindowLong をつかってウインドウハンドルからポインタを取得せよ!!
ってなもんでした.


/*----------------------------------------------------------------------------------*/
/*  ウインドウプロシージャ                                                          */
/*----------------------------------------------------------------------------------*/
LRESULT CALLBACK GameWindow::WndProc ( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
    //---- ウインドウもポインタを得る.
    GameWindow * pWindow = (GameWindow*) GetWindowLong ( hWnd, 0 );

    if ( message == WM_CREATE ) {
        ::SetWindowLong ( hWnd, 0, lParam );
        pWindow = (GameWindow*) lParam ;
    }


    if ( pWindow == NULL )
        return ::DefWindowProc ( hWnd, message, wParam, lParam );
    else
        return pWindow->DispatchMessage ( hWnd, message, wParam, lParam );
}


これ,勘違いしてました.
リファレンス見た感じでは,CreateWindow の最後の引数の値が,WM_CREATE メッセージのときの LPARAM にセットされそう だったので,


    // ウインドウの作成
    m_hWnd  = ::CreateWindow ( wcex.lpszClassName,
        "ゲームウインドウ",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        NULL,
        NULL, 
        hInstance,
        (void*)this );


ってしてたんだけど,this の値と 実際に WM_CREATE でわたされる LPARAM の値が違ってました.
これで,仮想関数のテーブル参照できくて ダウンしちゃってたわけね.

今回は,全てのメッセージを処理させるのはあきらめました.
もう,WM_CREATE は無視しよう.
(ていうか,WM_CREATE以前にもメッセージは送られてくるようなので,どっちにしろ全て処理できてなかったが・・・)

というわけで,ウインドウのポインタは CreateWindow のあとにセットすることにしました.
で,ソースはこんな感じになりました.


/************************************************************************************/
/*                                                                                  */
/*      ■ Main.cpp ■                                                              */
/*                                                                                  */
/************************************************************************************/

#include <windows.h>
#include "GameWindow.h"

/*==================================================================================*/
/*  WinMain                                                                         */
/*==================================================================================*/
int APIENTRY WinMain (  HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
    MSG         msg ;
    GameWindow  window ;

    //---- ウインドウの作成
    window.Create ( hInstance, nCmdShow );

    //---- メッセージループ
    while ( GetMessage( &msg, NULL, 0, 0 ) )
    {
        TranslateMessage ( &msg );
        DispatchMessage ( &msg );
    }

    return msg.wParam ;
}
/************************************************************************************/
/*      EOF : Main.cpp                                                              */
/************************************************************************************/



/************************************************************************************/
/*                                                                                  */
/*      ■ GameWindow.h ■                                                          */
/*                                                                                  */
/************************************************************************************/
#ifndef _GAME_WINDOW_H_
#define _GAME_WINDOW_H_

#include 

/*==================================================================================*/
/*  GameWindow                                                                      */
/*      ゲーム用のウインドウクラス                                                  */
/*==================================================================================*/
class GameWindow 
{
protected:
    HWND    m_hWnd ;

public:
    GameWindow ();
    virtual ~GameWindow ();

    BOOL    Create ( HINSTANCE hInst, int nCmdShow );

    virtual BOOL OnCreate ();
    virtual BOOL OnInit ();
    virtual LRESULT DispatchMessage ( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam );
    static LRESULT CALLBACK WndProc ( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam );
};

#endif
/************************************************************************************/
/*      EOF : GameWindow.h                                                          */
/************************************************************************************/



/************************************************************************************/
/*                                                                                  */
/*      ■ GameWindow.cpp ■                                                        */
/*                                                                                  */
/************************************************************************************/

#include "GameWindow.h"

/*==================================================================================*/
/*  コンストラクタ                                                                  */
/*==================================================================================*/
GameWindow ::GameWindow ()
{
    m_hWnd  = NULL ;
}

/*==================================================================================*/
/*  デストラクタ                                                                    */
/*==================================================================================*/
GameWindow ::~GameWindow ()
{
    // ウインドウが破棄されたら ポインタを参照できなくする.
    ::SetWindowLong ( m_hWnd, 0, NULL );
}


/*----------------------------------------------------------------------------------*/
/*  ウインドウの作成                                                                */
/*----------------------------------------------------------------------------------*/
BOOL    GameWindow ::Create ( HINSTANCE hInstance, int nCmdShow )
{
    WNDCLASSEX  wcex ;

    // ウインドウクラス設定
    ::memset ( &wcex, 0, sizeof(WNDCLASSEX) );
    wcex.cbSize         = sizeof(WNDCLASSEX) ;
    wcex.style          = CS_HREDRAW | CS_VREDRAW ;
    wcex.lpfnWndProc    = (WNDPROC) WndProc ;
    wcex.cbClsExtra     = 0 ;
    wcex.cbWndExtra     = sizeof(LONG) ;        // 拡張メモリ(ここにポインタを格納)
    wcex.hInstance      = hInstance ;
    wcex.hIcon          = ::LoadIcon ( NULL, IDI_APPLICATION );
    wcex.hCursor        = ::LoadCursor ( NULL, IDC_ARROW );
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW + 1);
    wcex.lpszMenuName   = NULL ;
    wcex.lpszClassName  = "GameWindow";
    wcex.hIconSm        = ::LoadIcon ( NULL, IDI_APPLICATION );

    // ウインドウクラスの登録
    ::RegisterClassEx ( &wcex );


    // ウインドウの作成
    m_hWnd  = ::CreateWindow ( wcex.lpszClassName,
        "ゲームウインドウ",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        NULL,
        NULL, 
        hInstance,
        NULL );    // NULL にする

    if ( m_hWnd == NULL ) return FALSE ;

    ::SetWindowLong ( m_hWnd, 0, (LONG)this );    // ← ここでポインタをセットする

    OnCreate ();   // 一応

    // ウインドウの表示
    ::ShowWindow ( m_hWnd, nCmdShow );
    ::UpdateWindow ( m_hWnd );
    
    return TRUE ;
}

/*----------------------------------------------------------------------------------*/
/*  初期化                                                                          */
/*----------------------------------------------------------------------------------*/
BOOL GameWindow ::OnCreate ()
{
    return TRUE ;
}

/*----------------------------------------------------------------------------------*/
/*  ウインドウプロシージャ                                                          */
/*----------------------------------------------------------------------------------*/
LRESULT CALLBACK GameWindow::WndProc ( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
    //---- ウインドウもポインタを得る.
    GameWindow * pWindow = (GameWindow*) GetWindowLong ( hWnd, 0 );

    if ( pWindow == NULL )
        return ::DefWindowProc ( hWnd, message, wParam, lParam );
    else
        return pWindow->DispatchMessage ( hWnd, message, wParam, lParam );
}

/*----------------------------------------------------------------------------------*/
/*  メッセージを受け取って処理する.                                                */
/*----------------------------------------------------------------------------------*/
LRESULT GameWindow ::DispatchMessage ( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
    //---- メッセージごとの処理

    switch ( message ) {
    case WM_DESTROY :
        PostQuitMessage ( 0 );
        return 0 ;

    default :
        return ::DefWindowProc ( hWnd, message, wParam, lParam );
    }
}

/************************************************************************************/
/*      EOF : GameWindow.h                                                          */
/************************************************************************************/


んー,一応できたけどなー,どーかなー.



< Back to Diary.