読み込み中にアクセス違反が発生しました[VisualStudio2008 C++]

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
Uriaria

読み込み中にアクセス違反が発生しました[VisualStudio2008 C++]

#1

投稿記事 by Uriaria » 11年前

現在windowを表示するアプリケーションを作成しています
後述のソースをビルドすると
0x00d00e26 でハンドルされていない例外が発生しました: 0xC0000005: 場所 0x00000000 を読み込み中にアクセス違反が発生しました。
と表示されプログラムが終了してしまいます
呼び出し履歴を見るとRender関数の中でエラーが発生しているのですが、何が原因で起こっているかが解りません
どのようにソースを修正すれば問題が解消されるでしょうか。よろしくお願いします

コード:

#include <windows.h>
#include <d3d9.h>
#include <d3dx9.h>
#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }

LPDIRECT3D9 g_pD3D;
D3DPRESENT_PARAMETERS g_D3DPParams;
LPDIRECT3DDEVICE9 g_pD3DDevice = 0;
HRESULT InitDirect3D(HWND hWnd);
VOID Render(LPDIRECT3DDEVICE9 theDevice);
VOID CleanUpDirect3D(void);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow){
	HWND windhwnd;
	GetKeyBoard();
	windhwnd = CreateWindow(
			"UKM",		// ウィンドウクラスの名前
			"SDKで作成したウィンドウ",	// ウィンドウのキャプション
			WS_OVERLAPPEDWINDOW,		// ウィンドウスタイル
			CW_USEDEFAULT,			// ウィンドウのx座標
			CW_USEDEFAULT,			// ウィンドウのy座標
			CW_USEDEFAULT,			// ウィンドウの幅
			CW_USEDEFAULT,			// ウィンドウの高さ
			NULL,				// 親ウィンドウのハンドル
			NULL,				// メニューのハンドル
			hInstance,			// アプリケーションのインスタンスハンドル
			NULL );				// WM_CREATEメッセージのlParamへ渡す値

	ShowWindow(windhwnd, nCmdShow);	// ウィンドウの表示状態を設定
	UpdateWindow(windhwnd);			// ウィンドウのクライアント領域を更新
	InitDirect3D(windhwnd);
	Render(g_pD3DDevice);
	CleanUpDirect3D();
}

HRESULT InitDirect3D(HWND hWnd)
{
	//Direct3Dオブジェクトの生成
	if(NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION))){return(E_FAIL);}

	//Direct3Dデバイスを生成するための構造体を設定する。Zバッファ尽付き
	ZeroMemory(&g_D3DPParams, sizeof(D3DPRESENT_PARAMETERS));

	//プレゼンテーションパラメータ

	//今表示されているモニタの設定と同じ
	g_D3DPParams.BackBufferFormat = D3DFMT_UNKNOWN;

	//ウィンドウモードにする
	g_D3DPParams.BackBufferCount = 1;

	//マルチサンプリングは行わない
	g_D3DPParams.MultiSampleType = D3DMULTISAMPLE_NONE;

	//マルチサンプリングは行わないので0
	g_D3DPParams.MultiSampleQuality = 0;

	//Direct3Dにスワップエフェクトをまかせる
	g_D3DPParams.SwapEffect = D3DSWAPEFFECT_DISCARD;

	//Direct3Dに震度バッファの管理を任せる
	g_D3DPParams.EnableAutoDepthStencil = TRUE;

	//震度バッファのフォーマット(通常はこの値で問題ない)
	g_D3DPParams.AutoDepthStencilFormat= D3DFMT_D16;

	//カバーウインドウ=アプリケーションのウィンドウ
	g_D3DPParams.hDeviceWindow = hWnd;

	//フラグは使わない
	g_D3DPParams.Flags = 0;

	//今のリフレッシュレートをそのまま使う
	g_D3DPParams.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;

	//モニタの垂直回帰を待つ
	g_D3DPParams.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;

	//CreateDeviceでDirect3Dを初期化するとき、HAL、HELの組み合わせは
	//プログラマーが自由に決めることができるが
	//普通はこの組み合わせで十分

	//Direct3Dデバイスの生成。まず、HALのいいやつ

	if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,D3DCREATE_HARDWARE_VERTEXPROCESSING, &g_D3DPParams, &g_pD3DDevice)))
	{
		//コケたら普通のHAL(HEL?)
		if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING, &g_D3DPParams, &g_pD3DDevice)))
		{
			if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING, &g_D3DPParams, &g_pD3DDevice)))
			{
				//それでもコケたらおしまい
				//MessageBox(NULL, "Direct3Dを初期化できませんでした", KWINDOW_TITLE, MB_OK | MB_ICONSTOP);
				return(E_FAIL);
			}
		}
	}
	return(S_OK);
}

//----------------------------------------Render
//
//	実際の描画作業
//
//----------------------------------------
VOID Render(LPDIRECT3DDEVICE9 theDevice)
{
	//Zバッファとバックバッファのクリア
	theDevice->Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 64), 1.0f, 0);

	//シーンの開始
	if(SUCCEEDED(theDevice->BeginScene()))
	{
		//終わりの定型処理
		theDevice->EndScene();		//シーンの終了
	}

	//バックバッファ表画面に反得させる
	HRESULT hr = theDevice->Present(NULL, NULL, NULL, NULL);

}

//-----------------------------------------CleanUpDirect3D
//
//	Direct3Dの後始末
//
//-----------------------------------------
VOID CleanUpDirect3D(void)
{
	//Direct3Dデバイスなどの解放
	SAFE_RELEASE(g_pD3DDevice);
	SAFE_RELEASE(g_pD3D);
}

naohiro19
記事: 256
登録日時: 14年前
住所: 愛知県

Re: 読み込み中にアクセス違反が発生しました[VisualStudio2008 C++]

#2

投稿記事 by naohiro19 » 11年前

メッセージループとウィンドウプロシージャーがありません。

Uriaria

Re: 読み込み中にアクセス違反が発生しました[VisualStudio2008 C++]

#3

投稿記事 by Uriaria » 11年前

