[自習]Delphi QuadrupleD3のD3DERR_DEVICENOTRESETで警告が出る件
- 2006/02/01
- 11:43
helloサンプルなどで次のようなエラーがでる
[警告] HelloMain.pas(91): 定数式が範囲を越えました
[警告] HelloMain.pas(91): case 式の範囲外のラベルがあります
それぞれF1を押してヘルプをみてみるとcase文のケースリスト式に範囲外の値を指定してしまったらしい。
エラーがでた箇所のコードはこれ
Case DG.D3DDevice.TestCooperativeLevel of
//OK、生きてます
D3D_OK: begin
(中略)
D3DERR_DEVICENOTRESET: begin
DG.Reset;
end;
ネットで得られる情報から対策は3つある。
・HRESULTでキャストする。
・Integerでキャストする。
・警告を消すためのキャストをしてはいけない。(現状維持)
今回はもうちょっと探ってみたい。
まず、caseが扱える範囲を疑ってみた
case文のヘルプから関係ありそうな所を探してみる
・セレクタ式「順序型の任意の式を使用できます」
・ケースリスト「セレクタ式と互換性のある順序型」
と説明がある。
case セレクタ式 of
ケースリスト1: 文1;
...
ケースリストn: 文n;
end
TestCooperativeLevelはHRESULT型の値を返す。つまり、ケースリストにはHRESULT型と互換性のある値しか使えない。ケースリストにD3DERR_DEVICENOTRESETを使ってエラーがでているのでこの点を調べる必要がある。
DelphiとC言語の違いを疑ってみる。
case文を調べている最中にコンバート時に言語間の差を無視した変換をしているのではないかと思いついたので調べてみる。HRESULTを調べてみるとtype HResult = Longint;と定義されている。VCのほうではlong intで定義されているので扱える範囲は同じ。ここは大丈夫だった。
どうもD3DERR_DEVICENOTRESETそのものに問題がありそうなので、どう定義されてるのが調べてみることにした。「D3DERR_DEVICENOTRESETにマウスカーソルをあわせて右クリック→定義の検索」。
D3DERR_DEVICENOTRESET = $88760869;
HRESULT(Longint)が扱える範囲は-2147483648..2147483647
$88760869を16進数から10進数に直すと2289436777
キタ━━━━━━(゚∀゚)━━━━━━ !!
落ち着いて考えてみる。
DirectXのヘッダを追いかけてみると、もともとD3DERR_DEVICENOTRESETは定数ではなく計算で出される値のようだ。long int型なのだからこの値($88760869)は本来は負数。定数にしてしまったためにDelphiは正数だと解釈してしまった・・・んだと思う。だからIntegerやHRESULTにキャストすると警告が消える。
ちなみにIntegerはLongintと同じです。その違いは、Integerはその時代に即した型が割り当てられるため将来のコンパイラによって変わる可能性があり、Longintは変わる可能性がない。ただ、実際はもう変わらないだろうとも2ちゃんねるで誰かが言ってた気がします。
D3DERR_DEVICENOTRESETをHRESULT型にする方法を考える
DirectXのヘッダといえばClootieが有名なので見てみた。
D3DERR_DEVICENOTRESET = HResult(MAKE_D3DHRESULT_R or 2153);
定義時にキャストしているので真似してみる。
D3DERR_DEVICENOTRESET =HRESULT($88760869);
コンパイル時にHRESULTToStringが「定数式が範囲を越えました」「case 式の範囲外のラベルがあります」と警告を出した。
このHRESULTToString関数はD3DERR~を文字列に直してくれる便利や関数です。HRESULT値をDWORDにキャストしていたのが原因。なるほど、セレクタ式のほうをキャストしてしまえばケースリストをキャストするより楽だ。
D3DERR~定数がHRESULTの範囲を超えているためにキャストしているんだと思う。今回はD3DERR_DEVICENOTRESETをきっかけに調べ始めた。だからD3DERR_DEVICENOTRESETはもうHRESULTにキャストしている。ほかにもD3DERR~定数はたくさんある。全てを書き換えた。これでもうD3DERR~定数を扱うときにキャストの必要はなくなった。
(d3d9.pas:3142行より)
D3DERR_WRONGTEXTUREFORMAT = HRESULT($88760818);
D3DERR_UNSUPPORTEDCOLOROPERATION = HRESULT($88760819);
D3DERR_UNSUPPORTEDCOLORARG = HRESULT($8876081A);
D3DERR_UNSUPPORTEDALPHAOPERATION = HRESULT($8876081B);
D3DERR_UNSUPPORTEDALPHAARG = HRESULT($8876081C);
D3DERR_TOOMANYOPERATIONS = HRESULT($8876081D);
D3DERR_CONFLICTINGTEXTUREFILTER = HRESULT($8876081E);
D3DERR_UNSUPPORTEDFACTORVALUE = HRESULT($8876081F);
D3DERR_CONFLICTINGRENDERSTATE = HRESULT($88760821);
D3DERR_UNSUPPORTEDTEXTUREFILTER = HRESULT($88760822);
D3DERR_CONFLICTINGTEXTUREPALETTE = HRESULT($88760826);
D3DERR_DRIVERINTERNALERROR = HRESULT($88760827);
D3DERR_NOTFOUND = HRESULT($88760866);
D3DERR_MOREDATA = HRESULT($88760867);
D3DERR_DEVICELOST = HRESULT($88760868);
D3DERR_DEVICENOTRESET =HRESULT($88760869);
D3DERR_NOTAVAILABLE = HRESULT($8876086A);
D3DERR_OUTOFVIDEOMEMORY = HRESULT($8876017C);
D3DERR_INVALIDDEVICE = HRESULT($8876086B);
D3DERR_INVALIDCALL = HRESULT($8876086C);
D3DERR_DRIVERINVALIDCALL = HRESULT($8876086D);
D3DERR_WASSTILLDRAWING = HRESULT($8876021C);
D3DOK_NOAUTOGEN = HRESULT($0876086F);
キーマクロを使った。
DelphiのIDEはCTRL+SHIFT+Rを押すと記録をはじめる。その後、繰り返したい操作をして再びCTRL+SHIFT+Rを押すと記録終了。以後はCTRL+SHIFT+Pを押すと記録した操作を何度でも再生できる。大量に手動で書き換える必要がでたときには非常に便利だ。
これで警告はでなくなった。おわり。