Backed out changeset 2450366cf7ca (bug 1891629) for causing win msix mochitest failures
[gecko.git] / widget / windows / ToastNotificationHeaderOnlyUtils.h
blobdd777c0c32444807e423d52cad3add28a7e14258
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_ToastNotificationHeaderOnlyUtils_h
8 #define mozilla_ToastNotificationHeaderOnlyUtils_h
10 /**
11 * This header is intended for self-contained, header-only, utility code to
12 * share between Windows toast notification code in firefox.exe and
13 * notificationserver.dll.
16 // Use XPCOM logging if we're in a XUL context, otherwise use Windows Event
17 // logging.
18 // NOTE: The `printf` `format` equivalent argument to `NOTIFY_LOG` is converted
19 // to a wide string when outside of a XUL context. String format specifiers need
20 // to specify they're a wide string with `%ls` or narrow string with `%hs`.
21 #include "mozilla/Logging.h"
22 #ifdef IMPL_LIBXUL
23 namespace mozilla::widget {
24 extern LazyLogModule sWASLog;
25 } // namespace mozilla::widget
26 # define NOTIFY_LOG(_level, _args) \
27 MOZ_LOG(mozilla::widget::sWASLog, _level, _args)
28 #else
29 # include "mozilla/WindowsEventLog.h"
31 bool gVerbose = false;
33 # define NOTIFY_LOG(_level, _args) \
34 if (gVerbose || _level == mozilla::LogLevel::Error) { \
35 POST_EXPAND_NOTIFY_LOG(MOZ_LOG_EXPAND_ARGS _args); \
37 # define POST_EXPAND_NOTIFY_LOG(...) \
38 MOZ_WIN_EVENT_LOG_ERROR_MESSAGE( \
39 L"" MOZ_APP_DISPLAYNAME " Notification Server", L"" __VA_ARGS__)
40 #endif
42 #include <functional>
43 #include <string>
45 #include "nsWindowsHelpers.h"
47 namespace mozilla::widget::toastnotification {
49 const wchar_t kLaunchArgProgram[] = L"program";
50 const wchar_t kLaunchArgProfile[] = L"profile";
51 const wchar_t kLaunchArgTag[] = L"windowsTag";
52 const wchar_t kLaunchArgLogging[] = L"logging";
53 const wchar_t kLaunchArgAction[] = L"action";
55 const DWORD kNotificationServerTimeoutMs = (10 * 1000);
57 struct ToastNotificationPidMessage {
58 DWORD pid = 0;
61 struct ToastNotificationPermissionMessage {
62 DWORD setForegroundPermissionGranted = 0;
65 inline std::wstring GetNotificationPipeName(const wchar_t* aTag) {
66 // Prefix required by pipe API.
67 std::wstring pipeName(LR"(\\.\pipe\)");
69 pipeName += L"" MOZ_APP_NAME;
70 pipeName += aTag;
72 return pipeName;
75 inline bool WaitEventWithTimeout(const HANDLE& event) {
76 DWORD result = WaitForSingleObject(event, kNotificationServerTimeoutMs);
78 switch (result) {
79 case WAIT_OBJECT_0:
80 NOTIFY_LOG(LogLevel::Info, ("Pipe wait signaled"));
81 return true;
82 case WAIT_TIMEOUT:
83 NOTIFY_LOG(LogLevel::Warning, ("Pipe wait timed out"));
84 return false;
85 case WAIT_FAILED:
86 NOTIFY_LOG(LogLevel::Error,
87 ("Pipe wait failed, error %lu", GetLastError()));
88 return false;
89 case WAIT_ABANDONED:
90 NOTIFY_LOG(LogLevel::Error, ("Pipe wait abandoned"));
91 return false;
92 default:
93 NOTIFY_LOG(LogLevel::Error, ("Pipe wait unknown error"));
94 return false;
98 /* Handles running overlapped transactions for a Windows pipe. This function
99 * manages lifetimes of Event and OVERLAPPED objects to ensure they are not used
100 * while an overlapped operation is pending. */
101 inline bool SyncDoOverlappedIOWithTimeout(
102 const nsAutoHandle& pipe, const size_t bytesExpected,
103 const std::function<BOOL(OVERLAPPED&)>& transactPipe) {
104 nsAutoHandle event(CreateEventW(nullptr, TRUE, FALSE, nullptr));
105 if (!event) {
106 NOTIFY_LOG(
107 LogLevel::Error,
108 ("Error creating pipe transaction event, error %lu", GetLastError()));
109 return false;
112 OVERLAPPED overlapped{};
113 overlapped.hEvent = event.get();
114 BOOL result = transactPipe(overlapped);
116 if (!result && GetLastError() != ERROR_IO_PENDING) {
117 NOTIFY_LOG(LogLevel::Error,
118 ("Error reading from pipe, error %lu", GetLastError()));
119 return false;
122 if (!WaitEventWithTimeout(overlapped.hEvent)) {
123 NOTIFY_LOG(LogLevel::Warning, ("Pipe transaction timed out, canceling "
124 "(transaction may still succeed)."));
126 CancelIo(pipe.get());
128 // Transaction may still succeed before cancellation is handled; fall
129 // through to normal handling.
132 DWORD bytesTransferred = 0;
133 // Pipe transfer has either been signaled or cancelled by this point, so it
134 // should be safe to wait on.
135 BOOL overlappedResult =
136 GetOverlappedResult(pipe.get(), &overlapped, &bytesTransferred, TRUE);
138 if (!overlappedResult) {
139 NOTIFY_LOG(
140 LogLevel::Error,
141 ("Error retrieving pipe overlapped result, error %lu", GetLastError()));
142 return false;
143 } else if (bytesTransferred != bytesExpected) {
144 NOTIFY_LOG(LogLevel::Error,
145 ("%lu bytes read from pipe, but %zu bytes expected",
146 bytesTransferred, bytesExpected));
147 return false;
150 return true;
153 } // namespace mozilla::widget::toastnotification
155 #endif // mozilla_ToastNotificationHeaderOnlyUtils_h