DirectShow Filterのinterface定義でエラーが発生する原因を解析

このQ&Aのポイント
  • DirectShow Filterのinterface定義で呼び出し規約のエラーが発生する
  • DirectShowのGraphEdit上で動作する自作Filterを作成したが、C++プログラム上で独自定義のメソッドを呼び出すとエラーが発生
  • DEFINE_GUIDやMIDL_INTERFACEを使用してクラスとインターフェースを定義し、__stdcallを指定しているが、呼び出し元と先で呼び出し規約が異なるというエラーが出てしまう
回答を見る
  • ベストアンサー

自作DirectShow Filterのinterface定義

DirectShow Filterを自作しGraphEdit上で動作することを確認しました。 しかしC++プログラム上から独自定義のメソッドを呼び出すと 呼び出し元と先で呼び出し規約が異なるというエラーが出てしまいます。 定義は DEFINE_GUID(CLSID_MyClass, <<適当なGUID1>>); DEFINE_GUID(IID_IMyClass, <<適当なGUID2>>); MIDL_INTERFACE("<<適当なGUID2>>") IMyClass : public IUnknown {  STDMETHOD(myMethod)(void) PURE; }; class CMyClass : public CTransInPlaceFilter {  CMyClass ::CMyClass (IUnknown * pOuter, HRESULT * phr, BOOL ModifiesData);  CMyClass ::~CMyClass (); public:  static CUnknown *WINAPI CMyClass::CreateInstance(LPUNKNOWN punk, HRESULT *phr);  DECLARE_IUNKNOWN;  STDMETHODIMP CMyClass::myMethod(void){return S_OK;}; } 呼び出し元では DEFINE_GUID(CLSID_MyClass, <<適当なGUID1>>); DEFINE_GUID(IID_IMyClass, <<適当なGUID2>>); MIDL_INTERFACE("<<適当なGUID2>>") IMyClass : public IUnknown {  STDMETHOD(myMethod)(void) PURE; }; int main() {  CoInitialize(NULL);  IMyClass pMyClass;  CoCreateInstance(   CLSID_MyClass,   NULL,   CLSCTX_INPROC,   IID_IMyClass,   (LPVOID *)&pMyClass  );  pMyClass->myMethod();←ここでエラー  ・  ・  (略)  ・  ・ } エラーメッセージは Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention. です。 どちらも__stdcallになってるはずなんですが… 原因が分かる方おられましたらよろしくお願いいたします。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.3

 こんばんは。補足頂きました。  原因は「ダウンキャストが不完全であった」と言う事の様です。  多重継承になっている為、IMyClass*ではなく、最下層のCMyClass*へダウンキャストしてから、IMyClass*へアップキャストします(クロスキャスト)。  当方のVC2005では、以下で動作しました。参考程度に。 //以下を修正 HRESULT CMyClass::NonDelegatingQueryInterface(REFIID riid, void **ppv) { CheckPointer(ppv,E_POINTER); if ( riid == IID_IMyClass ) { //クロスキャスト IMyClass* pLeft = static_cast<CMyClass*>(this); return GetInterface(pLeft, ppv); } else { return CTransInPlaceFilter::NonDelegatingQueryInterface(riid, ppv); } } //以下で実行 int main() { ::CoInitialize(NULL); IMyClass* pMyClass; ::CoCreateInstance(CLSID_MyClass, NULL, CLSCTX_INPROC, IID_IMyClass, (LPVOID*)&pMyClass); pMyClass->myMethod(); pMyClass->Release(); ::CoUninitialize(); return 0; }

nisecuroro
質問者

お礼

