アプリ版:「スタンプのみでお礼する」機能のリリースについて

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になってるはずなんですが…
原因が分かる方おられましたらよろしくお願いいたします。

A 回答 (4件)

当てずっぽで不確かな回答で申し訳ありません。


#暫くC++から離れていたので忘れかけてます

>pMyClass->myMethod();←ここでエラー

ドット演算子とアロー演算子の使い分けを再確認してみて下さい。

この回答への補足

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

補足日時:2009/08/27 12:50
    • good
    • 0

 こんにちは。


 上手く行かないかもしれませんが、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);
}
}

この回答への補足

説明のためにコードを簡略化したので色々抜けてますね;
実際はNonDelegating~も実装してますが開発中のコードは載せられないので
検証用にCTransInPlaceFilterを派生させてmyMethod()だけ追加したコードを
作りました。
(名前はMyFilterの方が良かったな…)
http://www.rupan.net/uploader/download/125135935 …
pass:1234(ウィルスバスターでスキャンしてますが自己責任でお願いします)

今度はデバッグすると
pMyClass->myMethod();
を抜けるとデストラクタに入り例外が発生してしまいます。
メモリアクセス違反が起こってるようですが
何が起こっているのか余計に分からなくなってきました…。

補足日時:2009/08/27 16:53
    • good
    • 0

 こんばんは。

補足頂きました。

 原因は「ダウンキャストが不完全であった」と言う事の様です。
 多重継承になっている為、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;
}
    • good
    • 0
この回答へのお礼

提示して頂いたコードに書き直すことで
動作するようになりました。本当にありがとうございます。

今まで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 …
(保証はないが)ビットパターンを変更せずに再解釈する、とあります。
つまり無理やりな代入を行っただけで正しくキャストできておらず今回のエラーに繋がった、ということではないでしょうか?

お礼日時:2009/08/28 10:15

 こんにちは。

御礼頂きました。

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

この回答への補足

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

回答していただいた皆様、ありがとうざいました。

補足日時:2009/08/28 17:17
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!