Visual C++で、DoDragDropを使いファイル(仮想ファイル)をエクスプローラーにドラッグアンドドロップするという処理の実装を行っていたのだが、そこでよくわからないエラーが発生したのでその対処方法を紹介する。多少違う場合にも参考になるかもしれない。
エラー
自分のウインドウからDoDragDropを使ってエクスプローラーにドロップする時は問題なくできたのだが、自分が作成したIShellBrowserにドロップする際にしかもIStreamを使った場合に問題がエラーが発生した(HGLOBAL(TYMED_HGLOBAL)を使った場合には問題ない)。エラーは次のようなもの。
******.exe の 0x76dadfb8 でハンドルされていない例外が発生しました: 0xC0000005: 場所 0xcccccccc を読み込み中にアクセス違反が発生しました。
というもの。呼び出し履歴をみても、shell32.dll!76ef60ae()というところで落ちているらしいことしかわからなかった。
対処方法
問題は意外なところというか、あまりCOMプログラミングはやらないため慣習的なことを知らなかったことによる。IUnknownインタフェースのQueryInterfaceの部分でこのような感じで実装してたのだが、
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
STDMETHOD( QueryInterface ) ( REFIID iid, void ** ppvObject ) { if( iid == __uuidof( IUnknown ) || iid == __uuidof( IStream ) || iid == __uuidof( ISequentialStream ) ) { *ppvObject = this; AddRef(); return S_OK; } else { return E_NOINTERFACE; } } |
どうやらE_NOINTERFACEの場合には、*ppvObject = NULL;をしなければならないということであった。MSDNのページのIUnknown の動作を参照しても
コンポーネントは NULL へのポインタを設定し、E_NOINTERFACE を返す。
と書いてある。ちなみに、なぜエクスプローラーにドロップした時はエラーが発生しないかというと、QueryInterfaceでE_NOINTERFACE部分が呼ばれることがなかったからであった。
ちなみに、IShellBrowserにドロップした時には、FE0B6665-E0CA-49B9-A178-2B5CB48D92A5やAF51335E-692C-4FBF-A963-8E162C3EED36というインタフェースの要求をしているようであった(IStreamAsyncなんでしょうか、、、)。