C++ による Windows プログラミングの学習 1-1 ウィンドウを作成する

参考資料:
MSDN ライブラリ>Windows 開発>C++ による Windows プログラミングの学習>モジュール 1. 初めての Windows プログラム>ウィンドウを作成する
https://msdn.microsoft.com/ja-jp/library/ff381397(v=vs.85).aspx

RegisterClass
https://msdn.microsoft.com/ja-jp/library/cc410975.aspx

RegisterClassEx
https://msdn.microsoft.com/ja-jp/library/cc410996.aspx

WNDCLASSEX
https://msdn.microsoft.com/en-us/library/windows/desktop/ms633577(v=vs.85).aspx

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
  // ウィンドウ クラスを登録する
    const wchar_t CLASS_NAME[]  = L"Sample Window Class";
    
    WNDCLASS wc = { };
    wc.lpfnWndProc   = WindowProc;
    wc.hInstance     = hInstance;
    wc.lpszClassName = CLASS_NAME;

    RegisterClass(&wc);

ウィンドウクラス(WNDCLASS)を作成してRegisterClass()に渡しています。
“ウィンドウ クラス” は、複数のウィンドウが共通して実行する一連の動作を定義するもので、C++のクラス(class Window)とは別物です。

RegisterClass/WNDCLASSはRegisterClassEx/WNDCLASSEXを使ったほうが良いらしいのでそちらを使います。
それによりWNDCLASSEXの初期化部分に以下の分の追加が必要になります。

wc.cbSize = sizeof(WNDCLASSEXW);

Application(シングルトン)クラスを作って、
エントリポイントの引数であるhInstance,nCmdShowを渡し、
RegisterClassExもApplicationクラスメンバから呼び出すようにしてみました。
hInstance: インスタンスへのハンドル” または “モジュールへのハンドル” と呼ばれます。
 オペレーティング システムは、この値を使用して、メモリに読み込まれた実行可能ファイル (EXE) を特定します。
 このインスタンス ハンドルは、アイコンやビットマップを読み込むなど、Windows の特定の機能に必要です。
nCmdShow: メイン アプリケーション ウィンドウの最小化、最大化、通常表示を指定するためのフラグです。

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
	Application::InitializeInstance(hInstance,nCmdShow);
	
	// ウィンドウ クラスを登録する
	const wchar_t CLASS_NAME[] = L"Sample Window Class";
	WNDCLASSEXW wc = {};
	wc.cbSize = sizeof(WNDCLASSEXW);
	wc.lpfnWndProc = WindowProc;
	wc.lpszClassName = CLASS_NAME;

	Application::Instance().RegisterWindowClass(wc);

	// ウィンドウを作成する
	HWND hwnd = CreateWindowEx(
		0,                              // オプションのウィンドウ スタイル
		CLASS_NAME,                     // ウィンドウ クラス
		L"Learn to Program Windows",    // ウィンドウ テキスト
		WS_OVERLAPPEDWINDOW,            // ウィンドウ スタイル
										// サイズと位置
		CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
		NULL,       // 親ウィンドウ    
		NULL,       // メニュー
		Application::Instance().getHandle(),  // インスタンス ハンドル
		NULL        // 追加のアプリケーション データ
		);

	if (hwnd == NULL)
	{
		return 0;
	}

	ShowWindow(hwnd, Application::Instance().getCmdShow());

	// メッセージ ループを実行する
	MSG msg = {};
	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	Application::FinalizeInstance();
	return 0;
}
//Application.h
class Application
{
private:
	static Application* spAppInstance_;
public:

	static void InitializeInstance(HINSTANCE hInstance,int nCmdShow);
	static void FinalizeInstance();
	static Application& Instance();

private:
	HINSTANCE hInstance_;
	int nCmdShow_;
public:
	Application(HINSTANCE hInstance, int nCmdShow);
	~Application();

	void RegisterWindowClass(WNDCLASSEXW& exw);
	HINSTANCE getHandle()const;
	int getCmdShow() const;

};
//Application.cpp
//staticメンバのインスタンス作成
Application* Application::spAppInstance_;

void Application::InitializeInstance(HINSTANCE hInstance,int nCmdShow)
{
	FinalizeInstance();
	Application::spAppInstance_ = new Application(hInstance,nCmdShow);
}

void Application::FinalizeInstance()
{
	//インスタンスが作成済みだったら削除する
	if (Application::spAppInstance_)
	{
		delete Application::spAppInstance_;
		Application::spAppInstance_ = NULL;
	}
}

Application & Application::Instance()
{
	return *Application::spAppInstance_;
}

Application::Application(HINSTANCE hInstance, int nCmdShow)
{
	this->hInstance_ = hInstance;
	this->nCmdShow_ = nCmdShow;
}


Application::~Application()
{
}

void Application::RegisterWindowClass(WNDCLASSEXW& exw)
{
	exw.hInstance = this->hInstance_;
	::RegisterClassExW(&exw);
}

HINSTANCE Application::getHandle()const
{
	return this->hInstance_;
}

int Application::getCmdShow()const
{
	return this->nCmdShow_;
}

ウィンドウクラスの作成~ウィンドウの作成、表示をラップします。
ボタン等もウィンドウハンドルを持つウィンドウらしいのでWindowクラスじゃなくてFormクラスにしてみました。
とりあえず、WindowProc関数もFormクラスのstaticメンバにしておきます。

class Form
{
public:
	static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
private:
	HWND hwnd_;
public:
	Form();
	virtual ~Form();

	bool Show();
};
Form::Form()
{
	// ウィンドウ クラスを登録する
	const wchar_t CLASS_NAME[] = L"Sample Window Class";
	WNDCLASSEXW wc = {};
	wc.cbSize = sizeof(WNDCLASSEXW);
	wc.lpfnWndProc = Form::WindowProc;
	wc.lpszClassName = CLASS_NAME;

	Application::Instance().RegisterWindowClass(wc);

	// ウィンドウを作成する
	this->hwnd_ = CreateWindowEx(
		0,                              // オプションのウィンドウ スタイル
		CLASS_NAME,                     // ウィンドウ クラス
		L"Learn to Program Windows",    // ウィンドウ テキスト
		WS_OVERLAPPEDWINDOW,            // ウィンドウ スタイル
										// サイズと位置
		CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
		NULL,       // 親ウィンドウ    
		NULL,       // メニュー
		Application::Instance().getHandle(),  // インスタンス ハンドル
		NULL        // 追加のアプリケーション データ
		);
}

Form::~Form(){}

bool Form::Show()
{
	BOOL b = ShowWindow(hwnd_, Application::Instance().getCmdShow());
	return (b != 0);
}

LRESULT CALLBACK Form::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;

	case WM_PAINT:
	{
		PAINTSTRUCT ps;
		HDC hdc = BeginPaint(hwnd, &ps);
		FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
		EndPaint(hwnd, &ps);
	}
	return 0;

	}
	return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
	Application::InitializeInstance(hInstance,nCmdShow);
	
	Form form;
	form.Show();	

	// メッセージ ループを実行する
	MSG msg = {};
	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	Application::FinalizeInstance();
	return 0;
}

最後にメッセージループもApplicationクラスに移動してRun()メソッドとしました(ソースコード略)

このままでは何もできないので次は
ウィンドウメッセージによって、
ユーザーやオペレーティング システムによるさまざまなイベントに応答します

広告

akatukisiden について

フリーランスプログラマ 使用言語はC++,C#とそのつなぎのC++/CLI 専門はクライアントアプリ開発
カテゴリー: C++, WinAPI タグ: , , , , パーマリンク

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中