C++ による Windows プログラミングの学習 1-6 アプリケーション状態を管理する

MSDN ライブラリ>Windows 開発>C++ による Windows プログラミングの学習>モジュール 1. 初めての Windows プログラム>アプリケーション状態を管理する
https://msdn.microsoft.com/ja-jp/library/ff381400(v=vs.85).aspx

今回は1-3で触れたウィンドウプロシージャをメンバ関数にする話です。

まず、ウィンドウを表すクラスのコンストラクタで呼び出している
CreateWindowEx()の最後の引数lpParamにthisポインタ,作成中のオブジェクト自身を渡します。
渡されたオブジェクトはWM_NCCREATE,WM_CREATEメッセージのlParamに渡される
CREATESTRUCT型のオブジェクトのメlpCreateParamンバに代入されます。

WM_NCCREATEでこれを回収し、 SetWindowLongPtr()関数でウィンドウハンドルと関連付けます。
GetWindowLongPtr()関数でハンドルに関連付けられたオブジェクトを取得できるので、
ウィンドウプロシージャ内でメンバ関数を呼び出すことが出来ます。

WM_NCCREATE,WM_CREATEはCreateWindowEx()の終了前に呼び出されるので
ウィンドウハンドルをウィンドウを表すオブジェクトのメンバに保存する処理は、
これらのメッセージの処理内で行うようにします。

CreateWindowEx
https://msdn.microsoft.com/ja-jp/library/cc410714.aspx

SetWindowLongPtr()
https://msdn.microsoft.com/ja-jp/library/cc411204.aspx

GetWindowLongPtr()
https://msdn.microsoft.com/ja-jp/library/cc364762.aspx

class Form
{
public:
	static LRESULT CALLBACK WindowProc
            (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
				
private:
	LRESULT  WindowProc( UINT uMsg, WPARAM wParam, LPARAM lParam);
	HWND hwnd_;
public:
	Form();
	virtual ~Form();
	bool Show();
};
Form::Form()
{
	// ウィンドウ クラスを登録する
	const wchar_t CLASS_NAME[] = L"Form";
	WNDCLASSEXW wc = {};
	wc.cbSize = sizeof(WNDCLASSEXW);
	wc.lpfnWndProc = Form::WindowProc;
	wc.lpszClassName = CLASS_NAME;

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


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


/// static版ウィンドウプロシージャ
LRESULT CALLBACK Form::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	// ウィンドウ作成時メッセージ
	if (uMsg == WM_NCCREATE)
	{
		// lParamからCREATESTRUCTを取り出す。
		CREATESTRUCT *pCreate = reinterpret_cast<CREATESTRUCT*>(lParam);

		// CREATESTRUCTからウィンドウオブジェクトを取り出す。
		Form* f = reinterpret_cast<Form*>(pCreate->lpCreateParams);

		// ウィンドウハンドルを保存
		f->hwnd_ = hwnd;
		// ウィンドウオブジェクトとハンドルを関連付け
		SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(f));

	}

	{
		// ウィンドウハンドルに関連付けられたウィンドウオブジェクトを取得する
		LONG_PTR ptr = GetWindowLongPtr(hwnd, GWLP_USERDATA);
		if (ptr != 0)
		{
			// 関連付けされていた場合
			// メンバ関数版ウィンドウプロシージャを呼び出す。
			Form *f = reinterpret_cast<Form*>(ptr);
			return f->WindowProc(uMsg, wParam, lParam);
		}
		else
		{
			//関連付けられていなければデフォルトの処理を実行
			return DefWindowProc(hwnd, uMsg, wParam, lParam);
		}
	}
}

/// メンバ版ウィンドウプロシージャ
LRESULT Form::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	//とりあえずデフォルト処理
	return DefWindowProc(hwnd_, uMsg, wParam, lParam);
}

最後にこれらの処理をまとめて基底クラスへ移動します。

class Wnd
{
public:
	static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

protected:

	virtual LRESULT  WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
	HWND hwnd_;
public:
	Wnd();
	virtual ~Wnd();
};

/// static版ウィンドウプロシージャ
LRESULT CALLBACK Wnd::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	// ウィンドウ作成時メッセージ
	if (uMsg == WM_NCCREATE)
	{
		// lParamからCREATESTRUCTを取り出す。
		CREATESTRUCT *pCreate = reinterpret_cast<CREATESTRUCT*>(lParam);

		// CREATESTRUCTからウィンドウオブジェクトを取り出す。
		Wnd* f = reinterpret_cast<Wnd*>(pCreate->lpCreateParams);

		// ウィンドウハンドルを保存
		f->hwnd_ = hwnd;
		// ウィンドウオブジェクトとハンドルを関連付け
		SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(f));

	}

	{
		// ウィンドウハンドルに関連付けられたウィンドウオブジェクトを取得する
		LONG_PTR ptr = GetWindowLongPtr(hwnd, GWLP_USERDATA);
		if (ptr != 0)
		{
			// 関連付けされていた場合
			// メンバ関数版ウィンドウプロシージャを呼び出す。
			Wnd *f = reinterpret_cast<Wnd*>(ptr);
			return f->WindowProc(uMsg, wParam, lParam);
		}
		else
		{
			//関連付けられていなければデフォルトの処理を実行
			return DefWindowProc(hwnd, uMsg, wParam, lParam);
		}
	}
}

/// メンバ版ウィンドウプロシージャ
LRESULT Wnd::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	//とりあえずデフォルト処理
	return DefWindowProc(hwnd_, uMsg, wParam, lParam);
}

Wnd::Wnd(){}
Wnd::~Wnd(){}

class Form:public Wnd
{
protected:			
	LRESULT  WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
public:
	Form();
	virtual ~Form();
	bool Show();
};

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

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

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

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

/// メンバ版ウィンドウプロシージャ
LRESULT Form::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	return Wnd::WindowProc(uMsg, wParam, lParam);
}

広告
カテゴリー: C++, WinAPI | タグ: , , , , | コメントをどうぞ

C++ による Windows プログラミングの学習 1-5 ウィンドウを閉じる

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

閉じるボタン,Alt+F4などでウィンドウを閉じようとするとWM_CLOSEメッセージが送信される。
この時点ではまだキャンセルが可能で、ウィンドウプロシージャが0を返すことで、キャンセルが行われる
実際にウィンドウを閉じる場合は、DestroyWindow()メソッドを呼び出すか、
DefWindowProc()メソッドによるデフォルトの処理を呼び出す。

ウィンドウが閉じられた場合WM_DESTORYメッセージが送信される。
ウィンドウを閉じたときにアプリケーション自体も終了する場合、
PostQuitMessage(0)を呼び出す。
するとWM_QUITメッセージが送信され、メッセージループを脱出してアプリケーション終了する。

カテゴリー: C++, WinAPI | タグ: , , , , | コメントをどうぞ

C++ による Windows プログラミングの学習 1-4 ウィンドウに描画する

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

ウィンドウの再描画が必要なの時
(画面を最初に表示されるとき、
他のウィンドウなどと重なっていて表示されていなかった領域が再び表示された時,
ウィンドウサイズの変更により新たな領域が表示された時等)
そのウィンドウに対してWM_PAINTが送信されます。
タイトルバーやウィンドウの周りのフレームはWindowsにより描画されるため、
描画コードを書く必要があるのはクライアント領域のみになります。

BeginPaint関数を呼び出して描画を開始し、終了時にはEndPaint関数を呼び出します。
BeginPaint関数では、引数に渡すPAINTSTRUCT構造体に再描画要求に関する情報が
渡されます。描画が必要な領域はクライアント領域の相対位置として、rcPaint メンバーに代入されています。

	case WM_PAINT:
	{
		PAINTSTRUCT ps;
		HDC hdc = BeginPaint(hwnd, &ps);
		// すべての描画がこの BeginPaint と EndPaint の間で実行される
		::FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
		EndPaint(hwnd, &ps);

		return 0;
	}
カテゴリー: C++, WinAPI | タグ: , , , , | コメントをどうぞ

C++ による Windows プログラミングの学習 1-3 ウィンドウ プロシージャを記述する

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

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

ウィンドウプロシージャには戻り値LRESULT と4つの引数があります。
hwnd:ウィンドウへのハンドル
uMsg:メッセージ コード。たとえば WM_SIZE メッセージはウィンドウのサイズが変更されたことを示す。
wParam,lParam:メッセージに関する追加情報,ポインターと同じサイズを持つを格納します。正確な意味はメッセージ コードごとに異なる。
LRESULT:プログラムが Windows に返す整数値、特定のメッセージに対するプログラムの応答。正確な意味はメッセージ コードごとに異なる。

wParam/lParamはポインターと同じサイズ(32bit OR 64bit)を持つ整数値で
通常、構造体のアドレスまたは数値です。
数値の場合、合計32bit以下の複数の値が格納されている場合がありその場合は
bit演算で各値を取り出す必要があります。
またあらかじめ値を取り出すためのマクロが用意されている場合があります

