このページはゲームループの基礎講座シリーズの1つです。
今回は第3章の「ウインドウの作成」について説明します。(戻る)
ウインドウの作成
RegisterClassEx 関数でウインドウ・クラスの登録に成功したら実際にウインドウを作成します。
ウインドウの作成も CreateWindowEx という API 関数に必要な引数を渡して実行するだけで済みます。
ただし、渡す引数が少々多いので1つの引数に対して1行使って見やすく記述してます。
まずは関数のプロトタイプ宣言をご覧ください。
プロトタイプ宣言
HWND CreateWindowEx( DWORD dwExStyle, // 拡張ウインドウ・スタイル LPCTSTR lpClassName, // ウインドウのクラス名 LPCTSTR lpTitleName, // ウインドウのタイトル名 DWORD dwStyle, // ウインドウのスタイル int x, // ウインドウの横軸位置 int y, // ウインドウの縦軸位置 int nWidth, // ウインドウの横幅 int nHeight, // ウインドウの高さ HWND hWndParent, // 親ウインドウのハンドル HMENU hMenu, // メニューバーのハンドル(子ウインドウの識別ID) HINSTANCE hInstance, // インスタンスのハンドル LPVOID lpParam // ウインドウ作成のデータ );
今回は拡張ウインドウ・スタイル、メニューバー、ウインドウ作成データは使いません。
また、デスクトップが所有するトップレベル・ウインドウを作成するので親ウインドウのハンドルも必要ありません。
残りはゲーム・ウインドウを作成する上で必要な引数となります。
それではゲーム・ウインドウを作成する funcCreateWindow 関数のソースコードをご覧ください。
//------------------------------------------------ // ウインドウの作成(OK) //------------------------------------------------ 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; }
上記のうちでアプリケーションのインスタンス・ハンドル、ウインドウ・クラスの文字列、ウインドウ・タイトルの文字列は
ゲームによって異なる情報なので funcCreateWindow 関数の引数で受け取り CreateWindowEx 関数に渡してます。
また、ウインドウを作成しただけではメモリ内にウインドウを管理する情報が用意されただけです。
このままではデスクトップ画面にウインドウが表示されませんので ShowWindow 関数でウインドウを表示させてます。
この関数の第1引数にウインドウ作成に成功したウインドウ・ハンドルを渡して、第2引数でウインドウの表示状態を指定します。
ウインドウの表示状態も funcCreateWindow 関数の引数で受け取り ShowWindow 関数に渡します。
こうすることでショートカット・ファイル(*.lnk)で起動した時の「実行時の大きさ(R)」に対応できます。
- 通常のウインドウ
- 最小化
- 最大化
上記の3つのうちでゲーム・ウインドウを最大化で起動すると本当に最大化されます。
しかし、この表示状態を使えばショートカット・ファイル(*.lnk)でフル・スクリーンで起動するように改良できます。
今回はフル・スクリーンでの起動を考慮してないので説明は省略させてもらいます。
それではウインドウを作成する funcCreateWindow 関数を組み込んだソースコードをご覧ください。
ソース・ファイルに組み込む
//------------------------------------------------------------------------------ // 第3章 ウインドウの作成 //------------------------------------------------------------------------------ #include <tchar.h> #include <Windows.h> //------------------------------------------------ // break 付きのキーワード(OK) //------------------------------------------------ #define CASE break;case #define DEFAULT break;default //------------------------------------------------ // 記号定数(OK) //------------------------------------------------ #define ERRMSG_TITLE TEXT("WinMain関数") #define ERRMSG_WINREG TEXT("ウインドウ・クラスが登録できません。") #define ERRMSG_CREATE TEXT("ウインドウが作成できません。") //------------------------------------------------ // ウインドウのプロシージャ関数 //------------------------------------------------ static LRESULT CALLBACK mainWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch ( uMsg ){ CASE WM_CLOSE: DestroyWindow( hWnd ); CASE WM_DESTROY: PostQuitMessage( 0 ); DEFAULT: return DefWindowProc( hWnd, uMsg, wParam, lParam ); } return 0; } //------------------------------------------------ // ウインドウ・クラスの登録(OK) //------------------------------------------------ static ATOM funcWindowClass( HINSTANCE hInstance, LPCTSTR lpClassName ) { WNDCLASSEX wcex = { 0 }; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = 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 ); }//------------------------------------------------ // ウインドウの作成(OK) //------------------------------------------------ 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; }//------------------------------------------------ // メイン関数(OK) //------------------------------------------------ extern int WINAPI _tWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow ) { LPCTSTR lpClassName = TEXT("Lesson3WndClass"); LPCTSTR lpTitleName = TEXT("第3章 ウインドウの作成"); MSG Msg; // ウインドウ・クラスの登録 if ( funcWindowClass(hInstance,lpClassName) == 0 ){ MessageBox( NULL, ERRMSG_WINREG, ERRMSG_TITLE, (MB_OK|MB_ICONERROR) ); return -1; } // ウインドウの作成 if ( funcCreateWindow(hInstance,lpClassName,lpTitleName,nCmdShow) == NULL ){ MessageBox( NULL, ERRMSG_CREATE, ERRMSG_TITLE, (MB_OK|MB_ICONWARNING) ); return -2; } // メッセージ・ループ while ( GetMessage(&Msg,NULL,0,0) > 0 ){ TranslateMessage( &Msg ); DispatchMessage( &Msg ); } UNREFERENCED_PARAMETER( hPrevInstance ); UNREFERENCED_PARAMETER( lpCmdLine ); return Msg.wParam; } //------------------------------------------------------------------------------ // End of Lesson3.cpp //------------------------------------------------------------------------------
上記の 着色された場所 がウインドウを作成する funcCreateWindow 関数の部分です。
実行結果
実行するとウインドウが表示されます。
今回は funcWindowClass、funcCreateWindow 関数が正常に終了したのでエラー用のメッセージボックスは表示されませんでした。
もし、ウインドウ・クラスが登録できなかったり、ウインドウが作成されないとエラー用のメッセージボックスが表示されます。
それでは、これで第3章の「ウインドウの作成」についての説明は終わります。(つづく)
※コメント投稿者のブログIDはブログ作成者のみに通知されます