PeekMessage関数について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
Fimbul
記事: 100
登録日時: 12年前

PeekMessage関数について

#1

投稿記事 by Fimbul » 12年前

DirectX9、Windos APIを用いてウィンドウを作りスプライトを表示するプログラムです。

コード:

#include <windows.h>
#include <d3dx9.h>

#define CLASS_NAME TEXT("DirectX")
#define WINDOW_NAME TEXT("DirectX")

LPDIRECT3D9 pD3d; //Direct3Dオブジェクト
LPDIRECT3DDEVICE9 pDevice; //Direct3Dデバイスオブジェクト
LPDIRECT3DTEXTURE9 pTexture; //テクスチャオブジェクト
LPD3DXSPRITE pSprite; //スプライトオブジェクト

LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
HRESULT InitD3d(HWND hWnd); //Direct3Dの初期化関数
void DrawSprite(); //スプライトを描画する関数

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
	WNDCLASS wc;

	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc = WindowProc;
	wc.cbClsExtra = 0; //禁止用語になるので大文字で表記します
	wc.cbWndExtra = 0;
	wc.hInstance = hInstance;
	wc.hCursor = NULL;
	wc.hIcon = NULL;
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName = NULL;
	wc.lpszClassName = CLASS_NAME;

	if(!RegisterClass(&wc)) {
		return 1;
	}

	HWND hWnd;

	hWnd = CreateWindow(CLASS_NAME, WINDOW_NAME, WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 500, 500, NULL, NULL, hInstance, NULL);
	if(hWnd == NULL) {
		return 1;
	}

	//Direct3D初期化
	if(FAILED(InitD3d(hWnd))) {
		return 1;
	}

	MSG msg;

	//GetMessageの方
	/*
	while(GetMessage(&msg, NULL, 0, 0) > 0) {
		DrawSprite();
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	*/

	//PeekMessageの方
	while(true) {
		if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
			if(msg.message == WM_QUIT) {
				break;
			}

			TranslateMessage(&msg);
			DispatchMessage(&msg);
		} else {
			DrawSprite();
		}
	}

	return msg.wParam;
}

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

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

	return 0;
}

//Direct3D初期化関数
HRESULT InitD3d(HWND hWnd) {
	//Direct3Dオブジェクトの生成
	if(NULL == (pD3d = Direct3DCreate9(D3D_SDK_VERSION))) {
		MessageBox(hWnd, TEXT("Direct3Dオブジェクトの生成に失敗しました。"), TEXT("Error"), MB_OK);

		return E_FAIL;
	}

	//Direct3Dデバイスオブジェクトの生成
	D3DPRESENT_PARAMETERS d3dpp; 

	ZeroMemory(&d3dpp, sizeof(d3dpp));
	d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
	d3dpp.BackBufferCount = 1;
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3dpp.Windowed = true;

	if(FAILED(pD3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &pDevice))) {
		MessageBox(hWnd, TEXT("HALモードでDirect3Dデバイスオブジェクトの生成に失敗しました。\nREFモードで再試行します。"), TEXT("Error"), MB_OK);

		if(FAILED(pD3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, hWnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &pDevice))) {
			MessageBox(hWnd, TEXT("Direct3Dデバイスオブジェクトの生成に失敗しました。"), TEXT("Error"), MB_OK);

			return E_FAIL;
		}
	}

	//テクスチャオブジェクトの生成
	if(FAILED(D3DXCreateTextureFromFileEx(pDevice, TEXT("Sprite.bmp"), 100, 100, 0, 0, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT, D3DX_FILTER_NONE, D3DX_DEFAULT, 0xff000000, NULL, NULL, &pTexture))) {
		MessageBox(hWnd, TEXT("テクスチャオブジェクトの生成に失敗しました。"), TEXT("Error"), MB_OK);

		return E_FAIL;
	}

	//スプライトオブジェクトの生成
	if(FAILED(D3DXCreateSprite(pDevice, &pSprite))) {
		MessageBox(hWnd, TEXT("スプライトオブジェクトの生成に失敗しました。"), TEXT("Error"), MB_OK);

		return E_FAIL;
	}

	return S_OK;
}

