VisualStudio2019でDirectXSDK(June 2010)のBuild

旧来のDirectX9でのアプリケーション開発を学習のためにやる機会がそれなりにあるので、そこに向けたビルドを通すまでを解説します。

# 1.環境の準備
これから解説する内容は、以下を用いています。

- VisualStudio2019Community
- DirectX9 SDK

それぞれの設定方法を解説します。

## 1.1 VisualStudio2019

### 1.1.1 ダウンロード
- https://visualstudio.microsoft.com/ja/vs/
- MicrosoftのID等は適宜、登録してください

### 1.1.2 必要なモジュールのインストール
- 既にインストール済みの場合は、以下からインストーラーを起動してください
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72979/c3d6fb12-6ded-1147-f07c-c0466e31fd50.png)
- 以下の二つが必要です、選んで右下の変更ボタンを押してください
 - C++によるデスクトップ開発
 - C++によるゲーム開発
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72979/5179d77c-25c3-0a91-09e9-da3f652f7584.png)

## 1.2 DirectX9 SDK
DirectXのバージョンは複数、在るので、適宜、必要なものを確認してください。今回はDirectX9のSDKを用いています。

### 1.2.1 ダウンロード
 - https://www.microsoft.com/en-us/download/details.aspx?id=6812
 - DirectXのバージョンは複数、在るので、適宜、必要なものを確認してください。

### 1.2.2 インストール

- インストーラを起動すると以下が出ます、適宜、読みながら進めて下さい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72979/1e1cf344-22b2-2575-08aa-9b760c02671c.png)

- インストールパスはこの画面で変更できます。デフォルトのままでも好いですが、Cドライブを節約したい場合などに変更してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72979/69fba6a8-dbe6-df49-a6ce-c64d0b502d10.png)

- 最後にエラーになる場合があります。その場合でも一応、開発には問題ありませんが、以下の点に注意してください。
 - アンインストール一覧に出ません。
 - 再度、別の場所へのインストールしたくても、インストーラーで上記の画面が出ないためにインストール先の変更が出来ません。
 - エラーが出る場合はいかに対処方法がありますので、お試しください。
 - http://nanoappli.com/blog/archives/4739

### 1.2.3 環境変数の確認
インストール後に検索から「環境変数」と入れると、以下が出ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72979/ded0eb3c-45a3-5077-1fb0-79881a7c150d.png)
「環境変数の編集」を選んで、`DXSDK_DIR`が在るか、確認してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72979/daf4248f-8f46-d4cd-2dd0-0190abc878fa.png)
この値を後で使います。


# 2. 新規プロジェクト・ソリューションの作成
ここからは実際にVisualStudioで操作する手順になります。

## 2.1 新規プロジェクトを作成する

### 2.1.1 VisualStudioの起動

直後はこの画面が出ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72979/8d04d649-c486-4f45-e892-b203f11617da.png)
`新しいプロジェクトの作成`を選んでください。

### 2.1.2 空のプロジェクトの作成
選択画面で、`空のプロジェクト`を選んでください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72979/e4ed3274-67b7-23f5-190a-a44d56d1a3cf.png)

次に、作成する名前とパスの指定が出てきます。指定フォルダのその中に、プロジェクトの名前のフォルダが生成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72979/66cad9da-e052-6198-3743-683b434b0b6a.png)
適宜、作りたい場所に設定してください。

## 2.2 プロジェクトの設定
そのままでは求める形のBuildは出来ないので、設定していきます。メニューの[`プロジェクト`]>[`プロパティ`]を選んでください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72979/7d844f37-cabe-6221-f1fc-6db1143fc73a.png)

### 2.2.1 VC++ディレクトリの設定
設定が必要な部分を、順を追って説明します。
先ず、左のペインから`VC++ディレクトリ`を選びます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72979/cf4f0a77-4151-a2a3-4f16-250e29ed00c7.png)

#### 2.2.1.1 インクルードディレクトリの設定
コンパイル時に使用するヘッダファイルの在りかを指定します。デフォルトで指定されている場所にはSDKのパスが含まれていないため、追加します。

`インクルードディレクトリ`を選び、右の🔽から`編集`を選びます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72979/ec3ffe82-d76c-8041-7d9a-54ee22bdc80e.png)

選ぶと`インクルードディレクトリ`編集画面が出るので、先頭に`$(DXSDK_DIR)include\`を追加し、[OK]ボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72979/218b9ef9-1a86-c0af-729a-401674229d5a.png)
ここで指定しているパスが、前に設定を確認した環境変数です。
この例では、
`C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\include\`
が追加されます。そのまま絶対パスを指定することも可能ですが、DXSDKのインストール場所を追跡できるので、例えば違うPCでSDKのインストール場所が動いていても、環境変数を参照するようにしていると、それに合わせて動作可能なので便利です。

#### 2.2.1.2 ライブラリディレクトリの設定
リンク時に使用するオブジェクトファイルを含むライブラリファイルの在りかを指定します。デフォルトで指定されている場所にはSDKのパスが含まれていないため、追加します。

`ライブラリディレクトリ`を選び、右の🔽から`編集`を選びます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72979/aee1ad6b-f486-b3cb-6a26-1031f9d9821b.png)

選ぶと`インクルードディレクトリ`編集画面が出るので、先頭に`$(DXSDK_DIR)lib\x86`を追加し、[OK]ボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72979/338ceb95-ea6b-c710-4438-483b1b23b2b3.png)
これもインクルードディレクトリと同様、
`C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\lib\x86`
が追加されます。そのまま絶対パスを指定することも可能ですが、DXSDKのインストール場所を追跡できるので、例えば違うPCでSDKのインストール場所が動いていても、環境変数を参照するようにしていると、それに合わせて動作可能なので便利です。

## 2.3 サブシステムの設定
今回のビルとするターゲットに合わせたサブシステムの設定をします。
左で`リンカー`>`システム`から`サブシステム`を選び、`Windows (/SUBSYSTEM:WINDOWS)`を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72979/af565ebc-8eff-914b-86b4-c6d01f197d8e.png)

ここまでの設定は作る内容に依存しないので、テンプレート化することも好いと思います。 

# 3.ソースの用意
今回は実験用として、DirectXの初期化と少し変化が出るプログラムを用意します。

## 3.1 基本的なソースコードの用意
プロジェクトにソースファイルを用意します。
右にある`ソリューションエクスプローラー`で`[ソースファイル]`を右クリックし、`追加`>`新しい項目`を選びます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72979/083f9614-ae1b-c421-10c9-958ff1007900.png)

`新しい項目の追加`ウィンドウが現れるので、適宜、名前を考えてC++ファイルを作ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72979/a58d9486-1e49-6890-68c7-c33a83f3c998.png)

この例では、プロジェクトの在るフォルダに`Source.cpp`というファイルを作成しています。

内容を記述します。

```cpp:Source.cpp
#include<windows.h>
#include<d3dx9.h>


LPDIRECT3D9 pD3d;
LPDIRECT3DDEVICE9 pDevice;

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HRESULT InitD3d(HWND);
VOID Draw();

