前触れも何もなくいきなり更新しちゃいました。
とあるプログラムを作っているときに見つけた微妙な動作不良
ちょっとCOMの扱い・・・というか互換処理に不具合があったようで、この処理のためにプログラムが間違って落ちてしまう、と言うことがあるようです。
普通、COMは受け取る側はインターフェイスを直接ポインタとして扱っている、と仮定しています。
実装側はCOMはIUnknownからの継承を行っているインターフェイスクラスを継承した、と仮定したC++のクラスで記述されています。
で、どうもこの部分の受け渡しに問題があったようで・・・。
例としては、DirectDraw7の処理を上書きしているルーチンで、
HRESULT WINAPI GetDirectDraw7Wrapper(void **ppv) { CDirectDraw7Wrapper *lpDirectDrawWrapper = new CDirectDraw7Wrapper(lpDirectDraw7); *ppv = lpDirectDrawWrapper ; return S_OK; }
とかと書いたりしていたのですが、これが間違いだったらしく、
HRESULT WINAPI GetDirectDraw7Wrapper(void **ppv) { CDirectDraw7Wrapper *lpDirectDrawWrapper = new CDirectDraw7Wrapper(lpDirectDraw7); *ppv = static_cast<IDirectDraw7 *>(lpDirectDrawWrapper); return S_OK; }
と、最低でもstatic_castを経由して変換したポインタを返さないと正しい上書き状態にならないらしく、一部の処理を発行したときにエラーとなるらしいです。
インターフェイスクラスをvoid **として受け取りを行おうとしたときに起こりうる問題というわけで。
普通のプログラムならvoid *ではなく対象のインターフェイス(この場合はIDirectDraw7 *)を指定するはずなのでこんな問題に巻き込まれることはまずないと思います。
また、ちょっとした別の見逃しとしては、QueryInterfaceのWrapper処理で「インターフェイスが継承しているすべての処理に対して自身を返さなければならない」ということが抜けていて、
継承元を指定されたときにWrapperからではなく本体を間違って返していたので・・・。
この辺を修正してDirectDrawやDirectShowでWindowModePatchを使っているときの問題を修正したバージョンです。
一部のゲームではこれで直るものがあるかもしれません。
ちなみに、WindowModePatchを更新するのは一年以上間隔があいてしまって
古いゲームなどで調べればいいのですが、なんかやる気が・・・。