Outputpin 中的调用约定冲突

Posted

技术标签:

【中文标题】Outputpin 中的调用约定冲突【英文标题】:Calling Convention conflict in Outputpin 【发布时间】:2014-04-04 13:13:57 【问题描述】:

尝试将我的过滤器输出引脚连接到另一个过滤器时出现以下错误。

这是触发错误的行(在 outputpin 代码中)

HRESULT hr = pPin->GetAllocatorRequirements(pprops); 

这里是函数声明:

class MCMyOutputPin : public CBaseOutputPin

    ....
    HRESULT CheckMediaType(const CMediaType *pmt);
    HRESULT SetMediaType(const CMediaType *pmt);
    HRESULT CompleteConnect(IPin *pReceivePin);
    //virtual HRESULT __stdcall Connect(IPin* pPin, const AM_MEDIA_TYPE *pmt);
    HRESULT BreakConnect();
    HRESULT GetMediaType(int i, CMediaType *pmt);
    HRESULT DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pProps);
    HRESULT DecideAllocator(IMemInputPin *pPin, IMemAllocator **ppAlloc);
    HRESULT Deliver(IMediaSample* sample);
    BOOL IsConnected();

    ...

我相信 DecideAllocator 是由 GetAllocatorRequirements 调用的。

根据 msdn (Building DirectShw Filters),函数必须用 __stdcall 声明。 所以调用函数和被调用函数之间似乎存在调用约定冲突。 但是,如果我尝试将函数设置为 __stdcall:

HRESULT __stdcall DecideAllocator(IMemInputPin *pPin, IMemAllocator **ppAlloc);

我得到编译错误:

'MCMyOutputPin::DecideAllocator':覆盖虚函数不同 从 'CBaseOutputPin::DecideAllocator' 仅通过调用约定

所以我尝试确保使用 stdcall 调用约定构建基类: 我打开了基类项目(C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0\Samples\multimedia\directshow\baseclasses)并设置

ConfigurationProperties->C/C++->Advanced->调用约定 到 __stdcall(/Gz)

总之:

我相信我有调用约定冲突 我无法更改代码中的调用约定 在基类项目中设置调用约定并重新编译仍然不能解决问题

但我仍然无法将我的项目的 outputpins 函数的调用约定更改为 stdcall

更新:

这是我的过滤器 NonDelegatingQueryInterface:

STDMETHODIMP MyFilter::NonDelegatingQueryInterface(REFIID riid, void **ppv)

    if(riid == IID_IMyInterfilter) 
        mylogger->LogDebug("In Nondelegationqueryinterface", L"D:\\TEMP\\yc.log");
        return GetInterface((IMyFilter*)this, ppv);
    

    else 
    
        return CBaseFilter::NonDelegatingQueryInterface(riid, ppv);
    

这里是过滤器标题:

class MyFilter : public  CBaseFilter, public IMyFilter

public: 

    CCritSec lockfilter;
    DECLARE_IUNKNOWN;

    const LONGLONG MEDIATIME = 5;

    MyFilter(LPUNKNOWN pUnk, HRESULT* phr);
    virtual ~MyFilter(void);

     virtual int  GetPinCount();
    virtual CBasePin*  GetPin(int n);

    STDMETHODIMP Run(REFERENCE_TIME tStart);
    STDMETHODIMP Pause();
    STDMETHODIMP Stop();

    void acceptFilterInput(LPCWSTR pinname, IMediaSample* sample);
    CMyInputPin* getPreviousPIN(LPCWSTR pinname);
    CMyInputPin* getNextPIN(LPCWSTR pinname);
    //BOOL requestRecordMode(LPCWSTR pinname); //returns false if previous pin thread is not sleeping

    static CUnknown* WINAPI CreateInstance(LPUNKNOWN pUnk, HRESULT *phr);
    STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv);

    //STDMETHODIMP   StartRecording();
    STDMETHODIMP  GetThePinCount(int* result);
    //STDMETHODIMP StopRecording();
    STDMETHOD_(IPin*,GetMyPin)(int index);

    //STDMETHODIMP Next(ULONG cPins, IPin** pppins, ULONG fetched);
    //STDMETHODIMP Clone(IEnumPins **ppenum);
    //STDMETHODIMP Reset();
    //STDMETHODIMP Skip(ULONG cpins);
    //

    CCritSec m_lock_filter;

    TimeGiver* m_pTimeGiver;    

    MCMyOutputPin *outpin;
    static const int COUNT_INPUTPINS = 3;
    static unsigned __stdcall workerthreadfunc(void *);
    HANDLE workerThreadHandle;
