Use of IUserNotification2 from Microsoft
I'm using IUserNotification2 to show a notification to the software user.
I use the existing implementation from microsoft, see here. (Note, I removed the standard headers and simplified a bit).
#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");
When doing it without callbacks (i,e showing a message with no action on click events) I have no problem and my code works.
Add a callback on click event
In order to add such a callback, it is requested to pass a IUserNotificationCallback
Object to the Show
Method of the IUserNotification2
Object.
See here I changed just the call to Show.
Callback cbk;
if (!SUCCEEDED(handleNotification->Show(nullptr, 5000,& cbk)))
throw std::exception("failed Show of notification");
the Callback
class implements IUserNotificationCallback
. See the implementation of the class below.
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;
}
};
Now the problem,
Is that when I call the Show
method, My IUserNotificationCallback
objects gets called on QueryInterface of the IUnknown
Interface. In a classic COM style. But I received a query for the IID_IMarshall which I checked by adding
else if (inRiid == IID_IMarshal) {
printf("interface queried is IMarshall\n");
In the query interface method.
BUT WHY should I receive this, nowhere in the documentation it is mentionned that I should answer to this IID. In this case, I let E_NOINTERFACE be returned with a nullptr in the void** parameter.
I this generates a fail of the show Method.
note
I read the code of notifu to see if it could help, but it is basically the same than mine.
Solution
Apparently a working solution is provided by Roman R..
Changing the call to CoInitializeEx
to if (!SUCCEEDED(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED)))
makes it works!
Thank you again