QUESTION:
My simple Windows notification application throws an exception with the error message "Access is denied." How can I fix this?
PREFACE:
The structure in use is prescribed by the current implementation of and constraints placed on our application. While a better structure than this may exist, changing the structure is not an option at this time.
Relevant structural information:
We have a service that always runs. This service will spawn a process--let's call it data.exe--for every active session ID on the machine. For example, if there are currently four sessions active on the server with session IDs 1-4, data.exe will be running for all 4 sessions. Notably, the user name in Task Manager for each process is SYSTEM, despite running in non-zero session IDs.
INFORMATION:
My application--toaster.exe--is supposed to be launched from a different process via CreateProcessW() . The full launch function is adapted from a Raymond Chen blog post found here. As a brief explanation of what this function does, it launches a program with the shell as its parent process. For clarity, I implemented this function into data.exe to launch toaster.exe, and the adaptations I made are simply to handle errors and, obviously, to launch the particular program I want, rather than cmd.exe. Mr. Chen's function was the only method I found that would successfully and reliably launch my application and have it perform as intended.
Currently, if I launch toaster.exe by clicking on it, it performs its functions perfectly. I can also confirm that I am able to launch toaster.exe from another process--I setup a test application that can successfully launch toaster.exe in such a way that it does not throw an exception. To clarify what I mean by "functions perfectly," toaster.exe successfully sends me a simple one-line notification with a message that I have hardcoded for testing purposes.
However, if I launch toaster.exe from a program that was launched by our service, it hits an exception when it attempts to create the winrt::Windows::UI::Notifications::ToastNotification
object. Unfortunately, this last one is the only launch method I care about--this program needs to be compatible with being launched in this way because it will always be launched by data.exe, which, as mentioned in the preface, is launched by our service.
Here is the function in toaster.exe where the exception occurs:
using namespace winrt;
using namespace Windows::Data::Xml::Dom;
using namespace Windows::UI::Notifications;
void SendBasicToast(const std::wstring &strMessage)
{
// Construct the toast template
XmlDocument doc;
doc.LoadXml(L"<toast>\
<visual>\
<binding template=\"ToastGeneric\">\
<text></text>\
</binding>\
</visual>\
</toast>");
// Populate with text and values
doc.SelectSingleNode(L"//text[1]").InnerText(strMessage);
// Construct the notification [THIS LINE CAUSES AN EXCEPTION]
ToastNotification notif{ doc };
// And send it!
DesktopNotificationManagerCompat::CreateToastNotifier().Show(notif);
}
DesktopNotificationManagerCompat.h
comes from this Microsoft repository, which is supplemental material to their local toast notification tutorial. For completeness of information, I will note that DesktopNotificationManagerCompat::CreateToastNotifier()
is a simple wrapper for ToastNotificationManager::CreateToastNotifier()
and is defined as such:
ToastNotifier DesktopNotificationManagerCompat::CreateToastNotifier()
if (HasIdentity())
{
return ToastNotificationManager::CreateToastNotifier();
}
else
{
return ToastNotificationManager::CreateToastNotifier(_win32Aumid);
}
}
I have already tried removing this wrapper function and directly calling CreateToastNotifier()
with my AUMID as a parameter, but this also resulted in an exception being thrown. However, this is not strictly relevant because the exception is thrown on the previous line.
The way I call the toast function:
try
{
std::wstring strMessage{ L"<(^.^<) || Default Toast || (>^.^)>" };
SendBasicToast(strMessage);
}
catch(winrt::hresult_error &e)
{
//Log the exception message
}
The only way toaster.exe will be launched is via data.exe as described in the above paragraph (and if the user clicks it in the notification tray, but that is beyond the scope of this question). As evidenced by this question, however, it does not work as intended in the particular circumstance under which I need it to work. I have diagnosed the issue to a single line (keep in mind I am effectively using namespace winrt::Windows::UI::Notifications
):
ToastNotification notif{ doc };
Thanks to StackOverflow user, IInspectable, suggesting that the exception may have type winrt::hresult_error
, I was able to discern that the error message I am receiving from the ToastNotification
constructor is "Access is denied." Normally, I would expect this to require elevated privileges to resolve, but when I run the program myself, it runs with standard privileges and does so without issue. What access is being denied and how do I attain it?
SO Question page for reference