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.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);
}
}
この回答への補足
説明のためにコードを簡略化したので色々抜けてますね;
実際はNonDelegating~も実装してますが開発中のコードは載せられないので
検証用にCTransInPlaceFilterを派生させてmyMethod()だけ追加したコードを
作りました。
(名前はMyFilterの方が良かったな…)
http://www.rupan.net/uploader/download/125135935 …
pass:1234(ウィルスバスターでスキャンしてますが自己責任でお願いします)
今度はデバッグすると
pMyClass->myMethod();
を抜けるとデストラクタに入り例外が発生してしまいます。
メモリアクセス違反が起こってるようですが
何が起こっているのか余計に分からなくなってきました…。
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;
}
提示して頂いたコードに書き直すことで
動作するようになりました。本当にありがとうございます。
今まで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 …
(保証はないが)ビットパターンを変更せずに再解釈する、とあります。
つまり無理やりな代入を行っただけで正しくキャストできておらず今回のエラーに繋がった、ということではないでしょうか?
No.4
- 回答日時:
こんにちは。
御礼頂きました。もう一度試しましたが、確かにreinterpret_cast<>の時におかしくなっています。
よくよく考えれば、thisはCMyClass*constでした。
「当方がクロスキャストしていないと勘違いして元凶であるreinterpret_cast<>を止めた」から動作したと言う事なので、クロスキャスト自体は関係ありませんでした。
当方はクラスのキャストにreinterpret_cast<>を使った事が無いので、此の事例は初めて見ました。
肝心な「クラスのキャストにreinterpret_cast<>を使用すると何故おかしくなるのか」に関して、当方はC++の規格には詳しくない為、これ以上明言する訳にはいかないので、大変申し訳ありませんが、此処でギブアップと言う事になります。
この回答への補足
各キャストが返す値を観察してみましたがどのキャストも同じ値を返してますね。
結局原因はよく分かりませんが当初の問題は解決しているので
これで締めきらせていただきます。
回答していただいた皆様、ありがとうざいました。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- その他(プログラミング・Web制作) 十進BASICでの再帰についての質問です。 2 2022/11/18 09:17
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- C言語・C++・C# 大量のデータを読み込んで表示する速度を改善したい 8 2023/05/07 13:29
- C言語・C++・C# C# DatagridviewにExcelシートを反映するとエラーが出る 2 2023/05/06 17:12
- Java Java プログラム public class Main { public static void 3 2023/08/10 23:46
- Java java 入力 3 4 3 出力 ABC DEFG HIJ このようなプログラムの書き方を教えてくだ 2 2022/07/15 14:18
- C言語・C++・C# スタックフレームの消滅 6 2023/05/20 12:33
- C言語・C++・C# C言語の課題が出たのですが自力でやっても分かりませんでした。 要素数がnであるint型の配列v2の並 3 2022/11/19 17:41
- Java eclipse実行ができない 2 2022/07/27 04:47
- その他(プログラミング・Web制作) laravel 本番環境でメールが送れません。 1 2023/02/17 17:57
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
戻り値を返す関数の前に(void)...
-
C++にてtemplateで受け取った任...
-
【gcc・cygwin】multiple defin...
-
Notepad++の関数リスト表示の変...
-
int main()、void main()、void...
-
C# KeyDownイベントでショート...
-
ArduinoでMouse関数を使用して...
-
ドラッグしたときにマウスカー...
-
多重定義が起きている?--lnk20...
-
合格か否かを表示するプログラ...
-
typedef unsigned int UINT;が...
-
構造体を宣言と共に初期化する方法
-
C++別のオブジェクトからメンバ...
-
VC++でGetKeyboardStateがうま...
-
C# Controls.Addで動的に配置し...
-
C#でラジオボタンを設定に記録...
-
void*型の配列について
-
gcc: incompatible pointer type
-
マルチメディアタイマーの使用方法
-
DLLの関数呼び出しで引数がある...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
【gcc・cygwin】multiple defin...
-
int main()、void main()、void...
-
戻り値を返す関数の前に(void)...
-
既定のコンストラクタがありま...
-
Notepad++の関数リスト表示の変...
-
ArduinoでMouse関数を使用して...
-
多重定義が起きている?--lnk20...
-
C++にてtemplateで受け取った任...
-
静的でないメンバ関数の呼び出...
-
C# Controls.Addで動的に配置し...
-
const_castのつかいどころを教...
-
(void)0 はどんな意味ですか
-
C# KeyDownイベントでショート...
-
gcc: incompatible pointer type
-
C#でラジオボタンを設定に記録...
-
VC++でGetKeyboardStateがうま...
-
C言語 ① 5秒間 1秒間隔で点滅を...
-
void*型の配列について
-
GDI+の使用方法について
-
DirectInput でのエラー
おすすめ情報