private:

    MyLogger *mylogger;
    CCritSec m_critSec;
    bool running;




    LPCWSTR currentInputPin;

    void startSyncThread();






     CMyInputPin* GetPinByName(LPCWSTR name);

     LONGLONG* mediaTimeBuffer;


     CMyInputPin* inputpins[COUNT_INPUTPINS];

;

这里是过滤器的实现:

#include "MyInputPin.h"
#include "CMyOutPutPin.h"
#include "MyLogger.h"
#include <windows.h>
#include <process.h>
#include <string>

using namespace std;



MyFilter::MyFilter(LPUNKNOWN pUnk, HRESULT* phr) : CBaseFilter(NAME("MyFilter"), pUnk, &lockfilter, CLSID_MyInterFilter)



    HRESULT *hr_0 = NOERROR;
    HRESULT *hr_1 = NOERROR;
    HRESULT* hr_2 = NOERROR;
    HRESULT* hr_3 = NOERROR;


    inputpins[0] = new CMyInputPin(TEXT("PIN0"), L"PIN0", pUnk, this, &this->m_lock_filter, hr_0, 0);
    inputpins[1] = new CMyInputPin(TEXT("PIN1"), L"PIN1", pUnk, this, &this->m_lock_filter, hr_1, 1);
    inputpins[2] = new CMyInputPin(TEXT("PIN2"), L"PIN2", pUnk, this, &this->m_lock_filter, hr_2, 2);
    outpin = new MCMyOutputPin(this, hr_3, TEXT("PINOUT0"));
    this->running = false;
    mylogger = new MyLogger();

    mylogger->LogDebug("Construtor of Filter", L"D:\\TEMP\\yc.log");

    m_pTimeGiver = new TimeGiver(2, MEDIATIME);










CMyInputPin* MyFilter::getPreviousPIN(LPCWSTR pinname)

    CMyInputPin *inpin = GetPinByName(pinname);
    int position = inpin->m_position;
    int adjused = position + COUNT_INPUTPINS - 1;
    int newInex = adjused % COUNT_INPUTPINS;
    return inputpins[newInex];


CMyInputPin* MyFilter::getNextPIN(LPCWSTR pinname)

    CMyInputPin *inpin = GetPinByName(pinname);
    int position = inpin->m_position;
    int incremented = position++;
    int newIndex = incremented % COUNT_INPUTPINS;
    return inputpins[newIndex];

//BOOL MyFilter::requestRecordMode(LPCWSTR pinname)  //returns false if previous pin thread is not sleeping
//  for (int i = 0; i < COUNT_INPUTPINS; i++)
//  
//      if (wcscmp(pinname, inputpins[i]->Name()) == 0)
//      
//          inputpins[i]->m_bIsSleeping = false;
//      
//      else 
//          inputpins[i]->m_bIsSleeping = true;
//      
// 
//  
//  return TRUE;
//


HRESULT MyFilter::Run(REFERENCE_TIME tStart)

    mylogger->LogDebug("In MyFilter::Run:", L"D:\\TEMP\\yc.log");
    CAutoLock cobjectlock(&m_critSec);  
    workerThreadHandle = (HANDLE) _beginthreadex(NULL, 0, workerthreadfunc, (void *)this, 0, NULL);
    //boost::thread workerThread(&MyFilter::startSyncThread, this);
    m_tStart = tStart;
    if (m_State == State_Stopped)
        HRESULT hr = Pause();

        if (FAILED(hr)) 
            return hr;
        
    


    return S_OK;


HRESULT MyFilter::Stop()

    mylogger->LogDebug("In MyFilter::Stop:", L"D:\\TEMP\\yc.log");
    CAutoLock cobjectlock(&m_critSec);
    m_State = State_Stopped;
    this->m_pTimeGiver->stop();
    //this->m_thread.join();
    return S_OK;


HRESULT MyFilter::Pause()

    CAutoLock cobjectlock(&m_critSec);
    m_State = State_Paused;

    mylogger->LogDebug("In MyFilter::PAuse:", L"D:\\TEMP\\yc.log");

    return S_OK;




MyFilter::~MyFilter(void)



    //delete mylogger;



    //delete outpin;
    //delete[] inputpins;



int  MyFilter::GetPinCount()

    return COUNT_INPUTPINS + 1; //One outputpin



IPin* MyFilter::GetMyPin(int n)


    CBasePin* pin = this->GetPin(n);
    return pin;



