このページはゲームループの基礎講座シリーズの1つです。
今回は第5章の「ウインドウのプロシージャ関数」について説明します。(戻る)
プロシージャ関数
//------------------------------------------------ // ウインドウのプロシージャ関数(OK) //------------------------------------------------ static LRESULT CALLBACK mainWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch ( uMsg ){ CASE WM_CREATE: /* 初期化 */ 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_ENDSESSION: PostMessage( hWnd, WM_CLOSE, 0, 0 ); CASE WM_LBUTTONDOWN: SendMessage( hWnd, WM_NCLBUTTONDOWN, HTCAPTION, 0 ); CASE WM_LBUTTONDBLCLK: SetWindowPos( hWnd, HWND_TOPMOST, 0, 0, 0, 0, (SWP_NOMOVE|SWP_NOSIZE) ); CASE WM_RBUTTONDBLCLK: SetWindowPos( hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, (SWP_NOMOVE|SWP_NOSIZE) ); DEFAULT: return DefWindowProc( hWnd, uMsg, wParam, lParam ); } return 0; }
ソース・ファイルに組み込む
//------------------------------------------------------------------------------ // 第5章 ウインドウのプロシージャ関数 //------------------------------------------------------------------------------ #include <tchar.h> #include <Windows.h> //------------------------------------------------ // break 付きのキーワード(OK) //------------------------------------------------ #define CASE break;case #define DEFAULT break;default //------------------------------------------------ // 記号定数(OK) //------------------------------------------------ #define SCREEN_STYLE (WS_OVERLAPPEDWINDOW ^ (WS_THICKFRAME|WS_MAXIMIZEBOX)) #define SCREEN_WIDTH (640) // スクリーンの横幅(32ドット×20個) #define SCREEN_HEIGHT (480) // スクリーンの高さ(32ドット×15個) //------------------------------------------------ // 記号定数(OK) //------------------------------------------------ #define ERRMSG_TITLE TEXT("WinMain関数") #define ERRMSG_WINREG TEXT("ウインドウ・クラスが登録できません。") #define ERRMSG_CREATE TEXT("ウインドウが作成できません。")//------------------------------------------------ // ウインドウのプロシージャ関数(OK) //------------------------------------------------ static LRESULT CALLBACK mainWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch ( uMsg ){ CASE WM_CREATE: /* 初期化 */ 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_ENDSESSION: PostMessage( hWnd, WM_CLOSE, 0, 0 ); CASE WM_LBUTTONDOWN: SendMessage( hWnd, WM_NCLBUTTONDOWN, HTCAPTION, 0 ); CASE WM_LBUTTONDBLCLK: SetWindowPos( hWnd, HWND_TOPMOST, 0, 0, 0, 0, (SWP_NOMOVE|SWP_NOSIZE) ); CASE WM_RBUTTONDBLCLK: SetWindowPos( hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, (SWP_NOMOVE|SWP_NOSIZE) ); 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 VOID funcSetClientSize( HWND hWnd, LONG sx, LONG sy ) { RECT rc1; RECT rc2; GetWindowRect( hWnd, &rc1 ); GetClientRect( hWnd, &rc2 ); sx += ((rc1.right - rc1.left) - (rc2.right - rc2.left)); sy += ((rc1.bottom - rc1.top) - (rc2.bottom - rc2.top)); SetWindowPos( hWnd, NULL, 0, 0, sx, sy, (SWP_NOZORDER|SWP_NOOWNERZORDER|SWP_NOMOVE) ); } //------------------------------------------------ // ウインドウの作成(OK) //------------------------------------------------ static HWND funcCreateWindow( HINSTANCE hInstance, LPCTSTR lpClassName, LPCTSTR lpTitleName, int nCmdShow ) { HWND hWnd = CreateWindowEx( 0, // 拡張ウインドウ・スタイル lpClassName, // ウインドウのクラス名 lpTitleName, // ウインドウのタイトル名 SCREEN_STYLE, // ウインドウのスタイル CW_USEDEFAULT, // ウインドウの横軸位置 CW_USEDEFAULT, // ウインドウの縦軸位置 CW_USEDEFAULT, // ウインドウの横幅 CW_USEDEFAULT, // ウインドウの高さ NULL, // 親ウインドウのハンドル NULL, // メニューバーのハンドル hInstance, // インスタンスのハンドル NULL ); // ウインドウ作成のデータ if ( hWnd != NULL ){ funcSetClientSize( hWnd, SCREEN_WIDTH, SCREEN_HEIGHT ); ShowWindow( hWnd, nCmdShow ); UpdateWindow( hWnd ); } return hWnd; } //------------------------------------------------ // メイン関数(OK) //------------------------------------------------ extern int WINAPI _tWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow ) { LPCTSTR lpClassName = TEXT("Lesson5WndClass"); LPCTSTR lpTitleName = TEXT("第5章 ウインドウのプロシージャ関数"); 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 Lesson5.cpp //------------------------------------------------------------------------------
上記の 着色された場所 がウインドウ・プロシージャの mainWindowProc 関数の部分です。
雛型ウインドウとは
アプリケーションを作成する上で基本的なウインドウを雛型ウインドウと呼びます。
また、その基本ソースコードをスケルトン・プログラムと呼びます。
上記に紹介してるソース・ファイルこそ雛型ウインドウを表示するためのスケルトン・プログラムです。
このスケルトン・プログラムは、ゲーム以外にも利用できるソースコードですが、
使うときには記号定数の SCREEN_STYLE、SCREEN_WIDTH、SCREEN_HEIGHT などを修正する必要があるかもしれません。
また、funcCreateWindow 関数内で使ってる funcSetClientSize 関数を取り除くことで
CW_USEDEFAULT 定数で決められた既定のウインドウ・サイズが有効になります。
どの道、雛型ウインドウを表示するためのスケルトン・プログラムは一部を修正して使い回します。
それでは、これで第5章の「ウインドウのプロシージャ関数」についての説明は終わります。(つづく)
※コメント投稿者のブログIDはブログ作成者のみに通知されます