提示して頂いたコードに書き直すことで 動作するようになりました。本当にありがとうございます。 今までCしか触ってなかったので C++特有のキャストの事などよく知りませんでした。 クロスキャストについて少し調べたのですが納得できていないことがあるので もう一点質問させてください。 thisポインタはこの場合CMyClass *const型ですよね? すると「CMyClass *const」→「CMyClass *」→「IMyClass *」 とキャストしているように見えるのですが それって「CMyClass *const」→「IMyClass *」と直接アップキャストしても問題ないような気がします。 実際 return GetInterface(static_cast<IMyClass*>(this), ppv); や return GetInterface(dynamic_cast<IMyClass*>(this), ppv); や return GetInterface((IMyClass*)this, ppv); と書いてもエラーは起きなくなります。 すると問題になっていたのはreinterpret_castか?と考えます。 各C++独自キャストの説明を見ると static_castとdynamic_castはチェック機構を除けば 行っていることは(IMyClass*)thisのCスタイルのキャストと同じに見えます。 このキャストは暗黙的にビットパターンが変更されているようです。 これに対しreinterpret_castは http://msdn.microsoft.com/ja-jp/library/cc440192(VS.71).aspx (保証はないが)ビットパターンを変更せずに再解釈する、とあります。 つまり無理やりな代入を行っただけで正しくキャストできておらず今回のエラーに繋がった、ということではないでしょうか?

その他の回答 (3)

回答No.4

 こんにちは。御礼頂きました。  もう一度試しましたが、確かにreinterpret_cast<>の時におかしくなっています。  よくよく考えれば、thisはCMyClass*constでした。  「当方がクロスキャストしていないと勘違いして元凶であるreinterpret_cast<>を止めた」から動作したと言う事なので、クロスキャスト自体は関係ありませんでした。  当方はクラスのキャストにreinterpret_cast<>を使った事が無いので、此の事例は初めて見ました。    肝心な「クラスのキャストにreinterpret_cast<>を使用すると何故おかしくなるのか」に関して、当方はC++の規格には詳しくない為、これ以上明言する訳にはいかないので、大変申し訳ありませんが、此処でギブアップと言う事になります。

nisecuroro
質問者

補足

各キャストが返す値を観察してみましたがどのキャストも同じ値を返してますね。 結局原因はよく分かりませんが当初の問題は解決しているので これで締めきらせていただきます。 回答していただいた皆様、ありがとうざいました。

回答No.2

 こんにちは。  上手く行かないかもしれませんが、NonDelegatingQueryInterface()をオーバーライドしても駄目でしょうか。 IMyClass : public IUnknown { STDMETHOD(myMethod)(void) PURE; }; class AM_NOVTABLE CMyClass : public CTransInPlaceFilter, public IMyClass { CMyClass ::CMyClass (IUnknown * pOuter, HRESULT * phr, BOOL ModifiesData); CMyClass ::~CMyClass (); public: static CUnknown *WINAPI CMyClass::CreateInstance(LPUNKNOWN punk, HRESULT *phr); DECLARE_IUNKNOWN; STDMETHODIMP CMyClass::myMethod(void){return S_OK;} //from CBaseFilter [amfilter.h/cpp] STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv) { //独自のインターフェースなら if(riid == IID_IMyClass) { return GetInterface((IMyClass *)this, ppv); } //其れ以外なら return CBaseFilter::NonDelegatingQueryInterface(riid, ppv); } }

nisecuroro
質問者

補足

説明のためにコードを簡略化したので色々抜けてますね; 実際はNonDelegating~も実装してますが開発中のコードは載せられないので 検証用にCTransInPlaceFilterを派生させてmyMethod()だけ追加したコードを 作りました。 (名前はMyFilterの方が良かったな…) http://www.rupan.net/uploader/download/1251359357.zip pass:1234(ウィルスバスターでスキャンしてますが自己責任でお願いします) 今度はデバッグすると pMyClass->myMethod(); を抜けるとデストラクタに入り例外が発生してしまいます。 メモリアクセス違反が起こってるようですが 何が起こっているのか余計に分からなくなってきました…。

  • chie65535
  • ベストアンサー率43% (8524/19375)
回答No.1

当てずっぽで不確かな回答で申し訳ありません。 #暫くC++から離れていたので忘れかけてます >pMyClass->myMethod();←ここでエラー ドット演算子とアロー演算子の使い分けを再確認してみて下さい。

nisecuroro
質問者

補足

宣言部の写しミスです、申し訳ありません;; 誤)IMyClass pMyClass; 正)IMyClass *pMyClass; です。

