Можно ли вернуть CComPtr из функции?

Я пишу функцию, которая создает IMFSample и добавляет к нему буфер. Я хотел бы просто вернуть новый CComPtr в IMFSample, а не передавать указатель на указатель в параметрах. Это нормально делать это? Будет ли счетчик ссылок на образец IMFS правильным после выхода из функции? Я исследовал и не смог найти ни одного примера или обсуждения этого использования. Вот упрощенный пример функции:

CComPtr<IMFSample> getSample() {
    HRESULT hr = S_OK;
    CComPtr<IMFSample> pSample = NULL;

    hr = MFCreateSample(&pSample);
    if (hr != S_OK) {
        // pSample should be released at exception.
        throw "MFCreateSample failed";
    }

    // ...Create buffer, Add buffer, etc...

    return pSample;
}

Здесь я добавил более длинную версию, чтобы показать, как она упрощает мою обработку ошибок с помощью исключений. Остальная часть моей программы структурирована с использованием исключений, поэтому я пытаюсь изолировать части "COM", чтобы они лучше соответствовали остальным, насколько я могу.

void decodeLoop() {
    CComPtr<IMFSample> pSample;

    while (noError) {
        try {
            pSample = getNALSample(decoderPkt, MAX_SIZE);
            processSample(pSample);
            pSample = NULL;
            ...
        }
        catch (MyException& e) {
            ...
        }
    }
}

CComPtr<IMFSample> getNALSample(DecoderPkt* decoderPkt, DWORD maxBuffSize) {
    HRESULT hr = S_OK;
    CComPtr<IMFSample> pSample = nullptr;
    CComPtr<IMFMediaBuffer> pMediaBuffer = nullptr;
    byte *pBuffer = nullptr;

    // MFCreate Sample
    hr = MFCreateSample(&pSample);
    if (hr != S_OK) 
        throw MyException(hr, "getNALSample::MFCreateSample failed");

    // Get buffer
    hr = MFCreateMemoryBuffer(maxBuffSize, &pMediaBuffer);
    if (hr != S_OK) 
        throw MyException(hr, "getNALSample::MFCreateMemoryBuffer failed");

    // Set up buffer pointer
    hr = pMediaBuffer->Lock(&pBuffer, nullptr, nullptr);
    if (hr != S_OK) 
        throw MyException(hr, "getNALSample::pMediaBuffer->Lock failed");

    // Build NAL from decoder que
    hr = pMediaBuffer->SetCurrentLength(buildNAL(pBuffer, decoderPkt));
    if (hr != S_OK) 
        throw MyException(hr, "getNALSample::pMediaBuffer->SetCurrentLength failed");

    hr = pMediaBuffer->Unlock();
    if (hr != S_OK) 
        throw MyException(hr, "getNALSample::pMediaBuffer->Unlock failed");

    // Add buffer to sample
    hr = pSample->AddBuffer(pMediaBuffer);
    if (hr != S_OK) 
        throw MyException(hr, "getNALSample::pSample->AddBuffer failed");

    return pSample;
}

Спасибо.

1 ответ

Решение

Работает нормально.

Причина, по которой вы не видите много такого использования, состоит в том, что, как он спроектирован, он выглядит как действительно "приватный" метод.

Плюс это бросает вместо возвращения HRESULT. Лично я всегда предпочитаю возвращать HRESULT вместо броска (даже если вы носите с собой ComPtr), потому что с ним легче обращаться.

Вот (более сложный, я признаю) способ сделать это, который выглядит более "COM" (или больше "Microsoft", если хотите):

HRESULT GetSample(REFIID riid, void**ppv) // you can add other parameters (in front, and leave riid and ppv last)
{
  HRESULT hr = S_OK;
  CComPtr<IMFSample> pSample;

  hr = MFCreateSample(&pSample);
  if (hr != S_OK) return hr; // or if (FAILED(hr) ? depends if you handle S_FALSE an other non error cases

  // ...Create buffer, Add buffer, etc...

  return pSample->QueryInterface(riid, ppv);
}
Другие вопросы по тегам