summaryrefslogtreecommitdiffstats
path: root/widget/windows/ToastNotificationHeaderOnlyUtils.h
diff options
context:
space:
mode:
Diffstat (limited to 'widget/windows/ToastNotificationHeaderOnlyUtils.h')
-rw-r--r--widget/windows/ToastNotificationHeaderOnlyUtils.h157
1 files changed, 157 insertions, 0 deletions
diff --git a/widget/windows/ToastNotificationHeaderOnlyUtils.h b/widget/windows/ToastNotificationHeaderOnlyUtils.h
new file mode 100644
index 0000000000..533d5bec00
--- /dev/null
+++ b/widget/windows/ToastNotificationHeaderOnlyUtils.h
@@ -0,0 +1,157 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_ToastNotificationHeaderOnlyUtils_h
+#define mozilla_ToastNotificationHeaderOnlyUtils_h
+
+/**
+ * This header is intended for self-contained, header-only, utility code to
+ * share between Windows toast notification code in firefox.exe and
+ * notificationserver.dll.
+ */
+
+// Use XPCOM logging if we're in a XUL context, otherwise use Windows Event
+// logging.
+// NOTE: The `printf` `format` equivalent argument to `NOTIFY_LOG` is converted
+// to a wide string when outside of a XUL context. String format specifiers need
+// to specify they're a wide string with `%ls` or narrow string with `%hs`.
+#include "mozilla/Logging.h"
+#ifdef IMPL_LIBXUL
+namespace mozilla::widget {
+extern LazyLogModule sWASLog;
+} // namespace mozilla::widget
+# define NOTIFY_LOG(_level, _args) \
+ MOZ_LOG(mozilla::widget::sWASLog, _level, _args)
+#else
+# include "mozilla/WindowsEventLog.h"
+
+bool gVerbose = false;
+
+# define NOTIFY_LOG(_level, _args) \
+ if (gVerbose || _level == mozilla::LogLevel::Error) { \
+ POST_EXPAND_NOTIFY_LOG(MOZ_LOG_EXPAND_ARGS _args); \
+ }
+# define POST_EXPAND_NOTIFY_LOG(...) \
+ MOZ_WIN_EVENT_LOG_ERROR_MESSAGE( \
+ L"" MOZ_APP_DISPLAYNAME " Notification Server", L"" __VA_ARGS__)
+#endif
+
+#include <functional>
+#include <string>
+
+#include "nsWindowsHelpers.h"
+
+namespace mozilla::widget::toastnotification {
+
+const wchar_t kLaunchArgProgram[] = L"program";
+const wchar_t kLaunchArgProfile[] = L"profile";
+const wchar_t kLaunchArgUrl[] = L"launchUrl";
+const wchar_t kLaunchArgPrivilegedName[] = L"privilegedName";
+const wchar_t kLaunchArgTag[] = L"windowsTag";
+const wchar_t kLaunchArgLogging[] = L"logging";
+const wchar_t kLaunchArgAction[] = L"action";
+
+const DWORD kNotificationServerTimeoutMs = (10 * 1000);
+
+struct ToastNotificationPidMessage {
+ DWORD pid = 0;
+};
+
+struct ToastNotificationPermissionMessage {
+ DWORD setForegroundPermissionGranted = 0;
+};
+
+inline std::wstring GetNotificationPipeName(const wchar_t* aTag) {
+ // Prefix required by pipe API.
+ std::wstring pipeName(LR"(\\.\pipe\)");
+
+ pipeName += L"" MOZ_APP_NAME;
+ pipeName += aTag;
+
+ return pipeName;
+}
+
+inline bool WaitEventWithTimeout(const HANDLE& event) {
+ DWORD result = WaitForSingleObject(event, kNotificationServerTimeoutMs);
+
+ switch (result) {
+ case WAIT_OBJECT_0:
+ NOTIFY_LOG(LogLevel::Info, ("Pipe wait signaled"));
+ return true;
+ case WAIT_TIMEOUT:
+ NOTIFY_LOG(LogLevel::Warning, ("Pipe wait timed out"));
+ return false;
+ case WAIT_FAILED:
+ NOTIFY_LOG(LogLevel::Error,
+ ("Pipe wait failed, error %lu", GetLastError()));
+ return false;
+ case WAIT_ABANDONED:
+ NOTIFY_LOG(LogLevel::Error, ("Pipe wait abandoned"));
+ return false;
+ default:
+ NOTIFY_LOG(LogLevel::Error, ("Pipe wait unknown error"));
+ return false;
+ }
+}
+
+/* Handles running overlapped transactions for a Windows pipe. This function
+ * manages lifetimes of Event and OVERLAPPED objects to ensure they are not used
+ * while an overlapped operation is pending. */
+inline bool SyncDoOverlappedIOWithTimeout(
+ const nsAutoHandle& pipe, const size_t bytesExpected,
+ const std::function<BOOL(OVERLAPPED&)>& transactPipe) {
+ nsAutoHandle event(CreateEventW(nullptr, TRUE, FALSE, nullptr));
+ if (!event) {
+ NOTIFY_LOG(
+ LogLevel::Error,
+ ("Error creating pipe transaction event, error %lu", GetLastError()));
+ return false;
+ }
+
+ OVERLAPPED overlapped{};
+ overlapped.hEvent = event.get();
+ BOOL result = transactPipe(overlapped);
+
+ if (!result && GetLastError() != ERROR_IO_PENDING) {
+ NOTIFY_LOG(LogLevel::Error,
+ ("Error reading from pipe, error %lu", GetLastError()));
+ return false;
+ }
+
+ if (!WaitEventWithTimeout(overlapped.hEvent)) {
+ NOTIFY_LOG(LogLevel::Warning, ("Pipe transaction timed out, canceling "
+ "(transaction may still succeed)."));
+
+ CancelIo(pipe.get());
+
+ // Transaction may still succeed before cancellation is handled; fall
+ // through to normal handling.
+ }
+
+ DWORD bytesTransferred = 0;
+ // Pipe transfer has either been signaled or cancelled by this point, so it
+ // should be safe to wait on.
+ BOOL overlappedResult =
+ GetOverlappedResult(pipe.get(), &overlapped, &bytesTransferred, TRUE);
+
+ if (!overlappedResult) {
+ NOTIFY_LOG(
+ LogLevel::Error,
+ ("Error retrieving pipe overlapped result, error %lu", GetLastError()));
+ return false;
+ } else if (bytesTransferred != bytesExpected) {
+ NOTIFY_LOG(LogLevel::Error,
+ ("%lu bytes read from pipe, but %zu bytes expected",
+ bytesTransferred, bytesExpected));
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace mozilla::widget::toastnotification
+
+#endif // mozilla_ToastNotificationHeaderOnlyUtils_h