// アプリケーションのエントリー関数
int APIENTRY WinMain(_In_ HINSTANCE hInst, _In_opt_ HINSTANCE hPrevInstance, _In_	LPSTR lpCmdLine, _In_ int nCmdShow)
{
	HWND hWnd = NULL;
	MSG msg;
	//ウィンドウの初期化
	const WCHAR szAppName[] = L"BASE";
	WNDCLASSEX wndclass;

	wndclass.cbSize = sizeof(wndclass);
	wndclass.style = CS_HREDRAW | CS_VREDRAW;
	wndclass.lpfnWndProc = WndProc;
	wndclass.cbClsExtra = 0;
	wndclass.cbWndExtra = 0;
	wndclass.hInstance = hInst;
	wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
	wndclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
	wndclass.lpszMenuName = NULL;
	wndclass.lpszClassName = szAppName;
	wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

	RegisterClassEx(&wndclass);

	hWnd = CreateWindow(szAppName, szAppName, WS_OVERLAPPEDWINDOW,
		0, 0, 640, 480, NULL, NULL, hInst, NULL);
	ShowWindow(hWnd, SW_SHOW);
	UpdateWindow(hWnd);
	//Direct3D初期化
	if (FAILED(InitD3d(hWnd)))
	{
		return(0);
	}
	//メッセージループ
	ZeroMemory(&msg, sizeof(msg));
	while (msg.message != WM_QUIT)
	{
		if (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{
			Draw();
		}
	}
	return(INT)msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
	switch (iMsg)
	{
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	case WM_KEYDOWN:
		switch ((CHAR)wParam)
		{
		case VK_ESCAPE:
			PostQuitMessage(0);
			break;
		}
		break;
	}
	return DefWindowProc(hWnd, iMsg, wParam, lParam);
}

HRESULT InitD3d(HWND hWnd)
{
	// Direct3D作成
	if (NULL == (pD3d = Direct3DCreate9(D3D_SDK_VERSION)))
	{
		MessageBox(0, L"Direct3Dの作成に失敗しました", L"", MB_OK);
		return E_FAIL;
	}
	// Direct3D Device作成
	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(0, L"HALモードDIRECT3Dデバイス失敗\nREFモード再試行 ", NULL, MB_OK);
		if (FAILED(pD3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, hWnd,
			D3DCREATE_MIXED_VERTEXPROCESSING,
			&d3dpp, &pDevice)))
		{
			MessageBox(0, L"DIRECT3Dデバイス作成に失敗", NULL, MB_OK);
			return E_FAIL;
		}
	}
	return S_OK;
}

//　Draw
VOID Draw()
{
	static UCHAR c = 0;
	c = (c++) % UCHAR_MAX;
	pDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(c, c, c), 1.0f, 0);
	if (SUCCEEDED(pDevice->BeginScene()))
	{
		//ここに描画処理
		pDevice->EndScene();
	}
	pDevice->Present(NULL, NULL, NULL, NULL);
}


```
サンプルになるコードは色々、探しても面白いと思います。
この時点で一度、コンパイルしてみることを勧めます。エラーになる部分がある場合、これまでのどこかで設定が足りないか、ソースコードが間違っているか、どちらかです。エラーが出たら適宜、そのメッセージをネットで検索してみることを勧めます。

## 3.2 リンカーの入力ファイルの追加
利用しているDirectXの機能に従い、リンクに用いる入力で追加の依存ファイルを定義します。
`プロジェクト`>`プロパティ`を開き、更に`リンカー`>`入力`>`追加の依存ファイル`で🔽の編集を呼び出します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72979/7afe3bdc-ef93-e68f-bd8d-a59ab25039e6.png)

今回は`d3d9.lib`と`d3dx9d.lib`を追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72979/a66f5602-555f-bc56-3c19-c70d78474b04.png)

設定後、入ってるのを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72979/738b7d5e-1c5e-10ea-b62b-f0376e26d801.png)

# 4.ビルドと実行
エラーが無いことを確認したらいよいよ、実行してみます。
ソフトウエアのビルドと実行は、内部処理は以下を順番に実行しています。
1. ～.cppを～.hを読み込ませてコンパイル⇒オブジェクトファイル（～.obj)が出来上がる。
2. オブジェクトファイル群とライブラリから必要なものを合わせてリンク⇒一つの実行ファイル(～.exe)が出来上がる
3. 実行する

VisualStudioでは途中までやってた場合、その部分を飛ばして実行までやります。今回は、[F5]キーでデバッグ実行してみました。

[![Image from Gyazo](https://i.gyazo.com/6bd9ff3dece5512cff1ea2989bac4e5f.gif)](https://gyazo.com/6bd9ff3dece5512cff1ea2989bac4e5f)

ここでエラーが出る場合、何等かの間違いが在りますので、確認してみてください。
コンパイルだけは通るという場合は、追加のライブラリ不足が殆どだと思われます。

---
#　参考
- [VisualStudioでDirectXの開発環境を構築する方法](https://qiita.com/nisoka/items/f501a6cc7bc3636611c4)
- [未解決の外部シンボル\_mainが 関数"int\_cdecl invoke\_main\(void\)"\(? invoke\_main@@YAHXZ\)で参照されました](http://strimuer213p.hatenablog.com/entry/2017/02/17/143321)
- http://www.northbrain.org/book/DirectXSDK.html