gpt4 book ai didi

c++ - 为什么在 IUserNotificationCallback COM 对象上查询 IMarshall 接口(interface)?

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:01:56 25 4
gpt4 key购买 nike

使用 Microsoft 的 IUserNotification2

我正在使用 IUserNotification2向软件用户显示通知。

我使用 Microsoft 的现有实现,请参见此处。 (请注意,我删除了标准 header 并进行了一些简化)。

#include <Shobjidl.h> //IUserNotification2 interface header

void NotifyUser(const std::wstring &title,
const std::wstring &text){
if (!SUCCEEDED(CoInitializeEx(nullptr, COINIT_MULTITHREADED)))
throw std::exception("could not init COM");

IUserNotification2 * handleNotification = nullptr;
auto result = CoCreateInstance(CLSID_UserNotification, 0, CLSCTX_ALL, IID_IUserNotification2, (void**)&handleNotification);
if (!SUCCEEDED(result) || !handleNotification) {
throw std::exception("could not create CLSID_UserNotification");
}
DWORD notif_flags = NIIF_RESPECT_QUIET_TIME|NIIF_WARNING;
result = handleNotification->SetBalloonInfo(title.c_str(), text.c_str(), notif_flags);
if (!SUCCEEDED(result))
throw std::exception("could not SetBalloonInfo of notification");
if (!SUCCEEDED(handleNotification->Show(nullptr, 5000,nullptr))
throw std::exception("failed Show of notification");

在没有回调的情况下执行此操作(即显示一条消息,但对点击事件没有任何操作)我没有问题,我的代码可以正常工作。

添加点击事件回调

为了添加这样的回调,需要传递一个IUserNotificationCallback。反对 Show IUserNotification2 对象的方法。

看这里,我只更改了对 Show 的调用。

Callback cbk;
if (!SUCCEEDED(handleNotification->Show(nullptr, 5000,& cbk)))
throw std::exception("failed Show of notification");

Callback 类实现了 IUserNotificationCallback。请参阅下面的类的实现。

class Callback : public IUserNotificationCallback {
public:
virtual HRESULT STDMETHODCALLTYPE OnBalloonUserClick(POINT * pt) override {return S_OK;}
virtual HRESULT STDMETHODCALLTYPE OnContextMenu(POINT * pt) override {}
virtual HRESULT STDMETHODCALLTYPE OnLeftClick(POINT * pt) override {return S_OK;}

/// Implementing IUnknown Interface
virtual ULONG STDMETHODCALLTYPE AddRef()override { return 1; }
virtual ULONG STDMETHODCALLTYPE Release() override { return 0; }
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID inRiid, void ** outAddressOfObjectPointer)override {
if (outAddressOfObjectPointer) {
if (inRiid == IID_IUnknown || inRiid == IID_IUserNotificationCallback)
{
*outAddressOfObjectPointer = this;
AddRef();
return NOERROR;
}
}
*outAddressOfObjectPointer = nullptr;
return E_NOINTERFACE;
}
};

现在的问题,

是不是当我调用Show方法时,我的IUserNotificationCallback 对象在IUnknown 的QueryInterface 上被调用?界面。采用经典的 COM 风格。但是我收到了 IID_IMarshall 的查询,我通过添加检查了它

else if (inRiid == IID_IMarshal) {
printf("interface queried is IMarshall\n");

在查询接口(interface)方法中。

但是为什么我应该收到这个,文档中没有任何地方提到我应该回答这个 IID。在这种情况下,我让 E_NOINTERFACE 在 void** 参数中返回一个 nullptr。

我这会导致显示方法失败。

注意

我读了notifu的代码看看是否有帮助,但它与我的基本相同。

解决方案

显然 Roman R. 提供了一个可行的解决方案.将对 CoInitializeEx 的调用更改为 if (!SUCCEEDED(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED))) 使其有效!

再次感谢

最佳答案

nowhere in the documentation it is mentionned that I should answer to this IID

可能会查询任何 COM 对象以获取对象未知的接口(interface)。这是正常的,更重要的是,COM 对象必须正确响应此操作,然后任何 COM 对象都必须实现 IUnknown 和此方法。

所以你基本上应该将 *ppvObject 设置为 NULL 并返回 E_NOINTERFACE 如果你没有实现接口(interface),否则返回 S_OK 并使用有效指针初始化 *ppvObject,一旦调用者不再需要该指针,就为 IUnknown::Release 调用做好准备。

你的解决方案

Apparently the solution (suggested by a friend) is too always give back the this pointer even when returning E_NOINTERFACE.

因此是不正确的。如果调用者提供了一个由智能指针管理的变量,然后无论如何都试图释放它,那么有时也可能非常危险。这对于标准编码 OS 代码来说不太可能,因为后者更愿意立即丢弃该值。

如果你这样做,你的实现将是正确的

*outAddressOfObjectPointer = NULL;
if (inRiid == IID_IUnknown)
{
printf("interface required is IUnknown\n");
*outAddressOfObjectPointer = this;
AddRef();
return NOERROR;
}
// ...

NULLnullptr 不会在此处导致失败。但是,您的代码在其他方面也很危险:COM 初始化、Release 调用中的零返回以及本地堆栈支持的回调类实例,该实例在超出范围时被销毁,但稍后仍可能通过公开的接口(interface)调用指针。

现在回到最初的问题,编码在这里到底做了什么?您正在初始化 MTA 线程,并在那里创建单元线程 COM 对象 CLSID_UserNotification。 COM 在侧 STA 线程中为您创建通知 API,然后它尝试将您的回调传递到那里以匹配线程。它必须询问您的 COM 对象是它自己进行编码(marshal)处理,还是需要提供这个东西。您的对象必须说它不会自行编码并且对此一无所知。这就是正在发生的事情。使其成为 COINIT_APARTMENTTHREADED,您将看到不同的画面。

关于c++ - 为什么在 IUserNotificationCallback COM 对象上查询 IMarshall 接口(interface)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28166791/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com