Skip to content

Commit ac783ef

Browse files
authored
Fix UWP OCR on 64 bit NVDA (#18858)
### Summary of the issue: Windows OCR doesn't work on 64 bit builds of NVDA. ### Description of user facing changes: Windows OCR works on 64-bit builds of NVDA. ### Description of developer facing changes: Deprecations ### Description of development approach: * Fix up ctypes definitions for functions exported by `nvdaHelperLocalWin10.dll` that were causing problems * Move said ctypes definitions to a new `NVDAHelper.localWin10` module ### Testing strategy: Recognise text (NVDA welcome dialog) on: * [x] 64-bit source copy * [x] 32-bit source copy * [x] 64-bit portable copy * [x] 32-bit portable copy ### Known issues with pull request: I have not moved all ctypes definitions for functions exported by `nvdaHelperLocalWin10.dll` to `NVDAHelper.localWin10`. I believe this is best done in a separate PR, to allow this bugfix to be merged sooner than later.
1 parent ed52f3a commit ac783ef

File tree

5 files changed

+126
-44
lines changed

5 files changed

+126
-44
lines changed

source/NVDAHelper/__init__.py

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -55,39 +55,6 @@
5555
from utils import _deprecate
5656

5757

58-
__getattr__ = _deprecate.handleDeprecations(
59-
_deprecate.MovedSymbol(
60-
"LOCAL_WIN10_DLL_PATH",
61-
"NVDAState",
62-
"ReadPaths",
63-
"nvdaHelperLocalWin10Dll",
64-
),
65-
_deprecate.MovedSymbol(
66-
"versionedLibPath",
67-
"NVDAState",
68-
"ReadPaths",
69-
"versionedLibX86Path",
70-
),
71-
_deprecate.MovedSymbol(
72-
"coreArchLibPath",
73-
"NVDAState",
74-
"ReadPaths",
75-
"coreArchLibPath",
76-
),
77-
_deprecate.MovedSymbol(
78-
"generateBeep",
79-
"NVDAHelper.localLib",
80-
),
81-
_deprecate.MovedSymbol(
82-
"VBuf_getTextInRange",
83-
"NVDAHelper.localLib",
84-
),
85-
_deprecate.MovedSymbol(
86-
"nvdaController_onSsmlMarkReached",
87-
"NVDAHelper.localLib",
88-
),
89-
)
90-
9158
if typing.TYPE_CHECKING:
9259
from speech.priorities import SpeechPriority
9360
from characterProcessing import SymbolLevel
@@ -914,7 +881,7 @@ def getHelperLocalWin10Dll():
914881
return windll[ReadPaths.nvdaHelperLocalWin10Dll]
915882

916883

917-
def bstrReturn(address):
884+
def _bstrReturn(address: int) -> str:
918885
"""Handle a BSTR returned from a ctypes function call.
919886
This includes freeing the memory.
920887
This is needed for nvdaHelperLocalWin10 functions which return a BSTR.
@@ -926,3 +893,38 @@ def bstrReturn(address):
926893
val = wstring_at(address)
927894
winBindings.oleaut32.SysFreeString(address)
928895
return val
896+
897+
898+
__getattr__ = _deprecate.handleDeprecations(
899+
_deprecate.MovedSymbol(
900+
"LOCAL_WIN10_DLL_PATH",
901+
"NVDAState",
902+
"ReadPaths",
903+
"nvdaHelperLocalWin10Dll",
904+
),
905+
_deprecate.MovedSymbol(
906+
"versionedLibPath",
907+
"NVDAState",
908+
"ReadPaths",
909+
"versionedLibX86Path",
910+
),
911+
_deprecate.MovedSymbol(
912+
"coreArchLibPath",
913+
"NVDAState",
914+
"ReadPaths",
915+
"coreArchLibPath",
916+
),
917+
_deprecate.MovedSymbol(
918+
"generateBeep",
919+
"NVDAHelper.localLib",
920+
),
921+
_deprecate.MovedSymbol(
922+
"VBuf_getTextInRange",
923+
"NVDAHelper.localLib",
924+
),
925+
_deprecate.MovedSymbol(
926+
"nvdaController_onSsmlMarkReached",
927+
"NVDAHelper.localLib",
928+
),
929+
_deprecate.RemovedSymbol("bstrReturn", _bstrReturn),
930+
)

source/NVDAHelper/localWin10.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# A part of NonVisual Desktop Access (NVDA)
2+
# Copyright (C) 2017-2025 NV Access Limited
3+
# This file is covered by the GNU General Public License.
4+
# See the file COPYING for more details.
5+
6+
"""Functions exported by nvdaHelperLocalWin10.dll, and supporting definitions."""
7+
8+
from ctypes import CFUNCTYPE, POINTER, c_uint, c_void_p, c_wchar_p, windll
9+
from comtypes import BSTR
10+
11+
import NVDAState
12+
from winBindings.gdi32 import RGBQUAD
13+
14+
dll = windll.LoadLibrary(NVDAState.ReadPaths.nvdaHelperLocalWin10Dll)
15+
16+
UwpOcr_P = c_void_p
17+
"""Pointer to an UwpOcr object."""
18+
19+
uwpOcr_getLanguages = dll.uwpOcr_getLanguages
20+
"""
21+
Get supported language codes separated by semicolons.
22+
23+
.. seealso::
24+
``nvdaHelper/localWin10/uwpOcr.h``
25+
"""
26+
uwpOcr_getLanguages.argtypes = ()
27+
uwpOcr_getLanguages.restype = BSTR
28+
29+
uwpOcr_Callback = CFUNCTYPE(None, c_wchar_p)
30+
"""Function called when recognition is complete."""
31+
32+
uwpOcr_initialize = dll.uwpOcr_initialize
33+
"""
34+
Initialise a UWP OCR instance.
35+
36+
.. seealso::
37+
``nvdaHelper/localWin10/uwpOcr.h``
38+
"""
39+
uwpOcr_initialize.argtypes = (
40+
c_wchar_p, # language
41+
uwpOcr_Callback, # callback
42+
)
43+
uwpOcr_initialize.restype = UwpOcr_P
44+
45+
uwpOcr_terminate = dll.uwpOcr_terminate
46+
"""
47+
Terminate a UWP OCR instance.
48+
49+
.. seealso::
50+
``nvdaHelper/localWin10/uwpOcr.h``
51+
"""
52+
uwpOcr_terminate.argtypes = (
53+
UwpOcr_P, # instance
54+
)
55+
uwpOcr_terminate.restype = None
56+
57+
uwpOcr_recognize = dll.uwpOcr_recognize
58+
"""
59+
Recognise text in an image.
60+
61+
.. seealso::
62+
``nvdaHelper/localWin10/uwpOcr.h``
63+
"""
64+
uwpOcr_recognize.argtypes = (
65+
UwpOcr_P, # instance
66+
POINTER(RGBQUAD), # image
67+
c_uint, # width
68+
c_uint, # height
69+
)
70+
uwpOcr_recognize.restype = None

source/contentRecog/uwpOcr.py

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,23 @@
55

66
"""Recognition of text using the UWP OCR engine included in Windows 10 and later."""
77

8-
import ctypes
98
import json
109
import NVDAHelper
10+
from NVDAHelper.localWin10 import (
11+
uwpOcr_getLanguages,
12+
uwpOcr_initialize,
13+
uwpOcr_recognize,
14+
uwpOcr_terminate,
15+
uwpOcr_Callback as _uwpOcr_Callback,
16+
)
1117
from . import ContentRecognizer, LinesWordsResult
1218
import config
1319
import languageHandler
20+
from utils import _deprecate
1421

15-
uwpOcr_Callback = ctypes.CFUNCTYPE(None, ctypes.c_wchar_p)
22+
__getattr__ = _deprecate.handleDeprecations(
23+
_deprecate.MovedSymbol("uwpOcr_Callback", "NVDAHelper.localWin10"),
24+
)
1625

1726

1827
def getLanguages():
@@ -22,9 +31,7 @@ def getLanguages():
2231
for use as NVDA language codes.
2332
@rtype: list of str
2433
"""
25-
dll = NVDAHelper.getHelperLocalWin10Dll()
26-
dll.uwpOcr_getLanguages.restype = NVDAHelper.bstrReturn
27-
langs = dll.uwpOcr_getLanguages()
34+
langs = uwpOcr_getLanguages()
2835
return langs.split(";")[:-1]
2936

3037

@@ -99,7 +106,7 @@ def __init__(self, language=None):
99106
def recognize(self, pixels, imgInfo, onResult):
100107
self._onResult = onResult
101108

102-
@uwpOcr_Callback
109+
@_uwpOcr_Callback
103110
def callback(result):
104111
# If self._onResult is None, recognition was cancelled.
105112
if self._onResult:
@@ -108,16 +115,16 @@ def callback(result):
108115
self._onResult(LinesWordsResult(data, imgInfo))
109116
else:
110117
self._onResult(RuntimeError("UWP OCR failed"))
111-
self._dll.uwpOcr_terminate(self._handle)
118+
uwpOcr_terminate(self._handle)
112119
self._callback = None
113120
self._handle = None
114121

115122
self._callback = callback
116-
self._handle = self._dll.uwpOcr_initialize(self.language, callback)
123+
self._handle = uwpOcr_initialize(self.language, callback)
117124
if not self._handle:
118125
onResult(RuntimeError("UWP OCR initialization failed"))
119126
return
120-
self._dll.uwpOcr_recognize(self._handle, pixels, imgInfo.recogWidth, imgInfo.recogHeight)
127+
uwpOcr_recognize(self._handle, pixels, imgInfo.recogWidth, imgInfo.recogHeight)
121128

122129
def cancel(self):
123130
self._onResult = None

source/screenBitmap.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ def captureImage(self, x, y, w, h):
6565
winGDI.SRCCOPY,
6666
)
6767
# Fetch the pixels from our memory bitmap and store them in a buffer to be returned
68-
buffer = (winBindings.gdi32.RGBQUAD * self.width * self.height)()
68+
buffer = (winBindings.gdi32.RGBQUAD * (self.width * self.height))()
6969
winBindings.gdi32.GetDIBits(
7070
self._memDC,
7171
self._memBitmap,

user_docs/en/changes.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@ Use `winBindings.mmeapi.WAVEFORMATEX` instead. (#18207)
118118
Access to these symbols via `winKernel` is deprecated. (#18860)
119119
* `winKernel.advapi32` is deprecated.
120120
Use `winBindings.advapi32.dll` instead. (#18860)
121+
* `NVDAHelper.bstrReturn` is deprecated, with no planned replacement. (#18858)
122+
* `contentRecog.uwpOcr.uwpOcr_Callback` is deprecated.
123+
Use `NVDAHelper.localWin10.uwpOcr_Callback` instead. (#18858)
121124

122125
<!-- Beyond this point, Markdown should not be linted, as we don't modify old change log sections. -->
123126
<!-- markdownlint-disable -->

0 commit comments

Comments
 (0)