COM属性方法和常规接口方法有什么区别?

时间:2015-03-18 01:13:17

标签: c++ windows-runtime wrl

过去几周我一直在ABI层寻找WRL,并遇到了这个问题。

我在IDL中定义了一个接口,如下所示:

namespace Async{
[uuid(f469e110-7ef5-41df-a237-9ddef9aed55c), version(1.0)]
interface IDownloader : IInspectable
{
    HRESULT GetFeed([in] HSTRING url,[out, retval] Windows.Web.Syndication.SyndicationFeed ** feed);
    [propget]HRESULT Feed([out, retval]Windows.Web.Syndication.SyndicationFeed ** feed);
}

[version(1.0), activatable(1.0)]
runtimeclass Downloader
{
    [default] interface IDownloader;
}

}

我在头文件中定义了这样的内容:

#pragma once

#include "Async_h.h"

namespace ABI {
    namespace Async {


    class Downloader : public Microsoft::WRL::RuntimeClass<ABI::Async::IDownloader>
    {
        InspectableClass(L"Async.Downloader", BaseTrust);

    public:
        Downloader();
        STDMETHOD(GetFeed)(HSTRING url, ABI::Windows::Web::Syndication::ISyndicationFeed ** feed);
        STDMETHOD(get_Feed)(ABI::Windows::Web::Syndication::ISyndicationFeed ** feed);

    private:

        //Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Uri> feedUrl;
        Microsoft::WRL::ComPtr<ABI::Windows::Web::Syndication::ISyndicationFeed> m_feed;

    };

    ActivatableClass(Downloader);
}

}

在我的cpp文件中,我实现了以下功能:

    STDMETHODIMP Downloader::GetFeed(HSTRING url, ISyndicationFeed** feed)
    {

        HRESULT hr;
        RoInitializeWrapper ro(RO_INIT_MULTITHREADED);
        ComPtr<IUriRuntimeClass> uri;
        ComPtr<IUriRuntimeClassFactory> uriFactory;
        hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_Foundation_Uri).Get(), &uriFactory);
        hr = uriFactory->CreateUri(url, uri.GetAddressOf());

        ComPtr<ISyndicationClient> client;
        ComPtr<IInspectable> inspectable;

        RoActivateInstance(HStringReference(RuntimeClass_Windows_Web_Syndication_SyndicationClient).Get(), &inspectable);

        hr = inspectable.As(&client);
        Event timerCompleted(CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, WRITE_OWNER | EVENT_ALL_ACCESS));
        auto callback = Callback<IAsyncOperationWithProgressCompletedHandler<SyndicationFeed*,RetrievalProgress>>([&](IAsyncOperationWithProgress<SyndicationFeed*,RetrievalProgress> *op, AsyncStatus status) ->HRESULT 
        {
            auto error = GetLastError();
            if (status == AsyncStatus::Completed)
            {
                hr = op->GetResults(m_feed.GetAddressOf());
                *feed = m_feed.Get();

            }


            return S_OK;
        });
        ComPtr<IAsyncOperationWithProgress<SyndicationFeed*,RetrievalProgress>>  operation;
        hr = client->RetrieveFeedAsync(uri.Get(), operation.GetAddressOf());
        operation->put_Completed(callback.Get());
        return S_OK;
    }


    STDMETHODIMP Downloader::get_Feed(ISyndicationFeed** feed)
    {
        *feed = m_feed.Get();
        return S_OK;
    }

该属性按预期工作,它应该是c ++ / cx。但是,在GetFeed方法中,当我尝试将feed参数设置为检索到的Feed时,我会收到访问冲突。显然我知道内存不好但是我理解COM属性的方式,它们本质上是函数调用,属性方法和GetFeed方法完全相同,减去了检索部分。

以下是我的问题:

  1. COM属性方法和常规接口方法之间的区别在于预计的返回值(如果有的话)?
  2. 为什么属性方法的参数初始化为nullptr,GetFeed方法的参数在IDL中描述完全相同时不会?
  3. 如果属性方法中的out参数被初始化,那么COM运行时的哪个部分正在为我做这个并且可控制? IE有没有办法让我可以写的内存传递给我?
  4. 我知道我可能会将其设计出来,但这不是重点。我只是想了解它是如何运作的。

    感谢。

1 个答案:

答案 0 :(得分:1)

在你的lambda中,你通过引用[&]捕获。您需要按值捕获feed参数,因为堆栈帧在lambda执行时已经很久了。

更大的问题是客户不知道何时可以检索结果,因为您没有提供该信息。 (我看到你创建了一个未使用的Win32事件对象,所以也许还有一些其他代码可以让你删除它的工作。)