1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef mozilla_widget_WinUtils_h__
7 #define mozilla_widget_WinUtils_h__
14 #include <unordered_map>
17 // Undo the windows.h damage
22 #undef RemoveDirectory
28 #include "nsIRunnable.h"
29 #include "nsICryptoHash.h"
31 # include "nsIFaviconService.h"
33 #include "nsIDownloader.h"
35 #include "nsIWidget.h"
36 #include "nsIThread.h"
38 #include "mozilla/Attributes.h"
39 #include "mozilla/EventForwards.h"
40 #include "mozilla/HalScreenConfiguration.h"
41 #include "mozilla/HashTable.h"
42 #include "mozilla/LazyIdleThread.h"
43 #include "mozilla/UniquePtr.h"
44 #include "mozilla/Vector.h"
45 #include "mozilla/WindowsDpiAwareness.h"
46 #include "mozilla/WindowsProcessMitigations.h"
47 #include "mozilla/gfx/2D.h"
50 * NS_INLINE_DECL_IUNKNOWN_REFCOUNTING should be used for defining and
51 * implementing AddRef() and Release() of IUnknown interface.
52 * This depends on xpcom/base/nsISupportsImpl.h.
55 #define NS_INLINE_DECL_IUNKNOWN_REFCOUNTING(_class) \
57 STDMETHODIMP_(ULONG) AddRef() { \
58 MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
59 MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
60 NS_ASSERT_OWNINGTHREAD(_class); \
62 NS_LOG_ADDREF(this, mRefCnt, #_class, sizeof(*this)); \
63 return static_cast<ULONG>(mRefCnt.get()); \
65 STDMETHODIMP_(ULONG) Release() { \
66 MOZ_ASSERT(int32_t(mRefCnt) > 0, \
67 "Release called on object that has already been released!"); \
68 NS_ASSERT_OWNINGTHREAD(_class); \
70 NS_LOG_RELEASE(this, mRefCnt, #_class); \
72 NS_ASSERT_OWNINGTHREAD(_class); \
73 mRefCnt = 1; /* stabilize */ \
77 return static_cast<ULONG>(mRefCnt.get()); \
81 nsAutoRefCnt mRefCnt; \
82 NS_DECL_OWNINGTHREAD \
89 enum class PointerCapabilities
: uint8_t;
90 #if defined(ACCESSIBILITY)
92 class LocalAccessible
;
94 #endif // defined(ACCESSIBILITY)
96 // Helper function: enumerate all the toplevel HWNDs attached to the current
97 // thread via ::EnumThreadWindows().
99 // Note that this use of ::EnumThreadWindows() is, unfortunately, not an
100 // abstract implementation detail.
101 template <typename F
>
102 void EnumerateThreadWindows(F
&& f
)
103 // requires requires(F f, HWND h) { f(h); }
108 explicit Impl(F
&& f
) : f(std::forward
<F
>(f
)) {}
111 WNDENUMPROC proc
= &Impl::Callback
;
112 ::EnumThreadWindows(::GetCurrentThreadId(), proc
,
113 reinterpret_cast<LPARAM
>(&f
));
117 static BOOL CALLBACK
Callback(HWND hwnd
, LPARAM lp
) {
118 (*reinterpret_cast<F
*>(lp
))(hwnd
);
123 Impl(std::forward
<F
>(f
)).invoke();
128 // More complete QS definitions for MsgWaitForMultipleObjects() and
129 // GetQueueStatus() that include newer win8 specific defines.
132 # define QS_RAWINPUT 0x0400
136 # define QS_TOUCH 0x0800
137 # define QS_POINTER 0x1000
140 #define MOZ_QS_ALLEVENT \
141 (QS_KEY | QS_MOUSEMOVE | QS_MOUSEBUTTON | QS_POSTMESSAGE | QS_TIMER | \
142 QS_PAINT | QS_SENDMESSAGE | QS_HOTKEY | QS_ALLPOSTMESSAGE | QS_RAWINPUT | \
143 QS_TOUCH | QS_POINTER)
146 #define LogFunction() mozilla::widget::WinUtils::Log(__FUNCTION__)
147 #define LogThread() \
148 mozilla::widget::WinUtils::Log("%s: IsMainThread:%d ThreadId:%X", \
149 __FUNCTION__, NS_IsMainThread(), \
150 GetCurrentThreadId())
151 #define LogThis() mozilla::widget::WinUtils::Log("[%X] %s", this, __FUNCTION__)
152 #define LogException(e) \
153 mozilla::widget::WinUtils::Log("%s Exception:%s", __FUNCTION__, \
154 e->ToString()->Data())
155 #define LogHRESULT(hr) \
156 mozilla::widget::WinUtils::Log("%s hr=%X", __FUNCTION__, hr)
159 class myDownloadObserver final
: public nsIDownloadObserver
{
160 ~myDownloadObserver() {}
164 NS_DECL_NSIDOWNLOADOBSERVER
169 // Function pointers for APIs that may not be available depending on
170 // the Win10 update version -- will be set up in Initialize().
171 static SetThreadDpiAwarenessContextProc sSetThreadDpiAwarenessContext
;
172 static EnableNonClientDpiScalingProc sEnableNonClientDpiScaling
;
173 static GetSystemMetricsForDpiProc sGetSystemMetricsForDpi
;
175 // Set on Initialize().
176 static bool sHasPackageIdentity
;
179 class AutoSystemDpiAware
{
181 AutoSystemDpiAware() {
182 MOZ_DIAGNOSTIC_ASSERT(!IsWin32kLockedDown());
184 if (sSetThreadDpiAwarenessContext
) {
186 sSetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_SYSTEM_AWARE
);
190 ~AutoSystemDpiAware() {
191 if (sSetThreadDpiAwarenessContext
) {
192 sSetThreadDpiAwarenessContext(mPrevContext
);
197 DPI_AWARENESS_CONTEXT mPrevContext
;
200 // Wrapper for DefWindowProc that will enable non-client dpi scaling on the
201 // window during creation.
202 static LRESULT WINAPI
NonClientDpiScalingDefWindowProcW(HWND hWnd
, UINT msg
,
207 * Get the system's default logical-to-physical DPI scaling factor,
208 * which is based on the primary display. Note however that unlike
209 * LogToPhysFactor(GetPrimaryMonitor()), this will not change during
210 * a session even if the displays are reconfigured. This scale factor
211 * is used by Windows theme metrics etc, which do not fully support
212 * dynamic resolution changes but are only updated on logout.
214 static double SystemScaleFactor();
216 static bool IsPerMonitorDPIAware();
218 * Get the DPI of the given monitor if it's per-monitor DPI aware, otherwise
219 * return the system DPI.
221 static float MonitorDPI(HMONITOR aMonitor
);
222 static float SystemDPI();
224 * Functions to convert between logical pixels as used by most Windows APIs
225 * and physical (device) pixels.
227 static double LogToPhysFactor(HMONITOR aMonitor
);
228 static double LogToPhysFactor(HWND aWnd
);
229 static double LogToPhysFactor(HDC aDC
) {
230 return LogToPhysFactor(::WindowFromDC(aDC
));
232 static int32_t LogToPhys(HMONITOR aMonitor
, double aValue
);
233 static HMONITOR
GetPrimaryMonitor();
234 static HMONITOR
MonitorFromRect(const gfx::Rect
& rect
);
236 static bool HasSystemMetricsForDpi();
237 static int GetSystemMetricsForDpi(int nIndex
, UINT dpi
);
240 * @param msg Windows event message
241 * @return User-friendly event name, or nullptr if no
244 static const char* WinEventToEventName(UINT msg
);
247 * @param aHdc HDC for printer
248 * @return unwritable margins for currently set page on aHdc or empty margins
251 static gfx::MarginDouble
GetUnwriteableMarginsForDeviceInInches(HDC aHdc
);
253 static bool HasPackageIdentity() { return sHasPackageIdentity
; }
256 * The "family name" of a Windows app package is the full name without any of
257 * the components that might change during the life cycle of the app (such as
258 * the version number, or the architecture). This leaves only those properties
259 * which together serve to uniquely identify the app within one Windows
260 * installation, namely the base name and the publisher name. Meaning, this
261 * string is safe to use anywhere that a string uniquely identifying an app
262 * installation is called for (because multiple copies of the same app on the
263 * same system is not a supported feature in the app framework).
265 static nsString
GetPackageFamilyName();
268 * Logging helpers that dump output to prlog module 'Widget', console, and
269 * OutputDebugString. Note these output in both debug and release builds.
271 static void Log(const char* fmt
, ...);
272 static void LogW(const wchar_t* fmt
, ...);
275 * PeekMessage() and GetMessage() are wrapper methods for PeekMessageW(),
276 * GetMessageW(), ITfMessageMgr::PeekMessageW() and
277 * ITfMessageMgr::GetMessageW().
278 * Don't call the native APIs directly. You MUST use these methods instead.
280 static bool PeekMessage(LPMSG aMsg
, HWND aWnd
, UINT aFirstMessage
,
281 UINT aLastMessage
, UINT aOption
);
282 static bool GetMessage(LPMSG aMsg
, HWND aWnd
, UINT aFirstMessage
,
286 * Wait until a message is ready to be processed.
287 * Prefer using this method to directly calling ::WaitMessage since
288 * ::WaitMessage will wait if there is an unread message in the queue.
289 * That can cause freezes until another message enters the queue if the
290 * message is marked read by a call to PeekMessage which the caller is
291 * not aware of (e.g., from a different thread).
292 * Note that this method may cause sync dispatch of sent (as opposed to
294 * @param aTimeoutMs Timeout for waiting in ms, defaults to INFINITE
296 static void WaitForMessage(DWORD aTimeoutMs
= INFINITE
);
299 * Gets the value of a string-typed registry value.
301 * @param aRoot The registry root to search in.
302 * @param aKeyName The name of the registry key to open.
303 * @param aValueName The name of the registry value in the specified key whose
304 * value is to be retrieved. Can be null, to retrieve the key's unnamed/
306 * @param aBuffer The buffer into which to store the string value. Can be
307 * null, in which case the return value indicates just whether the value
309 * @param aBufferLength The size of aBuffer, in bytes.
310 * @return Whether the value exists and is a string.
312 static bool GetRegistryKey(HKEY aRoot
, char16ptr_t aKeyName
,
313 char16ptr_t aValueName
, wchar_t* aBuffer
,
314 DWORD aBufferLength
);
317 * Checks whether the registry key exists in either 32bit or 64bit branch on
320 * @param aRoot The registry root of aName.
321 * @param aKeyName The name of the registry key to check.
322 * @return TRUE if it exists and is readable. Otherwise, FALSE.
324 static bool HasRegistryKey(HKEY aRoot
, char16ptr_t aKeyName
);
327 * GetTopLevelHWND() returns a window handle of the top level window which
328 * aWnd belongs to. Note that the result may not be our window, i.e., it
329 * may not be managed by nsWindow.
331 * See follwing table for the detail of the result window type.
333 * +-------------------------+-----------------------------------------------+
334 * | | aStopIfNotPopup |
335 * +-------------------------+-----------------------+-----------------------+
337 + +-----------------+-------+-----------------------+-----------------------+
338 * | | | * an independent top level window |
339 * | | TRUE | * a pupup window (WS_POPUP) |
340 * | | | * an owned top level window (like dialog) |
341 * | aStopIfNotChild +-------+-----------------------+-----------------------+
342 * | | | * independent window | * only an independent |
343 * | | FALSE | * non-popup-owned- | top level window |
344 * | | | window like dialog | |
345 * +-----------------+-------+-----------------------+-----------------------+
347 static HWND
GetTopLevelHWND(HWND aWnd
, bool aStopIfNotChild
= false,
348 bool aStopIfNotPopup
= true);
351 * SetNSWindowPtr() associates aWindow with aWnd. If aWidget is nullptr, it
352 * instead dissociates any nsWindow from aWnd.
354 * No AddRef is performed. May not be used off of the main thread.
356 static void SetNSWindowPtr(HWND aWnd
, nsWindow
* aWindow
);
358 * GetNSWindowPtr() returns a pointer to the associated nsWindow pointer, if
359 * one exists, or nullptr, if not.
361 * No AddRef is performed. May not be used off of the main thread.
363 static nsWindow
* GetNSWindowPtr(HWND aWnd
);
366 * IsOurProcessWindow() returns TRUE if aWnd belongs our process.
369 static bool IsOurProcessWindow(HWND aWnd
);
372 * FindOurProcessWindow() returns the nearest ancestor window which
373 * belongs to our process. If it fails to find our process's window by the
374 * top level window, returns nullptr. And note that this is using
375 * ::GetParent() for climbing the window hierarchy, therefore, it gives
376 * up at an owned top level window except popup window (e.g., dialog).
378 static HWND
FindOurProcessWindow(HWND aWnd
);
381 * FindOurWindowAtPoint() returns the topmost child window which belongs to
382 * our process's top level window.
384 * NOTE: the topmost child window may NOT be our process's window like a
387 static HWND
FindOurWindowAtPoint(const POINT
& aPointInScreen
);
390 * InitMSG() returns an MSG struct which was initialized by the params.
391 * Don't trust the other members in the result.
393 static MSG
InitMSG(UINT aMessage
, WPARAM wParam
, LPARAM lParam
, HWND aWnd
);
396 * GetScanCode() returns a scan code for the LPARAM of WM_KEYDOWN, WM_KEYUP,
397 * WM_CHAR and WM_UNICHAR.
400 static WORD
GetScanCode(LPARAM aLParam
) { return (aLParam
>> 16) & 0xFF; }
403 * IsExtendedScanCode() returns TRUE if the LPARAM indicates the key message
404 * is an extended key event.
406 static bool IsExtendedScanCode(LPARAM aLParam
) {
407 return (aLParam
& 0x1000000) != 0;
411 * GetInternalMessage() converts a native message to an internal message.
412 * If there is no internal message for the given native message, returns
413 * the native message itself.
415 static UINT
GetInternalMessage(UINT aNativeMessage
);
418 * GetNativeMessage() converts an internal message to a native message.
419 * If aInternalMessage is a native message, returns the native message itself.
421 static UINT
GetNativeMessage(UINT aInternalMessage
);
424 * GetMouseInputSource() returns a pointing device information. The value is
425 * one of MouseEvent_Binding::MOZ_SOURCE_*. This method MUST be called during
426 * mouse message handling.
428 static uint16_t GetMouseInputSource();
431 * Windows also fires mouse window messages for pens and touches, so we should
432 * retrieve their pointer ID on receiving mouse events as well. Please refer
434 * https://msdn.microsoft.com/en-us/library/windows/desktop/ms703320(v=vs.85).aspx
436 static uint16_t GetMousePointerID();
438 static bool GetIsMouseFromTouch(EventMessage aEventType
);
441 * ConvertHRGNToRegion converts a Windows HRGN to an LayoutDeviceIntRegion.
443 * aRgn the HRGN to convert.
444 * returns the LayoutDeviceIntRegion.
446 static LayoutDeviceIntRegion
ConvertHRGNToRegion(HRGN aRgn
);
449 * ToIntRect converts a Windows RECT to a LayoutDeviceIntRect.
451 * aRect the RECT to convert.
452 * returns the LayoutDeviceIntRect.
454 static LayoutDeviceIntRect
ToIntRect(const RECT
& aRect
);
457 * Returns true if the context or IME state is enabled. Otherwise, false.
459 static bool IsIMEEnabled(const InputContext
& aInputContext
);
460 static bool IsIMEEnabled(IMEEnabled aIMEState
);
463 * Returns modifier key array for aModifiers. This is for
464 * nsIWidget::SynthethizeNative*Event().
466 static void SetupKeyModifiersSequence(nsTArray
<KeyPair
>* aArray
,
467 uint32_t aModifiers
, UINT aMessage
);
470 * Does device have touch support
472 static uint32_t IsTouchDeviceSupportPresent();
475 * The maximum number of simultaneous touch contacts supported by the device.
476 * In the case of devices with multiple digitizers (e.g. multiple touch
477 * screens), the value will be the maximum of the set of maximum supported
478 * contacts by each individual digitizer.
480 static uint32_t GetMaxTouchPoints();
483 * Returns the windows power platform role, which is useful for detecting
486 static POWER_PLATFORM_ROLE
GetPowerPlatformRole();
488 // For pointer and hover media queries features.
489 static PointerCapabilities
GetPrimaryPointerCapabilities();
490 // For any-pointer and any-hover media queries features.
491 static PointerCapabilities
GetAllPointerCapabilities();
492 // Returns a string containing a comma-separated list of Fluent IDs
493 // representing the currently active pointing devices
494 static void GetPointerExplanation(nsAString
* aExplanation
);
497 * Fully resolves a path to its final path name. So if path contains
498 * junction points or symlinks to other folders, we'll resolve the path
499 * fully to the actual path that the links target.
501 * @param aPath path to be resolved.
502 * @return true if successful, including if nothing needs to be changed.
503 * false if something failed or aPath does not exist, aPath will
506 static bool ResolveJunctionPointsAndSymLinks(std::wstring
& aPath
);
507 static bool ResolveJunctionPointsAndSymLinks(nsIFile
* aPath
);
510 * Returns true if executable's path is on a network drive.
512 static bool RunningFromANetworkDrive();
514 static void Initialize();
516 static nsresult
WriteBitmap(nsIFile
* aFile
,
517 mozilla::gfx::SourceSurface
* surface
);
518 // This function is a helper, but it cannot be called from the main thread.
519 // Use the one above!
520 static nsresult
WriteBitmap(nsIFile
* aFile
, imgIContainer
* aImage
);
523 * Wrapper for PathCanonicalize().
524 * Upon success, the resulting output string length is <= MAX_PATH.
525 * @param aPath [in,out] The path to transform.
526 * @return true on success, false on failure.
528 static bool CanonicalizePath(nsAString
& aPath
);
531 * Converts short paths (e.g. "C:\\PROGRA~1\\XYZ") to full paths.
532 * Upon success, the resulting output string length is <= MAX_PATH.
533 * @param aPath [in,out] The path to transform.
534 * @return true on success, false on failure.
536 static bool MakeLongPath(nsAString
& aPath
);
539 * Wrapper for PathUnExpandEnvStringsW().
540 * Upon success, the resulting output string length is <= MAX_PATH.
541 * @param aPath [in,out] The path to transform.
542 * @return true on success, false on failure.
544 static bool UnexpandEnvVars(nsAString
& aPath
);
547 * Retrieve a semicolon-delimited list of DLL files derived from AppInit_DLLs
549 static bool GetAppInitDLLs(nsAString
& aOutput
);
551 enum class PathTransformFlags
: uint32_t {
557 Default
= 7, // Default omits RequireFilePath
561 * Given a path, transforms it in preparation to be reported via telemetry.
562 * That can include canonicalization, converting short to long paths,
563 * unexpanding environment strings, and removing potentially sensitive data
566 * @param aPath [in,out] The path to transform.
567 * @param aFlags [in] Specifies which transformations to perform, allowing
568 * the caller to skip operations they know have already been
570 * @return true on success, false on failure.
572 static bool PreparePathForTelemetry(
574 PathTransformFlags aFlags
= PathTransformFlags::Default
);
576 static const size_t kMaxWhitelistedItems
= 3;
578 Vector
<std::pair
<nsString
, nsDependentString
>, kMaxWhitelistedItems
>;
580 static const WhitelistVec
& GetWhitelistedPaths();
582 static bool GetClassName(HWND aHwnd
, nsAString
& aName
);
584 static void EnableWindowOcclusion(const bool aEnable
);
586 static bool GetTimezoneName(wchar_t* aBuffer
);
589 static nsresult
SetHiDPIMode(bool aHiDPI
);
590 static nsresult
RestoreHiDPIMode();
593 static bool GetAutoRotationState(AR_STATE
* aRotationState
);
595 static void GetClipboardFormatAsString(UINT aFormat
, nsAString
& aOutput
);
598 static WhitelistVec
BuildWhitelist();
602 static a11y::LocalAccessible
* GetRootAccessibleForHWND(HWND aHwnd
);
607 class AsyncFaviconDataReady final
: public nsIFaviconDataCallback
{
610 NS_DECL_NSIFAVICONDATACALLBACK
612 AsyncFaviconDataReady(nsIURI
* aNewURI
, RefPtr
<LazyIdleThread
>& aIOThread
,
613 const bool aURLShortcut
,
614 already_AddRefed
<nsIRunnable
> aRunnable
);
615 nsresult
OnFaviconDataNotAvailable(void);
618 ~AsyncFaviconDataReady() {}
620 nsCOMPtr
<nsIURI
> mNewURI
;
621 RefPtr
<LazyIdleThread
> mIOThread
;
622 nsCOMPtr
<nsIRunnable
> mRunnable
;
623 const bool mURLShortcut
;
628 * Asynchronously tries add the list to the build
630 class AsyncEncodeAndWriteIcon
: public nsIRunnable
{
632 NS_DECL_THREADSAFE_ISUPPORTS
635 // Warning: AsyncEncodeAndWriteIcon assumes ownership of the aData buffer
637 AsyncEncodeAndWriteIcon(const nsAString
& aIconPath
,
638 UniquePtr
<uint8_t[]> aData
, uint32_t aStride
,
639 uint32_t aWidth
, uint32_t aHeight
,
640 already_AddRefed
<nsIRunnable
> aRunnable
);
643 virtual ~AsyncEncodeAndWriteIcon();
645 nsAutoString mIconPath
;
646 UniquePtr
<uint8_t[]> mBuffer
;
647 nsCOMPtr
<nsIRunnable
> mRunnable
;
653 class AsyncDeleteAllFaviconsFromDisk
: public nsIRunnable
{
655 NS_DECL_THREADSAFE_ISUPPORTS
658 explicit AsyncDeleteAllFaviconsFromDisk(bool aIgnoreRecent
= false);
661 virtual ~AsyncDeleteAllFaviconsFromDisk();
663 int32_t mIcoNoDeleteSeconds
;
665 nsCOMPtr
<nsIFile
> mJumpListCacheDir
;
668 class FaviconHelper
{
670 static const char kJumpListCacheDir
[];
671 static const char kShortcutCacheDir
[];
672 static nsresult
ObtainCachedIconFile(
673 nsCOMPtr
<nsIURI
> aFaviconPageURI
, nsString
& aICOFilePath
,
674 RefPtr
<LazyIdleThread
>& aIOThread
, bool aURLShortcut
,
675 already_AddRefed
<nsIRunnable
> aRunnable
= nullptr);
677 static nsresult
HashURI(nsCOMPtr
<nsICryptoHash
>& aCryptoHash
, nsIURI
* aUri
,
678 nsACString
& aUriHash
);
680 static nsresult
GetOutputIconPath(nsCOMPtr
<nsIURI
> aFaviconPageURI
,
681 nsCOMPtr
<nsIFile
>& aICOFile
,
684 static nsresult
CacheIconFileFromFaviconURIAsync(
685 nsCOMPtr
<nsIURI
> aFaviconPageURI
, nsCOMPtr
<nsIFile
> aICOFile
,
686 RefPtr
<LazyIdleThread
>& aIOThread
, bool aURLShortcut
,
687 already_AddRefed
<nsIRunnable
> aRunnable
);
689 static int32_t GetICOCacheSecondsTimeout();
692 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(WinUtils::PathTransformFlags
);
694 // RTL shim windows are temporary child windows of our nsWindows created to
695 // address RTL issues in picker dialogs. (See bug 588735.)
696 class MOZ_STACK_CLASS ScopedRtlShimWindow
{
698 explicit ScopedRtlShimWindow(nsIWidget
* aParent
);
699 ~ScopedRtlShimWindow();
701 ScopedRtlShimWindow(const ScopedRtlShimWindow
&) = delete;
702 ScopedRtlShimWindow(ScopedRtlShimWindow
&&) = delete;
704 HWND
get() const { return mWnd
; }
710 } // namespace widget
711 } // namespace mozilla
713 #endif // mozilla_widget_WinUtils_h__