Repository: nvaccess/nvda

Issue:
sysListView32.ListItem._getColumnLocationRaw can return malformed rectangles (i.e. with a left coordinate that is greather than the right coordinate)
### Steps to reproduce:
1. Install NVDA Version: next-15126,d5e58ddf
2. Launch Becky! Internet Mail and focus a list of messages.
3. Try to navigate with arrow keys.
### Expected behavior:
NVDA should read list columns such as subject send date and from

### Actual behavior:
An error sound is played. I am attaching a  fragment of the log with specific error.

### System configuration:
NVDA version:
next-15126,d5e58ddf

NVDA Installed or portable:
Installed
Other information:
It is probably caused by #8190. The problematic column seems to be the first column, which contain graphical presentation of the message state read, unread etc. I am also attaching developer info for this column.

Windows version:
Windows 8 x64

Name and version of other software in use when reproducing the issue:
Becky! Internet Mail version 2.74 [en] 
### Other questions:

Does the issue still occur after restarting your PC?
Yes
Have you tried any other versions of NVDA?
Yes next 15121,7fcd6fe7 and it was possible to read this list.
[Issue.zip](https://github.com/nvaccess/nvda/files/2005295/Issue.zip)



Discussion:
This is caused by #7537, which introduces the new locationHelper module. It looks like sysListView32.ListItem._getColumnLocationRaw can return malformed rectangles (i.e. with a left coordinate that is greather than the right coordinate). This really should not be the case for these rectangles. In any case, this code is slightly complex and fixing that as part of #7537 might be quite error prone, so I reverted _getColumnLocationRaw to the stage before locationHelper for now. I think we should leave it as is for now, but we should keep this issue open in order to investigate why _getColumnLocationRaw returns a rectangle that we do not expect.
@lukaszgo1: Could you please try this again with the latest version of next?
@leonardder Latest next fixes it. Thanks.
should this be closed now?
never mind, I think not.
Hmm, I was able to reproduce this with Becky. When I use UIA for syslistview32,, the location for the particular column turns out to be different and according to the guidelines.

Resolving patch:
diff --git a/source/NVDAObjects/IAccessible/sysListView32.py b/source/NVDAObjects/IAccessible/sysListView32.py
--- a/source/NVDAObjects/IAccessible/sysListView32.py
+++ b/source/NVDAObjects/IAccessible/sysListView32.py
@@ -7,6 +7,7 @@
 
 import time
 from ctypes import *
+import ctypes
 from ctypes.wintypes import *
 from comtypes import BSTR
 import oleacc
@@ -23,6 +24,7 @@
 from NVDAObjects.behaviors import RowWithoutCellObjects, RowWithFakeNavigation
 import config
 from locationHelper import RectLTRB
+from logHandler import log
 
 #Window messages
 LVM_FIRST=0x1000
@@ -223,6 +225,8 @@ def _get__columnOrderArray(self):
 			res = watchdog.cancellableSendMessage(self.windowHandle,LVM_GETCOLUMNORDERARRAY, self.columnCount, internalCoa)
 			if res:
 				winKernel.readProcessMemory(processHandle,internalCoa,byref(coa),sizeof(coa),None)
+			else:
+				log.debugWarning("LVM_GETCOLUMNORDERARRAY failed for list")
 		finally:
 			winKernel.virtualFreeEx(processHandle,internalCoa,0,winKernel.MEM_RELEASE)
 		return coa
@@ -306,26 +310,49 @@ def event_stateChange(self):
 class ListItem(RowWithFakeNavigation, RowWithoutCellObjects, ListItemWithoutColumnSupport):
 
 	def _getColumnLocationRaw(self,index):
-		assert index>0, "Invalid index: %d" % index
 		processHandle=self.processHandle
 		# LVM_GETSUBITEMRECT requires a pointer to a RECT structure that will receive the subitem bounding rectangle information.
 		localRect=RECT(
-			left=LVIR_LABEL, # Returns the bounding rectangle of the entire item, including the icon and label
-			top=index # The one-based index of the subitem
+			# Returns the bounding rectangle of the entire item, including the icon and label.
+			left=LVIR_LABEL,
+			# According to Microsoft, top should be the one-based index of the subitem.
+			# However, indexes coming from LVM_GETCOLUMNORDERARRAY are zero based.
+			top=index
 		)
 		internalRect=winKernel.virtualAllocEx(processHandle,None,sizeof(localRect),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE)
 		try:
 			winKernel.writeProcessMemory(processHandle,internalRect,byref(localRect),sizeof(localRect),None)
-			watchdog.cancellableSendMessage(self.windowHandle,LVM_GETSUBITEMRECT, (self.IAccessibleChildID-1), internalRect)
-			winKernel.readProcessMemory(processHandle,internalRect,byref(localRect),sizeof(localRect),None)
+			res = watchdog.cancellableSendMessage(
+				self.windowHandle,
+				LVM_GETSUBITEMRECT,
+				self.IAccessibleChildID - 1,
+				internalRect
+			)
+			if res:
+				winKernel.readProcessMemory(
+					processHandle,
+					internalRect,
+					ctypes.byref(localRect),
+					ctypes.sizeof(localRect),
+					None
+				)
 		finally:
 			winKernel.virtualFreeEx(processHandle,internalRect,0,winKernel.MEM_RELEASE)
+		if res == 0:
+			log.debugWarning(f"LVM_GETSUBITEMRECT failed for index {index} in list")
+			return None
 		# #8268: this might be a malformed rectangle
 		# (i.e. with a left coordinate that is greather than the right coordinate).
-		left = min(localRect.left, localRect.right)
-		top = min(localRect.top, localRect.bottom)
-		right = max(localRect.left, localRect.right)
-		bottom = max(localRect.top, localRect.bottom)
+		# This happens in Becky! Internet Mail,
+		# as well in applications that expose zero width columns.
+		left = localRect.left
+		top = localRect.top
+		right = localRect.right
+		bottom = localRect.bottom
+		if left > right:
+			left = right
+		if top > bottom:
+			top = bottom
 		return RectLTRB(left, top, right, bottom).toScreen(self.windowHandle).toLTWH()
 
 	def _getColumnLocation(self,column):
@@ -405,6 +432,9 @@ def _get_name(self):
 			return name
 		textList = []
 		for col in range(1, self.childCount + 1):
+			location = self._getColumnLocation(col)
+			if location.width == 0:
+				continue
 			content = self._getColumnContent(col)
 			if not content:
 				continue
@@ -417,7 +447,8 @@ def _get_name(self):
 			else:
 				textList.append(content)
 		name = "; ".join(textList)
-		#Some list view items in Windows Vista and later can contain annoying left-to-right and right-to-left indicator characters which really should not be there.
+		# Some list view items in Windows Vista and later can contain annoying left-to-right and right-to-left
+		# indicator characters which really should not be there.
 		return name.replace(CHAR_LTR_MARK,'').replace(CHAR_RTL_MARK,'')
 
 	value = None
diff --git a/source/NVDAObjects/behaviors.py b/source/NVDAObjects/behaviors.py
--- a/source/NVDAObjects/behaviors.py
+++ b/source/NVDAObjects/behaviors.py
@@ -559,11 +559,11 @@ def _moveToColumnNumber(self, column):
 	def script_moveToNextColumn(self, gesture):
 		cur = api.getNavigatorObject()
 		if cur == self:
-			new = self.firstChild
+			new = self.simpleFirstChild
 		elif cur.parent != self:
 			new = self
 		else:
-			new = cur.next
+			new = cur.simpleNext
 		self._moveToColumn(new)
 	script_moveToNextColumn.canPropagate = True
 	# Translators: The description of an NVDA command.
@@ -573,10 +573,10 @@ def script_moveToPreviousColumn(self, gesture):
 		cur = api.getNavigatorObject()
 		if cur == self:
 			new = None
-		elif cur.parent != self or cur.columnNumber == 1:
+		elif cur.parent != self or not cur.simplePrevious:
 			new = self
 		else:
-			new = cur.previous
+			new = cur.simplePrevious
 		self._moveToColumn(new)
 	script_moveToPreviousColumn.canPropagate = True
 	# Translators: The description of an NVDA command.
@@ -711,7 +711,10 @@ def _get_tableID(self):
 		return id(self.parent.parent)
 
 	def _get_states(self):
-		return self.parent.states
+		states = self.parent.states.copy()
+		if not self.location or self.location.width == 0:
+			states.add(controlTypes.STATE_INVISIBLE)
+		return states
 
 class FocusableUnfocusableContainer(NVDAObject):
 	"""Makes an unfocusable container focusable using its first focusable descendant.


Test patch: