【发布时间】:2015-01-27 09:14:59
【问题描述】:
使用 Microsoft 的 IUserNotification2
我正在使用IUserNotification2 向软件用户显示通知。
我使用 microsoft 的现有实现,请参见此处。 (注意,我删除了标准标题并简化了一点)。
#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对象传递给IUserNotification2对象的Show方法。
请看这里,我只更改了对 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");
在查询接口方法中。
但是我为什么要收到这个,文档中没有提到我应该回答这个 IID。 在这种情况下,我让 E_NOINTERFACE 在 void** 参数中返回一个 nullptr。
这会导致显示方法失败。
注意
我看了notifu的代码,看看有没有用,不过和我的基本一样。
解决方案
显然Roman R. 提供了一个可行的解决方案。
将CoInitializeEx 的调用更改为if (!SUCCEEDED(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED))) 即可!
再次感谢您
【问题讨论】:
-
它正在尝试编组公寓 (codeguru.com/cpp/com-tech/activex/apts/article.php/c5529/…) 之间的接口,并且无法使用 typelib 编组器(无论出于何种原因)这样做。看到这个stackoverflow.com/q/1714926/57428我想说你最好的选择是让你的代码在不需要编组的公寓配置中运行。如果您提供有关如何在组件的注册脚本中指定线程模型的更多数据,那么有人可以就此提供进一步的建议。
-
顺便说一句,你怎么称呼
CoInitializeEx()? -
@sharptooth,代码在帖子里:CoInitializeEx(nullptr, COINIT_MULTITHREADED)
-
是的,我现在明白了。如果您在注册表中查找
CLSID_UserNotification,您会看到它的“线程模型”设置为“公寓”。您的代码要求 MTA。如果没有在此配置中编组,您的代码和 COM 服务器之间的调用将无法正常工作。一种选择是要求COINIT_APARTMENTTHREADED。 -
顺便说一句,每次调用该函数时,您的代码都会调用
CoInitializeEx()吗?
标签: c++ winapi com notifications msdn