naohiro19 さんが書きました:メッセージループとウィンドウプロシージャーがありません。
回答ありがとうございます。ウィンドウプロシージャを調べてみたところこれがないとアプリケーションが操作を読み取れないのですね。知りました
メッセージループを追加し、ソースを修正したところ前に起こっていたエラー文はなくなりました
ですがウィンドウは表示されません。どこか順序や方法が間違っているのでしょうか?よろしくお願いします

コード:

#include <windows.h>
#include <d3d9.h>
#include <d3dx9.h>
#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }

LPDIRECT3D9 g_pD3D;
D3DPRESENT_PARAMETERS g_D3DPParams;
LPDIRECT3DDEVICE9 g_pD3DDevice = 0;
HRESULT InitDirect3D(HWND hWnd);
VOID Render(LPDIRECT3DDEVICE9 theDevice);
VOID CleanUpDirect3D(void);

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

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow){
	HWND windhwnd;
	MSG msg;
	windhwnd = CreateWindow(
			"UKM",		// ウィンドウクラスの名前
			"SDKで作成したウィンドウ",	// ウィンドウのキャプション
			WS_OVERLAPPEDWINDOW,		// ウィンドウスタイル
			CW_USEDEFAULT,			// ウィンドウのx座標
			CW_USEDEFAULT,			// ウィンドウのy座標
			CW_USEDEFAULT,			// ウィンドウの幅
			CW_USEDEFAULT,			// ウィンドウの高さ
			NULL,				// 親ウィンドウのハンドル
			NULL,				// メニューのハンドル
			hInstance,			// アプリケーションのインスタンスハンドル
			NULL );				// WM_CREATEメッセージのlParamへ渡す値

	ShowWindow(windhwnd, nCmdShow);	// ウィンドウの表示状態を設定
	UpdateWindow(windhwnd);			// ウィンドウのクライアント領域を更新
	InitDirect3D(windhwnd);
	
	while (GetMessage(&msg, NULL, 0, 0) > 0) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return msg.wParam;
}

HRESULT InitDirect3D(HWND hWnd)
{
	//Direct3Dオブジェクトの生成
	if(NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION))){return(E_FAIL);}

	//Direct3Dデバイスを生成するための構造体を設定する。Zバッファ尽付き
	ZeroMemory(&g_D3DPParams, sizeof(D3DPRESENT_PARAMETERS));

	//プレゼンテーションパラメータ

	//今表示されているモニタの設定と同じ
	g_D3DPParams.BackBufferFormat = D3DFMT_UNKNOWN;

	//ウィンドウモードにする
	g_D3DPParams.BackBufferCount = 1;

	//マルチサンプリングは行わない
	g_D3DPParams.MultiSampleType = D3DMULTISAMPLE_NONE;

	//マルチサンプリングは行わないので0
	g_D3DPParams.MultiSampleQuality = 0;

	//Direct3Dにスワップエフェクトをまかせる
	g_D3DPParams.SwapEffect = D3DSWAPEFFECT_DISCARD;

	//Direct3Dに震度バッファの管理を任せる
	g_D3DPParams.EnableAutoDepthStencil = TRUE;

	//震度バッファのフォーマット(通常はこの値で問題ない)
	g_D3DPParams.AutoDepthStencilFormat= D3DFMT_D16;

	//カバーウインドウ=アプリケーションのウィンドウ
	g_D3DPParams.hDeviceWindow = hWnd;

	//フラグは使わない
	g_D3DPParams.Flags = 0;

	//今のリフレッシュレートをそのまま使う
	g_D3DPParams.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;

	//モニタの垂直回帰を待つ
	g_D3DPParams.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;

	//CreateDeviceでDirect3Dを初期化するとき、HAL、HELの組み合わせは
	//プログラマーが自由に決めることができるが
	//普通はこの組み合わせで十分

	//Direct3Dデバイスの生成。まず、HALのいいやつ

	if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,D3DCREATE_HARDWARE_VERTEXPROCESSING, &g_D3DPParams, &g_pD3DDevice)))
	{
		//コケたら普通のHAL(HEL?)
		if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING, &g_D3DPParams, &g_pD3DDevice)))
		{
			if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING, &g_D3DPParams, &g_pD3DDevice)))
			{
				//それでもコケたらおしまい
				//MessageBox(NULL, "Direct3Dを初期化できませんでした", KWINDOW_TITLE, MB_OK | MB_ICONSTOP);
				return(E_FAIL);
			}
		}
	}
	return(S_OK);
}

//----------------------------------------Render
//
//	実際の描画作業
//
//----------------------------------------
VOID Render(LPDIRECT3DDEVICE9 theDevice)
{
	//Zバッファとバックバッファのクリア
	theDevice->Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 64), 1.0f, 0);

	//シーンの開始
	if(SUCCEEDED(theDevice->BeginScene()))
	{
		//終わりの定型処理
		theDevice->EndScene();		//シーンの終了
	}

	//バックバッファ表画面に反得させる
	HRESULT hr = theDevice->Present(NULL, NULL, NULL, NULL);

}

//-----------------------------------------CleanUpDirect3D
//
//	Direct3Dの後始末
//
//-----------------------------------------
VOID CleanUpDirect3D(void)
{
	//Direct3Dデバイスなどの解放
	SAFE_RELEASE(g_pD3DDevice);
	SAFE_RELEASE(g_pD3D);
}

LRESULT CALLBACK WndProc(
    HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg) {
    case WM_DESTROY:
		CleanUpDirect3D();
        PostQuitMessage(0);
        break;
	case WM_PAINT:
		Render(g_pD3DDevice);
		break;
	}
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}


Milla

Re: 読み込み中にアクセス違反が発生しました[VisualStudio2008 C++]

#5

投稿記事 by Milla » 11年前

いや、おかしくないね。
表示っていってたから、とりあえずSHOWWINDOWかなとおもたけど。
強制SH_SHOWにしても表示されない?

Milla

Re: 読み込み中にアクセス違反が発生しました[VisualStudio2008 C++]

#6

投稿記事 by Milla » 11年前

WNDCLASSEX型の構造体をRegisterClassExで登録しないとだめ。

コード:

WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_APPLICATION));
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = 0;
wc.lpszClassName = _title;
wc.hIconSm = wc.hIcon;

if(!RegisterClassEx(&wc))
{
    return 0;
}

// この後CreateWindow

Uriaria

Re: 読み込み中にアクセス違反が発生しました[VisualStudio2008 C++]

#7

投稿記事 by Uriaria » 11年前

Milla さんが書きました:いや、おかしくないね。
表示っていってたから、とりあえずSHOWWINDOWかなとおもたけど。
強制SH_SHOWにしても表示されない?
回答ありがとうございます。引数を変えてみましたがウィンドウは表示されませんでした
おかしいと思いブレークポイントを置いてみたところウィンドウを作成したばかりのハンドルの中身がNULLになっていました※1
作成しているはずなのに中身が無いというのはどうしてなのでしょうか?よろしくお願いします

それとウィンドウが作成されたと仮定して進めた場合、メッセージループに入りメッセージを読み取り変換してwindowsに送出するところまで処理しました
ですが肝心のメッセージを処理する関数の中にブレークポイントを置いても中に入っていませんでした※2
このCALLBACK関数はDispatchMessageを処理した時に処理されるものだと認識しているのですが間違っているのでしょうか?よろしくお願いします

コード:

LRESULT CALLBACK WndProc(
    HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg) {       //※2ブレークポイント
    case WM_DESTROY:
		CleanUpDirect3D();
        PostQuitMessage(0);
        break;
	case WM_PAINT:
		Render(g_pD3DDevice);
		break;
	case WM_LBUTTONUP:
		MessageBox(hwnd , TEXT("終わります") ,
		TEXT("Kitty") , MB_ICONINFORMATION);
		exit(0);
	}
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow){
	HWND windhwnd;
	MSG msg;
	WNDCLASSEX wc;
	nCmdShow = SW_SHOW;
	wc.cbSize = sizeof(WNDCLASSEX);
	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc = WndProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = hInstance;
	wc.hCursor = LoadCursor(0, IDC_ARROW);
	wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName = 0;
	wc.lpszClassName = "_title";
	wc.hIconSm = wc.hIcon;
	 
	if(!RegisterClassEx(&wc))
	{
		return 0;
	}
 
	// この後CreateWindow
	windhwnd = CreateWindow(
			"UKM",		// ウィンドウクラスの名前
			"SDKで作成したウィンドウ",	// ウィンドウのキャプション
			WS_OVERLAPPEDWINDOW,		// ウィンドウスタイル
			CW_USEDEFAULT,			// ウィンドウのx座標
			CW_USEDEFAULT,			// ウィンドウのy座標
			CW_USEDEFAULT,			// ウィンドウの幅
			CW_USEDEFAULT,			// ウィンドウの高さ
			NULL,				// 親ウィンドウのハンドル
			NULL,				// メニューのハンドル
			hInstance,			// アプリケーションのインスタンスハンドル
			NULL );				// WM_CREATEメッセージのlParamへ渡す値

	if (windhwnd == NULL) return 0;    //※1ブレークポイント

	ShowWindow(windhwnd, nCmdShow);	// ウィンドウの表示状態を設定
	UpdateWindow(windhwnd);			// ウィンドウのクライアント領域を更新
	InitDirect3D(windhwnd);
	while (TRUE) {
		GetMessage(&msg , NULL , 0 , 0);
           TranslateMessage(&msg);
            DispatchMessage(&msg);
      }

      return msg.wParam;
}

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 読み込み中にアクセス違反が発生しました[VisualStudio2008 C++]

#8

投稿記事 by みけCAT » 11年前

この場合、RegisterClassExに渡すクラス名とCreateWindowに渡すクラス名は一致させないといけないと思います。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

Ryo

Re: 読み込み中にアクセス違反が発生しました[VisualStudio2008 C++]

#9

投稿記事 by Ryo » 11年前

せっかくRegisterClassExで登録したのに、そのウィンドウクラスのクラス名と
CreateWindowに引き渡しているウィンドウクラス名が違っています
これでは、意味がない
Uriaria さんが書きました:それとウィンドウが作成されたと仮定して進めた場合、メッセージループに入りメッセージを読み取り変換してwindowsに送出するところまで処理しました
ですが肝心のメッセージを処理する関数の中にブレークポイントを置いても中に入っていませんでした※2
ウィンドウが作成されていないと受け取れません。

この場合
1.RegisterClassExにて「WndProcを受け取り口にする(27行目)」というクラスを登録
2.そのクラスをCreateWindowで実際に作成
3.メッセージループで、メッセージ待ちを延々と繰り返す
という流れです

Uriaria

Re: 読み込み中にアクセス違反が発生しました[VisualStudio2008 C++]

#10

投稿記事 by Uriaria » 11年前

みけCAT さんが書きました:この場合、RegisterClassExに渡すクラス名とCreateWindowに渡すクラス名は一致させないといけないと思います。
Ryo さんが書きました:せっかくRegisterClassExで登録したのに、そのウィンドウクラスのクラス名と
CreateWindowに引き渡しているウィンドウクラス名が違っています
これでは、意味がない

回答ありがとうございます。ウィンドウクラス名を同じにしたところ無事ウィンドウを表示することができました
ですが当初の問題だったアクセス違反がまた起きてしまい描画を処理する関数を処理することができません
ブレークポイントを置いたところRender関数の処理でアクセス違反が発生している様なのですがなにが原因なのでしょうか?よろしくお願いします

コード:

//宣言です
LPDIRECT3D9 g_pD3D;
D3DPRESENT_PARAMETERS g_D3DPParams;
LPDIRECT3DDEVICE9 g_pD3DDevice = 0;
HRESULT InitDirect3D(HWND hWnd);
VOID Render(LPDIRECT3DDEVICE9 theDevice);
VOID CleanUpDirect3D(void);

//プロシージャです
LRESULT CALLBACK WndProc(
    HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg) {
    case WM_DESTROY:
		CleanUpDirect3D();
        PostQuitMessage(0);
        break;
	case WM_PAINT:
		Render(g_pD3DDevice);
		break;
	case WM_LBUTTONUP:
		MessageBox(hwnd , TEXT("終わります") ,
		TEXT("Kitty") , MB_ICONINFORMATION);
		CleanUpDirect3D();
		exit(0);
	}
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
//----------------------------------------Render
//
//	実際の描画作業
//
//----------------------------------------
VOID Render(LPDIRECT3DDEVICE9 theDevice)
{
	//Zバッファとバックバッファのクリア
	theDevice->Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 64), 1.0f, 0);

	//シーンの開始
	if(SUCCEEDED(theDevice->BeginScene()))
	{
		//終わりの定型処理
		theDevice->EndScene();		//シーンの終了
	}

	//バックバッファ表画面に反得させる
	HRESULT hr = theDevice->Present(NULL, NULL, NULL, NULL);

}

Milla

Re: 読み込み中にアクセス違反が発生しました[VisualStudio2008 C++]

#11

投稿記事 by Milla » 11年前

コード:

//プロシージャです
LRESULT CALLBACK WndProc(
    HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg) {
    case WM_DESTROY:
        CleanUpDirect3D();
        PostQuitMessage(0);
        break;
    case WM_PAINT:
        Render(g_pD3DDevice);
        break;
    case WM_LBUTTONUP:
        MessageBox(hwnd , TEXT("終わります") ,
        TEXT("Kitty") , MB_ICONINFORMATION);
        CleanUpDirect3D();
        exit(0);
    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
けっこう破壊的なプロシージャ書いてるね。
まず、exit(0);で終了はまずい。おそらく強制終了的な終わり方になっているはず。
ウィンドウプログラムの作法に則って終了するべき。

正しい終わり方については以下のリンクが参考になると思う。
http://msdn.microsoft.com/ja-jp/library ... 85%29.aspx

いちおう正答を書いておくと
やりたいことが左クリックでウィンドウを閉じて、終了なら

コード:

LRESULT CALLBACK WndProc(
    HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg) {
    case WM_DESTROY:
        CleanUpDirect3D();
        PostQuitMessage(0);
        break;
    case WM_PAINT:
        Render(g_pD3DDevice);
        break;
    case WM_LBUTTONDOWN:
        PostMessage(hWnd, WM_CLOSE, NULL, NULL);
        break;
    }
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
またmain関数内のメッセージループも抜けないと、main関数が終了しないでプロセスが残ったままになるので、こうかな。

コード:

while (1)
{
    // 後々、メッセージループでRenderするためにメッセージ待ちを行わないPeekMessageへと変更しときます。
    if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
        // 終了メッセージがきたら終了
        if (msg.message == WM_QUIT)
        {
            break;
        }
        /* ちなみにWM_PAINTでRenderするのはあまりよくないらしいので
        else (FPSController(60))  // FPS制御関数
        {
            Render(g_pD3DDevice);
        }
        コメントを外すとメッセージループでRenderする。FPS制御関数は自作してください
        */
    }
    // ほかのプロセスの処理時間を与えるためにSleep(0);する。しないと超重くなる
    Sleep(0);
}
さらにさらにInitDirect3D()内のこの部分を

コード:

//ウィンドウモードにする
g_D3DPParams.BackBufferCount = 1;
こうしましょうw

コード:

//ウィンドウモードにする
g_D3DPParams.Windowed = TRUE;
ここが間違えてるので、D3DDeviceの作成に失敗しています。
なので実体のないポインタでClear()しようとして、アクセス違反が起きています。
なんのためのHRESULT型の関数なのか。。。

WinMain()のInirDirect3D()の呼び出しをこうしとけば、防げた。

コード:

if( FAILED( InitDirect3D( hWnd ) ) )
{
    return 0;
}

Milla

Re: 読み込み中にアクセス違反が発生しました[VisualStudio2008 C++]

#12

投稿記事 by Milla » 11年前

失礼。
正しくはWM_PAINTでRenderするのがまずいわけではなく
ゲームプログラミングで、ゲームメイン処理の関数内にRenderをまとめてしまう場合において、
WM_PAINT内にゲームメイン処理の関数を書くのがまずい。はず。
おそらく、"WM_PAINTが発行されなければゲームの処理が進まないから","OSによって発行されるタイミングによってはゲームのスピードが安定しない"などの理由。
もっと詳しい人が書いてくれると嬉しいなぁ(ちらっちらっ

あと眠いまま書いたせいか、コメント中のelseの後にif抜けてるね。ごめんね。

Uriaria

Re: 読み込み中にアクセス違反が発生しました[VisualStudio2008 C++]

#13

投稿記事 by Uriaria » 11年前

Milla さんが書きました:
けっこう破壊的なプロシージャ書いてるね。
まず、exit(0);で終了はまずい。おそらく強制終了的な終わり方になっているはず。
ウィンドウプログラムの作法に則って終了するべき。
回答ありがとうございます。前までは強制終了の様な終了でしたが記述通りにしたところ正常な終了になりました
さらにさらにInitDirect3D()内のこの部分を

ここが間違えてるので、D3DDeviceの作成に失敗しています。
なので実体のないポインタでClear()しようとして、アクセス違反が起きています。
なんのためのHRESULT型の関数なのか。。。
本当です間違えていました。訂正したところRender関数を処理することができました
ですが処理を中断されなくはなりましたが未だにアクセス違反エラーが出てしまいます
まだどこかおかしな点があるのでしょうか?よろしくお願いします

※少々コードが多くなってしまいます申し訳ありません

コード:

//WinMain.cpp
#include <windows.h>
#include <d3d9.h>
#include <d3dx9.h>
#include<stdlib.h>
#include "FPSController.h"
#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }

LPDIRECT3D9 g_pD3D;
D3DPRESENT_PARAMETERS g_D3DPParams;
LPDIRECT3DDEVICE9 g_pD3DDevice = 0;
HRESULT InitDirect3D(HWND hWnd);
VOID Render(LPDIRECT3DDEVICE9 theDevice);
VOID CleanUpDirect3D(void);

FPSController* FPS;

LRESULT CALLBACK WndProc(
    HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg) {
    case WM_DESTROY:
		CleanUpDirect3D();
        PostQuitMessage(0);
		delete FPS;
        break;
	case WM_PAINT:
		break;
	case WM_LBUTTONUP:
		CleanUpDirect3D();
		delete FPS;
		PostMessage(hwnd, WM_CLOSE, NULL, NULL);
	}
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow){
	HWND windhwnd;
	MSG msg;
	WNDCLASSEX wc;
	nCmdShow = SW_SHOW;
	wc.cbSize = sizeof(WNDCLASSEX);
	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc = WndProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = hInstance;
	wc.hCursor = LoadCursor(0, IDC_ARROW);
	wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName = 0;
	wc.lpszClassName = "_title";
	wc.hIconSm = wc.hIcon;
	 
	if(!RegisterClassEx(&wc))
	{
		return 0;
	}
 
	// この後CreateWindow
	windhwnd = CreateWindow(
			"_title",		// ウィンドウクラスの名前
			"SDKで作成したウィンドウ",	// ウィンドウのキャプション
			WS_OVERLAPPEDWINDOW,		// ウィンドウスタイル
			CW_USEDEFAULT,			// ウィンドウのx座標
			CW_USEDEFAULT,			// ウィンドウのy座標
			CW_USEDEFAULT,			// ウィンドウの幅
			CW_USEDEFAULT,			// ウィンドウの高さ
			NULL,				// 親ウィンドウのハンドル
			NULL,				// メニューのハンドル
			hInstance,			// アプリケーションのインスタンスハンドル
			NULL );				// WM_CREATEメッセージのlParamへ渡す値

	if (windhwnd == NULL) return 0;

	ShowWindow(windhwnd, nCmdShow);	// ウィンドウの表示状態を設定
	UpdateWindow(windhwnd);			// ウィンドウのクライアント領域を更新
	if( FAILED( InitDirect3D( windhwnd ) ) )
		return 0;
	FPS = new FPSController();
	while (1){
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){
			TranslateMessage(&msg);
			DispatchMessage(&msg);
			// 終了メッセージがきたら終了
			if (msg.message == WM_QUIT)
			{
				break;
			}
			else if(FPS->FPSControll(60))  // FPS制御関数
				Render(g_pD3DDevice);
		}
		Sleep(0);
	}
    return msg.wParam;
}

HRESULT InitDirect3D(HWND hWnd)
{
	//Direct3Dオブジェクトの生成
	if(NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION))){return(E_FAIL);}

	//Direct3Dデバイスを生成するための構造体を設定する。Zバッファ尽付き
	ZeroMemory(&g_D3DPParams, sizeof(D3DPRESENT_PARAMETERS));

	//プレゼンテーションパラメータ

	//今表示されているモニタの設定と同じ
	g_D3DPParams.BackBufferFormat = D3DFMT_UNKNOWN;

	//ウィンドウモードにする
	g_D3DPParams.Windowed = TRUE;

	//バックバッファの数
	g_D3DPParams.BackBufferCount = 1;

	//マルチサンプリングは行わない
	g_D3DPParams.MultiSampleType = D3DMULTISAMPLE_NONE;

	//マルチサンプリングは行わないので0
	g_D3DPParams.MultiSampleQuality = 0;

	//Direct3Dにスワップエフェクトをまかせる
	g_D3DPParams.SwapEffect = D3DSWAPEFFECT_DISCARD;

	//Direct3Dに震度バッファの管理を任せる
	g_D3DPParams.EnableAutoDepthStencil = TRUE;

	//震度バッファのフォーマット(通常はこの値で問題ない)
	g_D3DPParams.AutoDepthStencilFormat= D3DFMT_D16;

	//カバーウインドウ=アプリケーションのウィンドウ
	g_D3DPParams.hDeviceWindow = hWnd;

	//フラグは使わない
	g_D3DPParams.Flags = 0;

	//今のリフレッシュレートをそのまま使う
	g_D3DPParams.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;

	//モニタの垂直回帰を待つ
	g_D3DPParams.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;

	//CreateDeviceでDirect3Dを初期化するとき、HAL、HELの組み合わせは
	//プログラマーが自由に決めることができるが
	//普通はこの組み合わせで十分

	//Direct3Dデバイスの生成。まず、HALのいいやつ

	if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,D3DCREATE_HARDWARE_VERTEXPROCESSING, &g_D3DPParams, &g_pD3DDevice)))
	{
		//コケたら普通のHAL(HEL?)
		if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING, &g_D3DPParams, &g_pD3DDevice)))
		{
			if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING, &g_D3DPParams, &g_pD3DDevice)))
			{
				//それでもコケたらおしまい
				//MessageBox(NULL, "Direct3Dを初期化できませんでした", KWINDOW_TITLE, MB_OK | MB_ICONSTOP);
				return(E_FAIL);
			}
		}
	}
	return(S_OK);
}

//----------------------------------------Render
//
//	実際の描画作業
//
//----------------------------------------
VOID Render(LPDIRECT3DDEVICE9 theDevice)
{
	//Zバッファとバックバッファのクリア
	theDevice->Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 64), 1.0f, 0);

	//シーンの開始
	if(SUCCEEDED(theDevice->BeginScene()))
	{
		//終わりの定型処理
		theDevice->EndScene();		//シーンの終了
	}

	//バックバッファ表画面に反得させる
	HRESULT hr = theDevice->Present(NULL, NULL, NULL, NULL);

}

//-----------------------------------------CleanUpDirect3D
//
//	Direct3Dの後始末
//
//-----------------------------------------
VOID CleanUpDirect3D(void)
{
	//Direct3Dデバイスなどの解放
	SAFE_RELEASE(g_pD3DDevice);
	SAFE_RELEASE(g_pD3D);
}
FPSController.cpp

コード:


#include "FPSController.h"

//===============================================
//コンストラクタ
//===============================================

FPSController::FPSController(){
	InitFlameTime = 0;
	nowTime = 0;
	FlameCount = 0;
	FlameTime = 0;
	RenderFlag = false;
	FPSInitFlag = false;
	timeBeginPeriod(1);
}

//==============================================
//デストラクタ
//==============================================
FPSController::~FPSController(){
	timeEndPeriod(1);
}


bool FPSController::FPSControll(int HowFlame){
	if(FPSInitFlag == false){
		FlameTime = 1000 / HowFlame;		//1フレーム時間代入
		InitFlameTime = timeGetTime();		//フレーム管理開始時間
		FPSInitFlag = true;
	}

	FlameCount++;
	nowTime = timeGetTime() - InitFlameTime;	//開始から経過した時間

	if(nowTime >= FlameCount * FlameTime){	//1フレーム時間経過したら描画
		if(FlameCount == HowFlame){			//フレーム更新
			FlameCount = 0;
			RenderFlag = true;
			FPSInitFlag = false;
		}
	}
	else
		Sleep(1);

	return RenderFlag;
}
FPSController.h

コード:

#include <windows.h>
#pragma comment(lib,"winmm.lib")

class FPSController{
	public:
		FPSController();
		~FPSController();
		bool	RenderFlag;
		bool	FPSControll(int HowFlame);
	private:
		DWORD	nowTime;
		DWORD	InitFlameTime;
		DWORD	FlameTime;
		int		FlameCount;
		bool	FPSInitFlag;
};

Milla

Re: 読み込み中にアクセス違反が発生しました[VisualStudio2008 C++]

#14

投稿記事 by Milla » 11年前

原因はRender関数をメインループ内で処理するようになったために
ウィンドウの×ボタンを押した後、プロシージャで削除されたLPDIRECT3DDEVICE9を用いてClearしようとしています。

申し訳ございません。メッセージループがまだおかしかったです。正しいメッセージループはこうです。

コード:

	while (1)
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
			// 終了メッセージがきたら終了
			if (msg.message == WM_QUIT)
			{
				break;
			}
		}
		else if (FPS->FPSControll(60))  // FPS制御関数
		{
			Render(g_pD3DDevice);
		}
		
		Sleep(0);
	}
http://msdn.microsoft.com/ja-jp/library/cc410948.aspx
PeekMessageはメッセージが来なければ0を返します。
よって以前のループでは、メッセージが来て、かつ、そのメッセージがWM_QUITでない時にしか、FPS制御に入りません。

またデバッグしてみたところ、FPS制御が上手く機能していない気がします。

よくあるSkeltonプログラムです。これを見て修正してみても、動かなければ、また書き込みしてください。

コード:

#include <windows.h>
#include <mmsystem.h>
#include <d3d9.h>
#include <d3dx9.h>
#include <stdlib.h>
#pragma comment(lib,"winmm.lib")
#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")

#define SAFE_DELETE(p) { if(p) { delete p; p = NULL; } }
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); p= NULL; } }

// グローバル変数
LPDIRECT3D9 g_pD3D = NULL;
LPDIRECT3DDEVICE9 g_pD3DDevice = NULL;

D3DPRESENT_PARAMETERS g_D3DPParams;

// プロトタイプ宣言
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
HRESULT InitDirect3D(HWND hWnd);
VOID Render(LPDIRECT3DDEVICE9 pDevice);
VOID CleanUpDirect3D(VOID);
BOOL FPSController(int fps);

//-----------------------------------------
//
//  エントリ ポイント
//
//-----------------------------------------
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){

	HWND hWnd;
	MSG msg;
	WNDCLASSEX wc;

	wc.cbSize = sizeof(WNDCLASSEX);
	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc = WndProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = hInstance;
	wc.hCursor = LoadCursor(0, IDC_ARROW);
	wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName = 0;
	wc.lpszClassName = "Skelton";
	wc.hIconSm = wc.hIcon;

	if (!RegisterClassEx(&wc))
	{
		return 0;
	}

	// この後CreateWindow
	hWnd = CreateWindow(
		wc.lpszClassName,       // ウィンドウクラスの名前
		"SDKで作成したウィンドウ",    // ウィンドウのキャプション
		WS_OVERLAPPEDWINDOW,        // ウィンドウスタイル
		CW_USEDEFAULT,          // ウィンドウのx座標
		CW_USEDEFAULT,          // ウィンドウのy座標
		CW_USEDEFAULT,          // ウィンドウの幅
		CW_USEDEFAULT,          // ウィンドウの高さ
		NULL,               // 親ウィンドウのハンドル
		NULL,               // メニューのハンドル
		hInstance,          // アプリケーションのインスタンスハンドル
		NULL);             // WM_CREATEメッセージのlParamへ渡す値

	if (hWnd == NULL) return 0;

	ShowWindow(hWnd, nCmdShow); // ウィンドウの表示状態を設定
	UpdateWindow(hWnd);         // ウィンドウのクライアント領域を更新

	// Direct3Dの初期化
	if (FAILED(InitDirect3D(hWnd))) return 0;

	// メッセージループ
	while (1)
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
			// 終了メッセージがきたら終了
			if (msg.message == WM_QUIT)
			{
				break;
			}
		}
		else if (FPSController(60))  // FPS制御関数
		{
			// 描画
			Render(g_pD3DDevice);
		}
		
		Sleep(0);
	}

	// Direct3Dの後始末
	CleanUpDirect3D();

	return msg.wParam;
}

//-----------------------------------------
//
//  ウィンドウ プロシージャ
//
//-----------------------------------------
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
	switch (Msg)
	{
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, Msg, wParam, lParam);
	}

	return 0;
}

//-----------------------------------------
//
//  Direct3Dの初期化
//
//-----------------------------------------
HRESULT InitDirect3D(HWND hWnd)
{
	//Direct3Dオブジェクトの生成
	if (NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION))){ return(E_FAIL); }

	//Direct3Dデバイスを生成するための構造体を設定する。Zバッファ尽付き
	ZeroMemory(&g_D3DPParams, sizeof(D3DPRESENT_PARAMETERS));

	//プレゼンテーションパラメータ

	//今表示されているモニタの設定と同じ
	g_D3DPParams.BackBufferFormat = D3DFMT_UNKNOWN;

	//ウィンドウモードにする
	g_D3DPParams.Windowed = TRUE;

	//バックバッファの数
	g_D3DPParams.BackBufferCount = 1;

	//マルチサンプリングは行わない
	g_D3DPParams.MultiSampleType = D3DMULTISAMPLE_NONE;

	//マルチサンプリングは行わないので0
	g_D3DPParams.MultiSampleQuality = 0;

	//Direct3Dにスワップエフェクトをまかせる
	g_D3DPParams.SwapEffect = D3DSWAPEFFECT_DISCARD;

	//Direct3Dに震度バッファの管理を任せる
	g_D3DPParams.EnableAutoDepthStencil = TRUE;

	//震度バッファのフォーマット(通常はこの値で問題ない)
	g_D3DPParams.AutoDepthStencilFormat = D3DFMT_D16;

	//カバーウインドウ=アプリケーションのウィンドウ
	g_D3DPParams.hDeviceWindow = hWnd;

	//フラグは使わない
	g_D3DPParams.Flags = 0;

	//今のリフレッシュレートをそのまま使う
	g_D3DPParams.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;

	//モニタの垂直回帰を待つ
	g_D3DPParams.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;

	//CreateDeviceでDirect3Dを初期化するとき、HAL、HELの組み合わせは
	//プログラマーが自由に決めることができるが
	//普通はこの組み合わせで十分

	//Direct3Dデバイスの生成。まず、HALのいいやつ

	if (FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &g_D3DPParams, &g_pD3DDevice)))
	{
		//コケたら普通のHAL(HEL?)
		if (FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &g_D3DPParams, &g_pD3DDevice)))
		{
			if (FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &g_D3DPParams, &g_pD3DDevice)))
			{
				//それでもコケたらおしまい
				//MessageBox(NULL, "Direct3Dを初期化できませんでした", KWINDOW_TITLE, MB_OK | MB_ICONSTOP);
				return(E_FAIL);
			}
		}
	}

	return S_OK;
}

//----------------------------------------
//
//  実際の描画作業
//
//----------------------------------------
VOID Render(LPDIRECT3DDEVICE9 pDevice)
{
	//Zバッファとバックバッファのクリア
	pDevice->Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 64), 1.0f, 0);

	//シーンの開始
	if (SUCCEEDED(pDevice->BeginScene()))
	{
		//終わりの定型処理
		pDevice->EndScene();      //シーンの終了
	}

	//バックバッファ表画面に反得させる
	pDevice->Present(NULL, NULL, NULL, NULL);
}

//-----------------------------------------
//
//  FPS制御関数
//
//-----------------------------------------
BOOL FPSController(int fps)
{
	// 現在の時刻を古い時刻として記録しておく。
	static DWORD nowtime, oldtime = timeGetTime();

	// 現在の時刻の更新
	nowtime = timeGetTime();

	// 現在の時刻 - 古い時刻が 1000ms / frame数 = one frameの時間 以上になったなら
	if ((nowtime - oldtime) >= (double)(1000 / fps))
	{
		// 古い時刻を現在の時刻で更新しTRUEを返す
		oldtime = nowtime;
		return TRUE;
	}

	return FALSE;
}

//-----------------------------------------
//
//  Direct3Dの後始末
//
//-----------------------------------------
VOID CleanUpDirect3D(void)
{
	//Direct3Dデバイスなどの解放
	SAFE_RELEASE(g_pD3DDevice);
	SAFE_RELEASE(g_pD3D);
}



Uriaria

Re: 読み込み中にアクセス違反が発生しました[VisualStudio2008 C++]

#15

投稿記事 by Uriaria » 11年前

Milla さんが書きました:原因はRender関数をメインループ内で処理するようになったために
ウィンドウの×ボタンを押した後、プロシージャで削除されたLPDIRECT3DDEVICE9を用いてClearしようとしています。
PeekMessageはメッセージが来なければ0を返します。
よって以前のループでは、メッセージが来て、かつ、そのメッセージがWM_QUITでない時にしか、FPS制御に入りません。
本当です、メインループ内でRender関数が処理されていないかった原因とアクセス違反が起きてしまう原因がわかりました
下記の通り修正を行ったところ正常に起動し正常に処理され正常に終了することができました。ありがとうございます
今後同じ様なバグを起こさないようにプログラム処理の流れを理解してからコードを書いていこうと思います
回答して下さった方、原因を見つけ解決して下さった方、ありがとうございました

コード:

#include <windows.h>
#include <mmsystem.h>
#include <d3d9.h>
#include <d3dx9.h>
#include<stdlib.h>
#include "FPSController.h"
#pragma comment(lib,"winmm.lib")
#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }

// グローバル変数
LPDIRECT3D9 g_pD3D = NULL;
LPDIRECT3DDEVICE9 g_pD3DDevice = NULL;

D3DPRESENT_PARAMETERS g_D3DPParams;

//プロトタイプ宣言
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
HRESULT InitDirect3D(HWND hWnd);
VOID Render(LPDIRECT3DDEVICE9 theDevice);
VOID CleanUpDirect3D(void);

FPSController* FPS;

LRESULT CALLBACK WndProc(
    HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg) {
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
	}
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow){
	HWND windhwnd;
	MSG msg;
	WNDCLASSEX wc;
	nCmdShow = SW_SHOW;
	wc.cbSize = sizeof(WNDCLASSEX);
	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc = WndProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = hInstance;
	wc.hCursor = LoadCursor(0, IDC_ARROW);
	wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName = 0;
	wc.lpszClassName = "_title";
	wc.hIconSm = wc.hIcon;
	 
	if(!RegisterClassEx(&wc))
	{
		return 0;
	}
 
	// この後CreateWindow
	windhwnd = CreateWindow(
			"_title",		// ウィンドウクラスの名前
			"SDKで作成したウィンドウ",	// ウィンドウのキャプション
			WS_OVERLAPPEDWINDOW,		// ウィンドウスタイル
			CW_USEDEFAULT,			// ウィンドウのx座標
			CW_USEDEFAULT,			// ウィンドウのy座標
			CW_USEDEFAULT,			// ウィンドウの幅
			CW_USEDEFAULT,			// ウィンドウの高さ
			NULL,				// 親ウィンドウのハンドル
			NULL,				// メニューのハンドル
			hInstance,			// アプリケーションのインスタンスハンドル
			NULL );				// WM_CREATEメッセージのlParamへ渡す値

	if (windhwnd == NULL) return 0;

	ShowWindow(windhwnd, nCmdShow);	// ウィンドウの表示状態を設定
	UpdateWindow(windhwnd);			// ウィンドウのクライアント領域を更新

	// Direct3Dの初期化
	if( FAILED( InitDirect3D( windhwnd ) ) ) return 0;

	FPS = new FPSController();

	//メッセージループ
	while (1){
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){
			TranslateMessage(&msg);
			DispatchMessage(&msg);
			// 終了メッセージがきたら終了
			if (msg.message == WM_QUIT)
				break;
		}
		else if(FPS->FPSControll(60))  // FPS制御関数
				Render(g_pD3DDevice);
		Sleep(0);
	}
	//Direct3Dの後始末
    CleanUpDirect3D();

	delete FPS;
    return msg.wParam;
}

HRESULT InitDirect3D(HWND hWnd)
{
	//Direct3Dオブジェクトの生成
	if(NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION))){return(E_FAIL);}

	//Direct3Dデバイスを生成するための構造体を設定する。Zバッファ尽付き
	ZeroMemory(&g_D3DPParams, sizeof(D3DPRESENT_PARAMETERS));

	//プレゼンテーションパラメータ

	//今表示されているモニタの設定と同じ
	g_D3DPParams.BackBufferFormat = D3DFMT_UNKNOWN;

	//ウィンドウモードにする
	g_D3DPParams.Windowed = TRUE;

	//バックバッファの数
	g_D3DPParams.BackBufferCount = 1;

	//マルチサンプリングは行わない
	g_D3DPParams.MultiSampleType = D3DMULTISAMPLE_NONE;

	//マルチサンプリングは行わないので0
	g_D3DPParams.MultiSampleQuality = 0;

	//Direct3Dにスワップエフェクトをまかせる
	g_D3DPParams.SwapEffect = D3DSWAPEFFECT_DISCARD;

	//Direct3Dに震度バッファの管理を任せる
	g_D3DPParams.EnableAutoDepthStencil = TRUE;

	//震度バッファのフォーマット(通常はこの値で問題ない)
	g_D3DPParams.AutoDepthStencilFormat= D3DFMT_D16;

	//カバーウインドウ=アプリケーションのウィンドウ
	g_D3DPParams.hDeviceWindow = hWnd;

	//フラグは使わない
	g_D3DPParams.Flags = 0;

	//今のリフレッシュレートをそのまま使う
	g_D3DPParams.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;

	//モニタの垂直回帰を待つ
	g_D3DPParams.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;

	//CreateDeviceでDirect3Dを初期化するとき、HAL、HELの組み合わせは
	//プログラマーが自由に決めることができるが
	//普通はこの組み合わせで十分

	//Direct3Dデバイスの生成。まず、HALのいいやつ

	if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,D3DCREATE_HARDWARE_VERTEXPROCESSING, &g_D3DPParams, &g_pD3DDevice)))
	{
		//コケたら普通のHAL(HEL?)
		if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING, &g_D3DPParams, &g_pD3DDevice)))
		{
			if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING, &g_D3DPParams, &g_pD3DDevice)))
			{
				//それでもコケたらおしまい
				//MessageBox(NULL, "Direct3Dを初期化できませんでした", KWINDOW_TITLE, MB_OK | MB_ICONSTOP);
				return(E_FAIL);
			}
		}
	}
	return(S_OK);
}

//----------------------------------------Render
//
//	実際の描画作業
//
//----------------------------------------
VOID Render(LPDIRECT3DDEVICE9 theDevice)
{
	//Zバッファとバックバッファのクリア
	theDevice->Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 64), 1.0f, 0);

	//シーンの開始
	if(SUCCEEDED(theDevice->BeginScene()))
	{
		//終わりの定型処理
		theDevice->EndScene();		//シーンの終了
	}

	//バックバッファ表画面に反得させる
	HRESULT hr = theDevice->Present(NULL, NULL, NULL, NULL);

}

//-----------------------------------------CleanUpDirect3D
//
//	Direct3Dの後始末
//
//-----------------------------------------
VOID CleanUpDirect3D(void)
{
	//Direct3Dデバイスなどの解放
	SAFE_RELEASE(g_pD3DDevice);
	SAFE_RELEASE(g_pD3D);
}
FPSController.cpp

コード:

#include "FPSController.h"

//===============================================
//コンストラクタ
//===============================================

FPSController::FPSController(){
	nowtime = 0;
	oldtime = 0;
	timeBeginPeriod(1);
}

//==============================================
//デストラクタ
//==============================================
FPSController::~FPSController(){
	timeEndPeriod(1);
}


bool FPSController::FPSControll(int fps){
	// 現在の時刻を古い時刻として記録しておく。
	static DWORD nowtime, oldtime = timeGetTime();

	// 現在の時刻の更新
	nowtime = timeGetTime();

	// 現在の時刻 - 古い時刻が 1000ms / frame数 = one frameの時間 以上になったなら
	if ((nowtime - oldtime) >= (double)(1000 / fps)){
		// 古い時刻を現在の時刻で更新しTRUEを返す
        oldtime = nowtime;
        return true;
	}
	else
		Sleep(1);

	return false;
}
FPSController.h

コード:

#include <windows.h>
#pragma comment(lib,"winmm.lib")

class FPSController{
	public:
		FPSController();
		~FPSController();
		bool	FPSControll(int HowFlame);
	private:
		DWORD	nowtime;
		DWORD	oldtime;
};

閉鎖

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