//スプライトを描画する関数
void DrawSprite() {
	pDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(255, 255, 255), 1.0f, 0);

	if(SUCCEEDED(pDevice->BeginScene())) {
		RECT rect = {0, 0, 100, 100};

		D3DXVECTOR3 vec3Center(0, 0, 0);
		D3DXVECTOR3 vec3Position(200, 200, 0);

		pSprite->Begin(D3DXSPRITE_ALPHABLEND);
		pSprite->Draw(pTexture, &rect, &vec3Center, &vec3Position, 0xffffffff);
		pSprite->End();
		pDevice->EndScene();
	}

	pDevice->Present(NULL, NULL, NULL, NULL);
}
質問はGetMessage関数、PeekMessage関数のどちらを使えば良いかと言う事です。
GetMessage関数を用いればwhileでループするたびに必ずDrawSprite関数が呼ばれ、PeekMessage関数を用いるとアイドル時間のみDrawSprite関数が呼ばれる違いなのでしょうか。
そして、その違いが何の違いに繋がるのでしょうか。

アバター
うしお
記事: 56
登録日時: 13年前

Re: PeekMessage関数について

#2

投稿記事 by うしお » 12年前

msdnリファレンスによれば、
http://msdn.microsoft.com/ja-jp/library/cc364699.aspx
「GetMessage 関数とは異なり、PeekMessage 関数は、何かメッセージがポストされるのを待たずに制御を返します。」
とあります。つまるところここの違いになります。

GetMessage はメッセージキューに何か来ないかぎり処理をストップさせます。
しかし、ゲームの場合は、メッセージにかかわらず、秒間に数十~フレームまわしたいためにPeekMessage を用いるでしょう。
DirectXSDKサンプルも基本的にPeekMessage を使用しています。

逆になにかアクションを起きた時、例えばマウスを動かす、クリックする、キーボードを押すなどの時のみ、
なにか処理、描画をしたい、そんなアプリケーションはGetMessage を使用します。

Fimbul
記事: 100
登録日時: 12年前

Re: PeekMessage関数について

#3

投稿記事 by Fimbul » 12年前

うしお さんが書きました: GetMessage はメッセージキューに何か来ないかぎり処理をストップさせます。
処理をストップというのは、GetMessageを呼び出す場所で、停止すると言う事ですか。
例えばPlaySound関数で同期再生した時と同じような事が起こると思って良いのでしょうか。

アバター
うしお
記事: 56
登録日時: 13年前

Re: PeekMessage関数について

#4

投稿記事 by うしお » 12年前

PlaySoundは使ったことがありませんが、
ストップというのはその行で一時停止を意味しています。
すこし突っ込んだ言葉で言うと、そのGetMessage呼び出し元スレッドが一時停止します。
停止している間はCPUの処理は他のアプリケーションに移ります。
もちろんメッセージが来ればまたすぐに動き出します。

Fimbul
記事: 100
登録日時: 12年前

Re: PeekMessage関数について

#5

投稿記事 by Fimbul » 12年前

スレッドですか・・・。
スレッドは勉強していないのでよく分かりませんが、1つのプロセスを分割して制御するための物だとか。

PeekMessage関数はメッセージが無い場合でも制御を返してDispatchMessage関数を呼び出すならば、そのアプリケーションからCPUの処理が離れなくなってしまうのではないのでしょうか。

アバター
うしお
記事: 56
登録日時: 13年前

Re: PeekMessage関数について

#6

投稿記事 by うしお » 12年前

基本的にPeekMessageを用いて休みなしの処理を書いた場合、
while(true)
{
計算
}
のような形でループさせたのと同じ様にCPUを占有してしまいます。
しかし、実際はOSが裏で並列するアプリケーションを適度に切り替えているので、
PCが操作不能になる、などといったことはあまり無いでしょう。
例えば、無限ループのプログラムを実行させても開発環境は動いていますよね?
また、CPUコアが複数あれば、よりその可能性は下がります。

とはいえ普通は適度にSleepや画面の垂直同期等を入れることで、
CPUの使いすぎないために調整を行うこともあります。CPUの処理は共有資源であるためです。

Fimbul
記事: 100
登録日時: 12年前

Re: PeekMessage関数について

#7

投稿記事 by Fimbul » 12年前

なるほど・・・。
そういえばそうですよね、でなければパソコンが固まっちゃいますね(笑)。

うしおさんありがとうございました。

閉鎖

“C言語何でも質問掲示板” へ戻る