CBasePin*  MyFilter::GetPin(int n)

    if (n >= 0 && n < COUNT_INPUTPINS)
    
        return inputpins[n];

    
    if (n == 3)
    
        return outpin;
    
    return NULL;


//HRESULT MyFilter::GetThePinCount(int *result)
//
//  *result = 4;
//

HRESULT MyFilter::GetThePinCount(int* giveme)

    *giveme = COUNT_INPUTPINS + 1;
    return S_OK;


STDMETHODIMP MyFilter::NonDelegatingQueryInterface(REFIID riid, void **ppv)

    if(riid == IID_IMyInterfilter) 
        mylogger->LogDebug("In Nondelegationqueryinterface", L"D:\\TEMP\\yc.log");
        return GetInterface((IMyFilter*)this, ppv);
    

    else 
    
        return CBaseFilter::NonDelegatingQueryInterface(riid, ppv);
    


/*RESULT MyFilter::StartRecording()

    this->running = true;
    return S_OK;

*/
//
//HRESULT MyFilter::StopRecording()
//
//  this->running = false;
//  return S_OK;
//
//

CUnknown* WINAPI MyFilter::CreateInstance(LPUNKNOWN pUnk, HRESULT *phr)


    CUnknown* pNewFilter = new MyFilter(pUnk, phr);

    if (phr)
    
        if (pNewFilter == NULL) 
            *phr = E_OUTOFMEMORY;
        else
            *phr = S_OK;
    

    return pNewFilter;



void MyFilter::acceptFilterInput(LPCWSTR pinname, IMediaSample* sample)


    mylogger->LogDebug("In acceptFIlterInput", L"D:\\TEMP\\yc.log");
    outpin->Deliver(sample);


//STDMETHODIMP MyFilter::Next(ULONG cPins, IPin** pppins, ULONG fetched)
//
//
//
//STDMETHODIMP MyFilter::(IEnumPins **ppenum)
//
//
//
//STDMETHODIMP MyFilter::Reset()
//
//
//
//STDMETHODIMP MyFilter::Skip(ULONG cpins)
//
//
//




CMyInputPin* MyFilter::GetPinByName(LPCWSTR name)

    for (int i = 0; i < COUNT_INPUTPINS; i++)
    
        if (wcscmp(name, inputpins[0]->Name()))
        
            return inputpins[0];
        
    


    return NULL;



void MyFilter::startSyncThread()

    this->m_pTimeGiver->start();


unsigned int  MyFilter::workerthreadfunc(void * param)

    MyFilter* myfilter;
    myfilter = (MyFilter *)param;
    myfilter->m_pTimeGiver->start();
    return S_OK;

【问题讨论】:

【参考方案1】:

错误的调用约定是收到此错误消息的典型问题,但这只是可能的原因之一。错误的指针转换可以“实现”相同的不匹配,例如,当您期望返回 IFooA* 指针,而您返回 IFooB* 时。然后调用IFooA::BarA 有效地执行你的IFooB::BarB 代码,它们的语法/调用差异结果是堆栈帧失败。我相信这就是您所遇到的情况,因为仅在特定接口/方法上使用错误的调用约定来构建并不容易。

问题肯定出在调试器停止的界面上。我将从NonDelegatingQueryInterface 实现开始检查,以确保您返回正确的接口,这些接口与IIDs 请求的正确匹配。

UPD。无论最初的问题是什么,这看起来都不好:

CMyInputPin* MyFilter::GetPinByName(LPCWSTR name)

    for (int i = 0; i < COUNT_INPUTPINS; i++)
    
        // 1. you want [i], not [0]
        // 2. you want if(wcscmp(...) == 0)
        if (wcscmp(name, inputpins[0]->Name()))
        
            // 3. you want [i], not [0]
            return inputpins[0];
        
    

【讨论】:

所以问题出在过滤器而不是引脚上?因为pin不是com类,也没有NoDelegatingQueryInterface方法。 Pin 也是一个 COM 对象,它特别实现了接口。问题可能在于演员阵容不佳,但没有信息可以添加更详细的内容。 我已经添加了更多代码。希望这是您需要帮助我的信息。

以上是关于Outputpin 中的调用约定冲突的主要内容,如果未能解决你的问题,请参考以下文章

汇编 ? cdecl 函数调用约定,stdcall 函数调用约定

《逆向工程核心原理》--- 函数调用约定

x86 x64下调用约定浅析

如何在 Visual C++ 中使用 Delphi 的寄存器调用约定调用函数?

C/C++学习笔记 关于调用约定

带你玩转Visual Studio——调用约定与(动态)库