COM 属性 方法和常规接口方法有什么区别?
What is the difference between COM property methods and regular interface methods?
过去几周我一直在 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 方法中,当我尝试将提要参数设置为检索到的提要时,我遇到了访问冲突。显然我知道内存不好,但我理解 COM 属性的方式,它们本质上是函数调用,属性 方法和 GetFeed 方法在做完全相同的事情,减去检索部分。
这是我的问题:
- COM 属性 方法和常规接口方法在预计 return 值方面有何区别(如果有)?
- 为什么 属性 方法的参数初始化为 nullptr 和 GetFeed 方法的参数不是在 IDL 中描述的完全相同?
- 如果 属性 方法中的 out 参数被初始化,那么 COM 运行time 的哪一部分正在为我做这件事并且是可控的? IE 有没有办法让我可以写入的内存传递给我?
我知道我可能会设计掉它,但这不是重点。我只是想了解它是如何工作的。
谢谢。
在您的 lambda 中,您使用 [&]
通过引用捕获。您需要按值捕获 feed
参数,因为在您的 lambda 执行时堆栈帧早已消失。
更大的问题是客户不知道他们何时可以检索结果,因为您不提供该信息。 (我看到您创建了一个未使用的 Win32 Event 对象,所以可能还有一些其他代码可以使您删除的代码起作用)。
过去几周我一直在 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 方法中,当我尝试将提要参数设置为检索到的提要时,我遇到了访问冲突。显然我知道内存不好,但我理解 COM 属性的方式,它们本质上是函数调用,属性 方法和 GetFeed 方法在做完全相同的事情,减去检索部分。
这是我的问题:
- COM 属性 方法和常规接口方法在预计 return 值方面有何区别(如果有)?
- 为什么 属性 方法的参数初始化为 nullptr 和 GetFeed 方法的参数不是在 IDL 中描述的完全相同?
- 如果 属性 方法中的 out 参数被初始化,那么 COM 运行time 的哪一部分正在为我做这件事并且是可控的? IE 有没有办法让我可以写入的内存传递给我?
我知道我可能会设计掉它,但这不是重点。我只是想了解它是如何工作的。
谢谢。
在您的 lambda 中,您使用 [&]
通过引用捕获。您需要按值捕获 feed
参数,因为在您的 lambda 执行时堆栈帧早已消失。
更大的问题是客户不知道他们何时可以检索结果,因为您不提供该信息。 (我看到您创建了一个未使用的 Win32 Event 对象,所以可能还有一些其他代码可以使您删除的代码起作用)。