D3D11CreateDeviceが呼べるようになるまで

新しい環境でそろそろDirectX 11と遊んでみようとしたらいきなりincludeのレベルではまってしまった…orz
DX9の時はそんなに苦労しなかったのに、手厳しい。とりあえずD3D11CreateDevice()呼び出しまでしか確認してないけど、そこにたどり着くまでの作業内容をメモメモ…

環境は

SDKは2009年度版もヘッダファイルがほぼ同じっぽいので、だいたい通用すると思われ。



まずinclude側はこんな感じで

#define UINT8 unsigned char
#define __in
#define __out
#define __inout
#define __in_opt
#define __out_opt
#define __inout_opt
#define __out_bcount(x)
#define __in_bcount_opt(x)
#define __out_bcount_opt(x)
#define __in_range(x, y)
#define __in_ecount(x)
#define __out_ecount(x)
#define __in_ecount_opt(x)
#define __out_ecount_opt(x)
#pragma warn -8027
#include 			// D3D11CreateDevice
#pragma warn +8027

UINT8はどこかに書いてあると思うけど、探すのも面倒だし自分で定義。一応D3D11.h内部でもwindows.hをincludeしてるっぽいんだけどなぁ…
他のinとoutはCOMインターフェイス用みたいなので、とりあえず無効化だけしておいた。



あと、ヘッダファイル側にも修正を入れた。てか、なんで元のヘッダファイルでVCとかはコンパイルが通るんだろ…エラーメッセージ的にヘッダファイル側が悪いっぽいのに。

  • D3D11.h

エラーメッセージはこんなのが出る

エラー E2500 D:\soft\Microsoft DirectX SDK (February 2010)\Include\D3D11.h 941:__declspec(selectany) is only for initialized and externally visible variables"

この辺http://msdn.microsoft.com/en-us/library/5tkz6s71.aspxの説明をみると「Incorrect - __declspec(selectany) is applied to the uninitialized」って書いてあるパターンに当てはまるのでは?と思ってしまう。selectany指定の変数は初期化が必要なんじゃないだろうか。
該当行をみると初期化が入ってない。とりあえず「DECLSPEC_SELECTANY」自体をコメントアウトして回避してみた。たぶんこの指定は外部定義のグローバル変数に初期値を指定するって機能なんじゃないかと思う。初期値が特にない(今回は0にしたいっぽい)なら指定そのものを削除で大丈夫だと思う。

extern const /*DECLSPEC_SELECTANY*/ CD3D11_DEFAULT D3D11_DEFAULT;
  • d3d11sdklayers.h

エラーメッセージはこんなのが出る

エラー E2132 D:\soft\Microsoft DirectX SDK (February 2010)\Include\d3d11sdklayers.h 99: テンプレートおよびオーバーロードした演算子が C リンケージを持てない
エラー E2132 D:\soft\Microsoft DirectX SDK (February 2010)\Include\d3d11sdklayers.h 101: テンプレートおよびオーバーロードした演算子が C リンケージを持てない
エラー E2132 D:\soft\Microsoft DirectX SDK (February 2010)\Include\d3d11sdklayers.h 103: テンプレートおよびオーバーロードした演算子が C リンケージを持てない
エラー E2132 D:\soft\Microsoft DirectX SDK (February 2010)\Include\d3d11sdklayers.h 105: テンプレートおよびオーバーロードした演算子が C リンケージを持てない
エラー E2132 D:\soft\Microsoft DirectX SDK (February 2010)\Include\d3d11sdklayers.h 107: テンプレートおよびオーバーロードした演算子が C リンケージを持てない
エラー E2132 D:\soft\Microsoft DirectX SDK (February 2010)\Include\d3d11sdklayers.h 109: テンプレートおよびオーバーロードした演算子が C リンケージを持てない
エラー E2132 D:\soft\Microsoft DirectX SDK (February 2010)\Include\d3d11sdklayers.h 111: テンプレートおよびオーバーロードした演算子が C リンケージを持てない

うん。確かに演算子オーバーロードはC形式でリンクできないよねーって思うんだけど、てか、こいつは何を言っているんだって感じ。
ヘッダファイルを見ても、ちゃんとこの周辺だけextern "C"が外れる感じになってる。もしextern "C"の範囲内に書いてあれば、間違いなくextern "C"が原因なんだけど。
いやな予感がしてcpp32でプリプロセス結果を見ようとしたら、行数が大変なことになって一瞬で挫折…orz仕方がないので、適当にextern "C"の閉じ括弧「}」をエラー部位の手前に書いてみたら、見事エラーは消滅して代わりにD3D11.hの1万行あたりでエラーになった。
どうやらD3D11.hの内部で巨大なextern "C"ブロック(?)があって、その中からd3d11sdklayers.hをincludeしてるっぽい。ぉぃぉぃ。ちょっとコーディング作法的にアレじゃない?1ヘッダ内部で閉じようよ。ゃれゃれ…
対策としては、L:98〜111に書いてあるD3D11_RLDO_FLAGSの演算子オーバーロード部分を「}」と「extern "C"{」でくくってextern "C"の呪縛から解放して対応。

}	// extern "C"	// ここ追加
inline D3D11_RLDO_FLAGS operator~( D3D11_RLDO_FLAGS a )
{ return D3D11_RLDO_FLAGS( ~UINT( a ) ); }
inline D3D11_RLDO_FLAGS operator&( D3D11_RLDO_FLAGS a, D3D11_RLDO_FLAGS b )
{ return D3D11_RLDO_FLAGS( UINT( a ) & UINT( b ) ); }
inline D3D11_RLDO_FLAGS operator|( D3D11_RLDO_FLAGS a, D3D11_RLDO_FLAGS b )
{ return D3D11_RLDO_FLAGS( UINT( a ) | UINT( b ) ); }
inline D3D11_RLDO_FLAGS operator^( D3D11_RLDO_FLAGS a, D3D11_RLDO_FLAGS b )
{ return D3D11_RLDO_FLAGS( UINT( a ) ^ UINT( b ) ); }
inline D3D11_RLDO_FLAGS& operator&=( D3D11_RLDO_FLAGS& a, D3D11_RLDO_FLAGS b )
{ a = a & b; return a; }
inline D3D11_RLDO_FLAGS& operator|=( D3D11_RLDO_FLAGS& a, D3D11_RLDO_FLAGS b )
{ a = a | b; return a; }
inline D3D11_RLDO_FLAGS& operator^=( D3D11_RLDO_FLAGS& a, D3D11_RLDO_FLAGS b )
{ a = a ^ b; return a; }
extern "C"{	// ここ追加

しかし、よくよく考えてみたらこのヘッダファイルって全体がextern "C"されてるってことだな。
もしかしたら、後々何かのリンクでC++とC形式で形式があわずにリンクエラーを起こすかもしれないな。後で理不尽なリンクエラーを見つけたら、このヘッダに入ってないか再チェックだな…



最後に備忘録として他の手順もメモ。

coff2omf d2d1.lib borland\d2d1.lib
以下同様...
set dx="D:\soft\Microsoft DirectX SDK (February 2010)"
bcc32 -I%dx%\Include -L%dx%\Lib\x86\borland test.cpp D3D11.lib

みたいに。必要なヘッダファイルと.libファイル名は、DirectXのヘルプファイルから各関数のヘルプをみると一番下に載っている。