[program-l] Re: Use Windows Message to get info från Python

  • From: Tony Malykh <anton.malykh@xxxxxxxxx>
  • To: program-l@xxxxxxxxxxxxx, Karl-Otto Rosenqvist <karl-otto@xxxxxxxxxx>, travis@xxxxxxxxxxxxxx
  • Date: Fri, 28 Jan 2022 17:56:25 -0800

Not that easy, but doable. First of all, NVDA uses watchdog.cancellableSendMessage function to send Windows messages. You can search usages of this function in NVDA source code. I am actually not sure why do they need this function instead of directly calling API, but I assume they must have a reason.
As for passing structures, one example I found is
source\NVDAObjects\window\scintilla.py
numBytes = watchdog.cancellableSendMessage(self.obj.windowHandle, SCI_GETTEXTRANGE, 0, internalTextRange)
You can probably find more examples in the source code. Also more people are familiar with NVDA internals on nvda-addons mailing list.
HTH

On 1/28/2022 3:01 PM, Karl-Otto Rosenqvist wrote:

Thanks!
The first call was successful because it didn't need any params and it just returned an int.

the second one requires a struct to be passed and that struct needs to contain a string pointer so the text on the tab can be written to it.
I haven't been able to do this successfully.

The struct to be passed:

class TCITEMAStruct(Structure):
    _fields_=[
        ("mask", c_uint),
        ('state', wintypes.DWORD),
        ('stateMask', wintypes.DWORD),
        ('text', c_char_p),
        ('textMax', c_int),
        ('image', c_int),
        ('lParam', wintypes.LPARAM),
    ]

If I do the following the host application crashes:
                bufLen = 100
                tcitemstruct = TCITEMAStruct()
                tcitemstruct.mask = TCIF_TEXT
                tcitemstruct.textMax = bufLen

                buf = create_string_buffer(bufLen)
                tcitemstruct.text = cast(buf, c_char_p)

                got_it = winUser.sendMessage(obj.windowHandle, TCM_GETITEMA, tabidx , tcitemstruct)



In scintilla.py I found a way to do it by allocating memory for the process and it almost works:

                bufLen = 100
                tcitemstruct = TCITEMAStruct()
                tcitemstruct.mask = TCIF_TEXT
                tcitemstruct.textMax = bufLen
                processHandle = obj.processHandle
                internalBuf = winKernel.virtualAllocEx(processHandle, None, bufLen, winKernel.MEM_COMMIT, winKernel.PAGE_READWRITE)
                try:
                    tcitemstruct.text = internalBuf
                    internalTCItem = winKernel.virtualAllocEx(processHandle, None, sizeof(tcitemstruct), winKernel.MEM_COMMIT, winKernel.PAGE_READWRITE)
                    try:
winKernel.writeProcessMemory(processHandle, internalTCItem, byref(tcitemstruct), sizeof(tcitemstruct), None)
                        got_it = winUser.sendMessage(obj.windowHandle, TCM_GETITEMW, tabidx , internalTCItem)
                    finally:
                        winKernel.virtualFreeEx(processHandle, internalTCItem, 0, winKernel.MEM_RELEASE)
                    buf = create_string_buffer(bufLen)
                    winKernel.readProcessMemory(processHandle, internalBuf, buf, bufLen, None)
                finally:
                    winKernel.virtualFreeEx(processHandle, internalBuf, 0, winKernel.MEM_RELEASE)
                if got_it:
                    ui.message("Got it!")
                    ui.message(buf)

The call is successful, i e got_it is true, but the buffer seems to be empty because NVDA doesn't say anything.

Does anyone have any idea on what's wrong here?


Kind regards

Karl-Otto

Karl-Otto Rosenqvist
MAWINGU
Orgnr: 750804-3937
0701- 75 98 56
karl-otto@xxxxxxxxxx
https://mawingu.se

Den 2022-01-28 kl. 18:00, skrev travis@xxxxxxxxxxxxxx:
In the case of NVDA, import winUser module. (You may also want to review it in the nvda \source folder.)
I'm not sure which method you need, perhaps getMessage() or sendMessage() will work.
NVDA has a lot of Windows helper function in winUser.py and something in there should do what you need.
-Travis


-----Original Message-----
From: program-l-bounce@xxxxxxxxxxxxx <program-l-bounce@xxxxxxxxxxxxx> On Behalf Of Karl-Otto Rosenqvist
Sent: Friday, January 28, 2022 10:48 AM
To: program-l@xxxxxxxxxxxxx
Subject: [program-l] Use Windows Message to get info från Python

Hi!
I'd like to enhance an add on I've created for NVDA and in order to get info about the selected tab and the text on that tab I need to send Windows Messages but I have no idea on how to do this in Python.

It is TCM_GETCURSEL and TCM_GETITEM I should use.


Thanks in advance

Karl-Otto

--
Karl-Otto Rosenqvist
MAWINGU
Orgnr: 750804-3937
0701- 75 98 56
karl-otto@xxxxxxxxxx
https://mawingu.se
** To leave the list, click on the immediately-following link:-
** [mailto:program-l-request@xxxxxxxxxxxxx?subject=unsubscribe]
** If this link doesn't work then send a message to:
** program-l-request@xxxxxxxxxxxxx
** and in the Subject line type
** unsubscribe
** For other list commands such as vacation mode, click on the
** immediately-following link:-
** [mailto:program-l-request@xxxxxxxxxxxxx?subject=faq]
** or send a message, to
** program-l-request@xxxxxxxxxxxxx with the Subject:- faq

** To leave the list, click on the immediately-following link:-
** [mailto:program-l-request@xxxxxxxxxxxxx?subject=unsubscribe]
** If this link doesn't work then send a message to:
** program-l-request@xxxxxxxxxxxxx
** and in the Subject line type
** unsubscribe
** For other list commands such as vacation mode, click on the
** immediately-following link:-
** [mailto:program-l-request@xxxxxxxxxxxxx?subject=faq]
** or send a message, to
** program-l-request@xxxxxxxxxxxxx with the Subject:- faq
** To leave the list, click on the immediately-following link:-
** [mailto:program-l-request@xxxxxxxxxxxxx?subject=unsubscribe]
** If this link doesn't work then send a message to:
** program-l-request@xxxxxxxxxxxxx
** and in the Subject line type
** unsubscribe
** For other list commands such as vacation mode, click on the
** immediately-following link:-
** [mailto:program-l-request@xxxxxxxxxxxxx?subject=faq]
** or send a message, to
** program-l-request@xxxxxxxxxxxxx with the Subject:- faq
** To leave the list, click on the immediately-following link:-
** [mailto:program-l-request@xxxxxxxxxxxxx?subject=unsubscribe]
** If this link doesn't work then send a message to:
** program-l-request@xxxxxxxxxxxxx
** and in the Subject line type
** unsubscribe
** For other list commands such as vacation mode, click on the
** immediately-following link:-
** [mailto:program-l-request@xxxxxxxxxxxxx?subject=faq]
** or send a message, to
** program-l-request@xxxxxxxxxxxxx with the Subject:- faq

Other related posts: