1

我需要将 IRandomAccessStream 放到没有选择器的文件中。

但是,我坚持使用 IStorageFile 或 IRandomAccessStreamReference 并且找不到从其中任何一个获取 IRandomAccessStream 的方法。

我用 C++(没有 /ZW)编写代码,但我认为在这种情况下并不重要。

请帮忙,摩西

4

1 回答 1

1

我设法使用 StorageFile 的 OpenReadAsync 做我想做的事。但这涉及 2 个异步调用并且很麻烦。我想知道是否有更短更优雅的方式。相关示例代码如下:

IFACEMETHODIMP MyClass::BeginCreateObject( 
    //... rest of parameters
    _In_ IMFAsyncCallback *pCallback,
    _In_ IUnknown *punkState)
{
    OutputDebugStringW(__FUNCTIONW__);
    HRESULT hr;

    HString hstrStorageFile;
    hstrStorageFile.Set(RuntimeClass_Windows_Storage_StorageFile);

    // Get the Activation Factory
    ComPtr<IActivationFactory> pStorageFileActivationFactory;
    hr = GetActivationFactory(hstrStorageFile.Get(), &pStorageFileActivationFactory);
    if (FAILED(hr))
    {
        ::Microsoft::WRL::Details::RaiseException(hr);
    }

    // QI for StorageFileStatics
    ComPtr<IStorageFileStatics> pStorageFileStatics;
    hr = pStorageFileActivationFactory.As(&pStorageFileStatics);
    if (FAILED(hr))
    {
        ::Microsoft::WRL::Details::RaiseException(hr);
    }

    HString hstrFileName;
    hstrFileName.Set(L"My_Cool_Movie.ts");

    // Call CreateFileAsync
    __FIAsyncOperation_1_Windows__CStorage__CStorageFile * operation;    
    hr = pStorageFileStatics->GetFileFromPathAsync(hstrFileName.Get(),
        &operation
        );
    if (FAILED(hr))
    {
        ::Microsoft::WRL::Details::RaiseException(hr);
    }

    typedef IAsyncOperationCompletedHandler<StorageFile*> HandlerDoneType; 
    ComPtr<HandlerDoneType> handler(Callback<HandlerDoneType>( 
        this, &MyClass::FileOpenCompletionHandler)); 
    hr = operation->put_Completed(handler.Get()); 

   ComPtr<IMFAsyncResult> spResult;

   //maybe I should pass some data in the first parameter?
   hr = MFCreateAsyncResult(nullptr, pCallback, punkState, &_spOpenResult);

   //the further processing will be done in the completion handler
    return  hr;
}

IFACEMETHODIMP MyClass::EndCreateObject( 
    _In_ IMFAsyncResult *pResult,
    _Out_  MF_OBJECT_TYPE *pObjectType,
    _Out_  IUnknown **ppObject)
{
    OutputDebugStringW(__FUNCTIONW__);
    if (pResult == nullptr || pObjectType == nullptr || ppObject == nullptr)
    {
        return E_INVALIDARG;
    }

    HRESULT hr = S_OK;
    //get a random access stream 
    if(!_spFile)
    {
        return E_FAIL;
    }

    ComPtr<IRandomAccessStream> streamHandle;
    hr = _spStream.As(&streamHandle);
    if (FAILED(hr))
    {
        ::Microsoft::WRL::Details::RaiseException(hr);
    }

    //Do what you need with IRandomAccessStream!
    //...

    return S_OK;
}

IFACEMETHODIMP MyClass::CancelObjectCreation( 
    _In_ IUnknown *pIUnknownCancelCookie)
{
    return E_NOTIMPL;
}

HRESULT MyClass::FileOpenCompletionHandler( IAsyncOperation<StorageFile*>* async, AsyncStatus status)
{
    //file is open, call the invoke to carry one

    if (status == Completed) { 
        HRESULT hr = async->GetResults(_spFile.GetAddressOf()); 

        if (_spFile) { 
            ComPtr<IRandomAccessStreamReference> streamReference;
            hr = _spFile.As(&streamReference);
            if (FAILED(hr))
            {
                ::Microsoft::WRL::Details::RaiseException(hr);
            }

            __FIAsyncOperation_1_Windows__CStorage__CStreams__CIRandomAccessStreamWithContentType * operation;    
            hr = streamReference->OpenReadAsync(&operation);

            if (FAILED(hr))
            {
                ::Microsoft::WRL::Details::RaiseException(hr);
            }

            typedef IAsyncOperationCompletedHandler<IRandomAccessStreamWithContentType*> OpenReadAsyncHandlerDoneType; 
            ComPtr<OpenReadAsyncHandlerDoneType> handler(Callback<OpenReadAsyncHandlerDoneType>( 
                this, &MyClass::FileOpenReadCompletionHandler)); 

            hr = operation->put_Completed(handler.Get()); 
        }

        return hr;
    }
    else { 
        OutputDebugStringW(L"Unexpected async status\n");
        return E_FAIL;
  } 

    return S_OK;
}

HRESULT MyClass::FileOpenReadCompletionHandler( IAsyncOperation<IRandomAccessStreamWithContentType*>* async, AsyncStatus status)
{
    if (status == Completed) { 
        HRESULT hr = async->GetResults(_spStream.GetAddressOf()); 

        if (_spStream) { 
            _spOpenResult->SetStatus(S_OK);
            hr = MFInvokeCallback(_spOpenResult.Get());
            _spOpenResult.ReleaseAndGetAddressOf();
        }
        return hr;
    }
    else { 
        OutputDebugStringW(L"Unexpected async status\n");
        return E_FAIL;
  } 

    return S_OK;
}
于 2012-08-29T11:58:16.423 回答