В чем разница между методами свойств COM и обычными интерфейсными методами?
Последние пару недель я возился с WRL на уровне ABI и столкнулся с этой проблемой.
У меня есть интерфейс, определенный в 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, когда я пытаюсь установить параметр канала для полученного канала, я получаю нарушение прав доступа. Очевидно, я знаю, что память плохая, но, как я понимаю, свойства COM, по сути, они являются вызовами функций, а метод свойства и метод GetFeed делают то же самое, за исключением части поиска.
Вот мои вопросы:
- В чем разница между методами свойств COM и обычными интерфейсными методами с точки зрения прогнозируемого возвращаемого значения, если оно есть?
- Почему параметр метода свойств инициализируется значением nullptr, а параметр метода GetFeed не совпадает, если они описаны точно так же в IDL?
- Если исходящие параметры в методах свойств инициализированы, какая часть времени выполнения COM делает это для меня и является ли это управляемым? IE есть способ получить память, в которую я могу написать, переданную мне?
Я знаю, что мог бы спроектировать это, но это не главное. Я просто пытаюсь узнать, как все это работает.
Благодарю.
1 ответ
В вашей лямбде вы захватываете по ссылке с [&]
, Вам нужно захватить feed
параметр по значению, так как стековый фрейм давно ушел к тому времени, когда ваша лямбда будет выполняться.
Большая проблема заключается в том, что клиент не знает, когда он сможет получить результаты, поскольку вы не предоставляете эту информацию. (Я вижу, что вы создаете неиспользуемый объект Win32 Event, так что, возможно, есть какой-то другой код для этой работы, который вы удалили).