ウィンドウのサイズを変更したときに発生するメッセージWM_SIZE はLParamが16bit値二つでマクロそれぞれLOWORD()、HIWORD()、で取り出すことが出来ます。
全ての処理をウィンドウプロシージャに書くのはわかりにくいため必要なデータを取り出したら別の関数に渡すようにします。

メッセージを特に処理しない場合は既定の動作としDefWindowProc()関数を呼び出します。

LRESULT CALLBACK Form::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
	case WM_SIZE:
	{
		int width = LOWORD(lParam);  // 下位ワードを取得するマクロ
		int height = HIWORD(lParam); // 上位ワードを取得するマクロ

									 // メッセージに応答:
		Form::OnSize(hwnd, (UINT)wParam, width, height);
		return 0;
	};
	}
	return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

void Form::OnSize(HWND hwnd, unsigned int flag, int width, int height)
{
	// ウィンドウサイズ変更時の処理
}

現状メッセージを処理するための関数がFormクラスがstatic関数にになっています。
どうにかして通常のメンバ関数にしたいと思います、
最初はstd::mapなどを用いて、ウィンドウハンドルとオブジェクトを関連付けようと思ったのですが、
専用のAPIがある様です、これについては後で解説します。

カテゴリー: C++, WinAPI | タグ: , , , , | コメントをどうぞ

C++ による Windows プログラミングの学習 1-2 ウィンドウメッセージ

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

GetMessage()
https://msdn.microsoft.com/ja-jp/library/cc364699.aspx

TranslateMessage()
https://msdn.microsoft.com/ja-jp/library/cc364841.aspx

DispatchMessage()
https://msdn.microsoft.com/ja-jp/library/cc410766.aspx

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

GUI アプリケーションはユーザーとオペレーティング システムによるさまざまなイベントに応答しなければなりません。

  • ユーザーによるイベント:
  • マウス クリック、キー操作、タッチスクリーン ジェスチャ,etc…

  • オペレーティング システムによるイベント:
  • プログラムの “外部” から行われ、プログラムの動作に影響を与えるすべてのイベント。
    ハードウェアデバイスの接続、スリープ、休止状態、etc…

Windows ではオペレーティング システムは、メッセージを用いてアプリケーションとの対話を行います。
ウィンドウを作成するスレッドごとに,メッセージ用のキューが作成されます。
このキューが、そのスレッドで作成されるすべてのウィンドウに向けられるメッセージを保持します。

GetMessage()メソッドで呼び出したスレッドのキューからメッセージを取り出し
DispathMessage()メソッドは、そのメッセージを処理するため、
適切なウィンドウのウィンドウプロシージャを呼び出します。
TransMessage()メソッドはキーボード入力に関連付けられており、これがキー操作 (キーを押す、キーを離す) を文字に変換します。DispatchMessage の直前に呼び出すということだけ覚えておけば、この関数の実際の処理を理解する必要はありません。

GetMessage()はキューにメッセージがなかった場合、メッセージが追加されるまで待機してから
そのメッセージを取り出します、
またメッセージが WM_QUIT の時0を返しwhileループを抜けます
それメッセージの値がそれ以外の時0以外の値を返し、ループが続きます。

カテゴリー: C++, WinAPI | タグ: , , , , | コメントをどうぞ

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()メソッドとしました(ソースコード略)

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

カテゴリー: C++, WinAPI | タグ: , , , , | コメントをどうぞ

C++ による Windows プログラミングの学習 1-0 初めての Windows プログラム

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

まず、新しいプロジェクトを作成します。
※各操作はVisual Studio 2015での物

ファイル>新規作成>プロジェクト>Visual C++>Win32プロジェクト
でプロジェクトを作成
ウィザードが表示されるのでアプリケーションの種類で
Windows アプリケーションを選択して完了

個人的に、使いまわせそうなラッパーはライブラリ化したいので
もう一つスタティックリンクライブラリを作成しておきます。

ファイル>追加>新しいプロジェクト>Visual C++>Win32プロジェクト
でプロジェクトを追加し、今度は、アプリケーションの種類でスタティックライブラリを選択して完了します。

アプリケーションプロジェクトから、ライブラリプロジェクトを参照するように設定します。

ソリューションエクスプローラーでアプリケーションプロジェクトで右クリック
>追加>参照>参照の追加ウィンドウが表示されるので
作成したスタティックライブラリプロジェクトをチェックしてOKします。

最初から書かれているコードを削除して
MSDNからサンプルコードを貼り付けます

#include <windows.h>

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);

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

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

	ShowWindow(hwnd, nCmdShow);

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

	return 0;
}

LRESULT CALLBACK 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);
}

とりあえず実行結果

カテゴリー: C++, WinAPI | タグ: , , , , | コメントをどうぞ