関連するQ&A

  • IUnknown_QueryService ?

    IUnknown_QueryService(pUnkSite, SID_SWebBrowserApp,IID_IWebBrowser2, (void**)&m_pWebBrowser2);// IID_PPV_ARGS(&m_pWebBrowser2));  これを古い形に書き換えるとどうなるのでしょうか? 'IUnknown_QueryService': 識別子が見つかりませんでした とメッセージが出ています。 For those versions of Microsoft Windows that do not include IUnknown_QueryService in Shlwapi.h, this function must be called directly from Shlwapi.dll using ordinal 176. となっています。  よろしくお願いします。

  • BHO-3

    いつもお世話になっています。 STDMETHODIMP CHelloWorldBHO::SetSite(IUnknown* pUnkSite) { HRESULT hr = S_OK; if (m_pSite != NULL){ m_pSite->Release(); m_pSite = NULL; } if (pUnkSite != NULL) { IHTMLDocument3 *pDocument3; HRESULT hr2 = pUnkSite->QueryInterface(IID_IHTMLDocument3, (void **)&pDocument3); if (SUCCEEDED(hr2)){ PutEventHandler(pDocument3); } ////////////////////////////// // IWebBrowser2 へのポインタをキャッシュします。 HRESULT hr = pUnkSite->QueryInterface(IID_IWebBrowser2, (void **)&m_spWebBrowser); if (SUCCEEDED(hr)) { // DWebBrowserEvents2 からのイベントをシンクに登録します。 hr = DispEventAdvise(m_spWebBrowser); if (SUCCEEDED(hr)) { m_fAdvised = TRUE; } } 上のコードの IHTMLDocument3 *pDocument3; HRESULT hr2 = pUnkSite->QueryInterface(IID_IHTMLDocument3, (void **)&pDocument3); if (SUCCEEDED(hr2)){ PutEventHandler(pDocument3); } ですが、 HRESULT hr2 = pUnkSite->QueryInterface(IID_IHTMLDocument3, (void **)&pDocument3); の部分で失敗します。 HRESULT hr = pUnkSite->QueryInterface(IID_IWebBrowser2, (void **)&m_spWebBrowser); if (SUCCEEDED(hr)) { // DWebBrowserEvents2 からのイベントをシンクに登録します。 hr = DispEventAdvise(m_spWebBrowser); if (SUCCEEDED(hr)) { m_fAdvised = TRUE; } } が、上手く動くのでまねをしたのですが上手く行きません。 すみませんが、アドバイスお願いします。

  • Cabの解凍プログラム

    現在Cabの解凍をするプログラムを作っています。 Cabファイル内のファイル数を取得するために、 int WINAPI CabGetFileCount(LPCSTR szArcFile); というAPIを使おうとしているのですが、 実行中に、デバッグエラーが出ます。 エラーメッセージ The value ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention pointer declared with a different calling convention. ソースは以下のものです。 typedef bool (*TFUNC)(LPCSTR); void 関数名(HWND hWnd) { HINSTANCE hCab=NULL; //cab32.dllのインスタンスハンドル TFUNC DllFunction; int FileCount; //cab32.dllのロード hCab = LoadLibrary("cab32.dll"); if(hCab == NULL) { MessageBox(hWnd,"cab32.dllがありません。","エラー",MB_OK); return; } DllFunction=(TFUNC)GetProcAddress(hCab,"CabGetFileCount"); FileCount = (*DllFunction)("test.cab"); FreeLibrary(hCab); } (DLL使用テストのソース) コンパイラーは"VC++6.0" OSはWin2Kになります。 わかるかたよろしくお願いします。

  • DirectShowでのfilterの作り方

    スマートデバイス上で動かす動画処理プログラムを作ろうと思っています。 WindowsMobile 5.0 の機器なのですが、DirectShowのフィルタを自作すれば、目的が達成できるのではないかと考えています。 フィルタは C++ で作るしかないのですよね。。 Windows での開発自体が始めてのため、プロジェクト種類の選択時点で迷っている始末なのですが、参考にすると良いサイトなどがあれば教えてください。

  • エラー内容について

    お世話になっております。 現在、VC++6.0にてアプリを開発中です。 そこで、下記エラーが発生し、処理がうまく行きません。 エラーの内容と、対策をお教え下さい。 [エラー内容] Debug Error! Program:xxxxxxxxx.exe Module: File:i386\chkesp.c Line:42 The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention. (Press Retry to debug the application) エラー発生の場所は、GetProcAddressで、DLLの関数のアドレスを取得し、その関数をコールした結果で起こっています。 DLL内部にログ出力を入れた結果、DLLの関数自体は正常終了しています。 DLLの関数を取得している部分は下記の通りです。 typedef int (APIENTRY *LPGetRouteList)(WORD wdIn1, WORD wdIn2, WORD wdin3);   ・   ・   ・ LPGetRouteList lpGetRouteList;   ・   ・   ・ lpGetRouteList = (LPGetRouteList)GetProcAddress(hHandle,"GetRouteList); 関数を使用している部分は、下記の通りです。 int iRet = 0;   ・   ・   ・ iRet = lpGetRouteList(wdA, wdB, wdC); <- ここでエラーが発生 DLLの関数は以下の通りです。 extern WORD APIENTRY GetRouteList(WORD wdIn1, WORD wdIn2, WORD wdIn3) { WORD wdRet = 0;   ・   ・   ・  return(wdRet); } 以上、長文で見づらいと思われますが、なにとぞ宜しくお願いします。

  • CreateDCA、CreateDCWのパラメータ

    HDC CreateDC(LPCTSTR lpszDriver, LPCTSTR lpszDevice, LPCTSTR lpszOutPut, CONST DEVMODE *lpInitData)にはUnicode版とANSI版が実装されます よってCreateDCAでは HDC CreateDCA(PCTSTR lpszDriver, PCTSTR lpszDevice, PCTSTR lpszOutPut, CONST DEVMODE *lpInitData) CreateDCWでは HDC CreateDCW(LCPWSTR lpszDriver, LCPWSTR lpszDevice, LCPWSTR lpszOutPut, CONST DEVMODE *lpInitData) と定義されているのだと思い、上記の形式で呼び出しましたがエラーとなってしました Run_Time check Failure #0- The Value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling conversion with a function pointer declared with a different calling conversion. なぜCreateDCではなくCreateDCAとCrateDCWを直接呼び出すような面倒なことをしているかというと、APIフックでCreateDCを引っ掛けたいのです CreateDCはCreateDCA、CreateDCWになってしまうのでCreateDCではフック出来ません そこでCreateDCA、CreateDCWでフックして当方の処理を行い、その後で本来のCreateDCA、CreateDCWを呼び出しております ところが呼出し方が悪いらしく上記の英文エラーが出てしまいます CreateDCA、CreateDCWで検索したのですが適当な資料が見当たりません 目下のところ手も足も出ません CreateDCA、CreateDCWのパラメータ指定法(多分エラーの原因だろうと思っていますので・・・)をご存知でしたらご指導願います

  • エラーでリンクができません(VC++)。「外部シンボル

    error LNK2001: 外部シンボル "_IID_IAutoComplete2" は未解決です error LNK2001: 外部シンボル "_CLSID_AutoComplete" は未解決です error LNK2001: 外部シンボル "_IID_IAutoComplete" は未解決です これら3つのエラーが出るためビルドに失敗します(コンパイルは成功しますがリンクに失敗します)。 MSDNによると #include "shldisp.h" #include "shlguid.h" が必要とあるのでincludeしています。VC++上でこのヘッダーファイル上で右クリックをして現れたメニューからファイルを開くと、この中にはきちんと「IID_IAutoComplete2」などが定義されています。またこれらのヘッダーファイルはPlatformSDK 20002年10月版 を使用しています。 MSDNにはshell32.dllのVer5.0以上が必要と書かれていますが、使用しているOSにインストールされているshell32.dllはver6.00.2600.0000です。 #include "shlguid.h"に含まれている以下の行をコピーしてソースに貼り付けると2つ目のエラーはなくなります。 DEFINE_GUID(CLSID_AutoComplete, 0x00BB2763L, 0x6A77, 0x11D0, 0xA5, 0x35, 0x00, 0xC0, 0x4F, 0xD7, 0xD0, 0x62); 環境は Windows XP InternetExplorer 6.0 Visual C++ 6.0 SP5 PlatformSDK(2002/10)(CoreSDK) PlatformSDK(2002/10)(InternetSDK) です。 何が原因でリンクできないのでしょう??まったくお手上げな状態です。分かる方がいましたらよろしくお願いします。

  • 関数名などの固有名詞(?)を英語の文で使うとき

    Win32APIのGetLastError functionのページを見て判断すると http://msdn.microsoft.com/en-us/library/windows/desktop/ms679360%28v=vs.85%29.aspx ~instead of GetLastError. ~by calling the SetLastError function. You should call the GetLastError function~ ~some functions call SetLastError with a zero when~ ~use the FormatMessage function. というように、関数名のみの時は冠詞(the)なしで、「関数名 function」のときはtheをつける、というのがスタンダードと考えていいのでしょうか? また、これはan HRESULT valueやthe HRESULT_FROM_WIN32 macro.といったように、型名やマクロ名 その他、例えばソースファイルやヘッダファイルなどにも当てはめて考えていいのでしょうか? また、「ABC関数内に問題があると考えたので~」というような場合、the ABC functionなどの前に入れる前置詞はin, at, onのどれがいいでしょうか?(状況によりどれもあり?)

  • COMプログラミング教えてください。

    //COMプログラミングVC->VB6.0 Visual C++で、 main.cpp , NumberClass.h , NumberClass.cpp , NumberIDL.idl ファイルを以下のコードで作成し、 実行しましたら、正常にコンソールアプリケーションが動作しました。 次に、 VisualBasic6.0から参照設定で、Number.tlbというタイプライブラリを読み込ませて実行させたところ、「Functionまたは変数が必要です。」とエラーが表示されました。 どうすれば解決できますか?よろしくお願いします。 VB6.0のコード Private Sub Command1_Click() Dim a As NumberLibrary.NumberClass Dim b As Long b = a.Add(15, 35) End Sub //main.cpp #include<stdio.h> #include<string.h> #include"NumberClass.h" int main() { NumberClass Number; printf("%d",Number.Add(10,90)); getchar(); return 0; } //NumberClass.h class NumberClass { private: int num; public: int Add(int a,int b); void Save(int a); void Load(int *a); }; //NumberClass.cpp #include"NumberClass.h" int NumberClass::Add(int a,int b) { return a+b; } void NumberClass::Save(int a) { num=a; return; } void NumberClass::Load(int *a) { *a=num; return; } //NumberIDL.idl import "oaidl.idl"; import "ocidl.idl"; [uuid(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx),version(1.0)] library NumberLibrary { importlib("stdole2.tlb"); [uuid(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx), object] interface INumber : IUnknown { HRESULT Add([in]int a,[in]int b); HRESULT Save([in]int a); HRESULT Load([out]int *a); }; [uuid(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)] coclass NumberClass { interface INumber; } };

  • Cygwinでg++がグローバル関数をはじいてしまう

    現在Win XP上にGygwinを導入し C++の勉強をしています。 書籍を購入し、以下のプログラムを試したところ グローバル関数宣言をしているにもかかわらず main() とfunc1()中で変数”count”が undeclared (first use this function) として弾かれてしまいます。 どうしてなのでしょうか? よろしくお願いします。 //example global variavle. #include<iostream> using namespace std; void func1(); void func2(); static int count; //This is global variavle. int main() { int i; //This is local variavle. for(i=0; i<10 ; i++){ count = i * 2; func1(); //calling func1(). } return 0; } void func1() { cout << "count: " << count; //access global "count" cout << "\n"; func2(); //calling func2(). } void func2() { int count; //define local "count" for(count=0;count<3;count++) { cout << "."; } }

専門家に質問してみよう