Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions source/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,14 @@ class App(wx.App):
def OnAssert(self,file,line,cond,msg):
message="{file}, line {line}:\nassert {cond}: {msg}".format(file=file,line=line,cond=cond,msg=msg)
log.debugWarning(message,codepath="WX Widgets",stack_info=True)

def InitLocale(self):
# Backport of `InitLocale` from wx Python 4.1.2 as the current version tries to set a Python
# locale to an nonexistent one when creating an instance of `wx.App`.
# This causes a crash when running under a particular version of Universal CRT (#12160)
import locale
locale.setlocale(locale.LC_ALL, "C")

app = App(redirect=False)
# We support queryEndSession events, but in general don't do anything for them.
# However, when running as a Windows Store application, we do want to request to be restarted for updates
Expand Down
17 changes: 15 additions & 2 deletions source/logHandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@
import ctypes
import sys
import warnings
from encodings import utf_8
import logging
import inspect
import winsound
import traceback
from types import MethodType, FunctionType
from types import FunctionType
import globalVars
import winKernel
import buildVersion
from typing import Optional

Expand Down Expand Up @@ -288,6 +288,19 @@ class Formatter(logging.Formatter):
def formatException(self, ex):
return stripBasePathFromTracebackText(super(Formatter, self).formatException(ex))

def formatTime(self, record: logging.LogRecord, datefmt: Optional[str] = None) -> str:
"""Custom implementation of `formatTime` which avoids `time.localtime`
since it causes a crash under some versions of Universal CRT ( #12160, Python issue 36792)
"""
timeAsFileTime = winKernel.time_tToFileTime(record.created)
timeAsSystemTime = winKernel.SYSTEMTIME()
winKernel.FileTimeToSystemTime(timeAsFileTime, timeAsSystemTime)
timeAsLocalTime = winKernel.SYSTEMTIME()
winKernel.SystemTimeToTzSpecificLocalTime(None, timeAsSystemTime, timeAsLocalTime)
res = f"{timeAsLocalTime.wHour:02d}:{timeAsLocalTime.wMinute:02d}:{timeAsLocalTime.wSecond:02d}"
return self.default_msec_format % (res, record.msecs)


class StreamRedirector(object):
"""Redirects an output stream to a logger.
"""
Expand Down
75 changes: 65 additions & 10 deletions source/winKernel.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
#winKernel.py
#A part of NonVisual Desktop Access (NVDA)
#Copyright (C) 2006-2019 NV Access Limited, Rui Batista, Aleksey Sadovoy, Peter Vagner, Mozilla Corporation, Babbage B.V., Joseph Lee
#This file is covered by the GNU General Public License.
#See the file COPYING for more details.
# A part of NonVisual Desktop Access (NVDA)
# Copyright (C) 2006-2021 NV Access Limited, Rui Batista, Aleksey Sadovoy, Peter Vagner,
# Mozilla Corporation, Babbage B.V., Joseph Lee, Łukasz Golonka
# This file is covered by the GNU General Public License.
# See the file COPYING for more details.

"""Functions that wrap Windows API functions from kernel32.dll and advapi32.dll"""

from typing import Union
import contextlib
import ctypes
import ctypes.wintypes
from ctypes import WinError
from ctypes import *
from ctypes.wintypes import *
from ctypes import byref, c_byte, POINTER, sizeof, Structure, windll, WinError
from ctypes.wintypes import BOOL, DWORD, HANDLE, LARGE_INTEGER, LPWSTR, LPVOID, WORD

kernel32=ctypes.windll.kernel32
advapi32 = windll.advapi32
Expand Down Expand Up @@ -160,6 +160,63 @@ class SYSTEMTIME(ctypes.Structure):
("wMilliseconds", WORD)
)


class FILETIME(Structure):
_fields_ = (
("dwLowDateTime", DWORD),
("dwHighDateTime", DWORD)
)


class TIME_ZONE_INFORMATION(Structure):
_fields_ = (
("Bias", ctypes.wintypes.LONG),
("StandardName", ctypes.wintypes.WCHAR * 32),
("StandardDate", SYSTEMTIME),
("StandardBias", ctypes.wintypes.LONG),
("DaylightName", ctypes.wintypes.WCHAR * 32),
("DaylightDate", SYSTEMTIME),
("DaylightBias", ctypes.wintypes.LONG)
)


def time_tToFileTime(time_tToConvert: float) -> FILETIME:
"""Converts time_t as returned from `time.time` to a FILETIME structure.
Based on a code snipped from:
https://docs.microsoft.com/en-us/windows/win32/sysinfo/converting-a-time-t-value-to-a-file-time
"""
timeAsFileTime = FILETIME()
res = (int(time_tToConvert) * 10000000) + 116444736000000000
timeAsFileTime.dwLowDateTime = res
timeAsFileTime.dwHighDateTime = res >> 32
return timeAsFileTime


def FileTimeToSystemTime(lpFileTime: FILETIME, lpSystemTime: SYSTEMTIME) -> None:
if kernel32.FileTimeToSystemTime(byref(lpFileTime), byref(lpSystemTime)) == 0:
raise WinError()


def SystemTimeToTzSpecificLocalTime(
lpTimeZoneInformation: Union[TIME_ZONE_INFORMATION, None],
lpUniversalTime: SYSTEMTIME,
lpLocalTime: SYSTEMTIME
) -> None:
"""Wrapper for `SystemTimeToTzSpecificLocalTime` from kernel32.
:param lpTimeZoneInformation: Either TIME_ZONE_INFORMATION containing info about the desired time zone
or `None` when the current time zone as configured in Windows settings should be used.
:param lpUniversalTime: SYSTEMTIME structure containing time in UTC wwhich you wish to convert.
: param lpLocalTime: A SYSTEMTIME structure in which time converted to the desired time zone would be placed.
:raises WinError
"""
if lpTimeZoneInformation is not None:
lpTimeZoneInformation = byref(lpTimeZoneInformation)
if kernel32.SystemTimeToTzSpecificLocalTime(
lpTimeZoneInformation, byref(lpUniversalTime), byref(lpLocalTime)
) == 0:
raise WinError()


def GetDateFormatEx(Locale,dwFlags,date,lpFormat):
if date is not None:
date=SYSTEMTIME(date.year,date.month,0,date.day,date.hour,date.minute,date.second,0)
Expand All @@ -182,8 +239,6 @@ def GetTimeFormatEx(Locale,dwFlags,date,lpFormat):
kernel32.GetTimeFormatEx(Locale,dwFlags,lpTime,lpFormat, buf, bufferLength)
return buf.value

def openProcess(*args):
return kernel32.OpenProcess(*args)

def virtualAllocEx(*args):
res = kernel32.VirtualAllocEx(*args)
Expand Down
1 change: 1 addition & 0 deletions user_docs/en/changes.t2t
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ What's New in NVDA
- known issue for right-to-left languages: the right border of groupings clips with labels/controls. (#12181)
- The python locale is set to match the language selected in preferences consistently, and will occur when using the default language. (#12214)
- - TextInfo.getTextInChunks no longer freezes when called on Rich Edit controls such as the NVDA log viewer. (#11613)
- It is once again possible to use NVDA in a languages containing underscores in the locale name such as de_CH on Windows 10 1803 and 1809. (#12250)


== Changes for Developers ==
Expand Down