Using COM with NVDA and Microsoft Word - nvaccess/nvda GitHub Wiki
This page provides a rough set of notes on getting started with COM calls via NVDA for Microsoft word.
Getting started
- Open Microsoft word (with the content you wish to explore)
- Press NVDA+ctrl+z to open the NVDA Python Console
- Get access to a
TextInfo
object:tInfo = focus.makeTextInfo("caret")
Test the size of this range with:
tInfo._rangeObj.start
tInfo._rangeObj.end
You can modify these and then use tInfo._rangeObj.text
to see what is in the range.
Exploring the interface
Using the Microsoft Word VBA Object model reference is helpful to explore what is available. See https://msdn.microsoft.com/EN-US/library/office/ff837519.aspx (if this link breaks, and you are having trouble finding this, try searching for "microsoft word range object" and going back up the documentation hierarchy).
The Object model referred to in the VBA reference is available in your NVDA Python Console under tInfo._rangeObj
. This allows you try getting the number of hyperlinks in the range, see the text for one, and its address:
tInfo._rangeObj.hyperlinks.count
tInfo._rangeObj.hyperlinks.item(1).range.text
tInfo._rangeObj.hyperlinks.item(1).address
Getting the method/property IDs
You will notice (in winword.cpp
) that there are calls to _com_dispatch_raw_method
and _com_dispatch_raw_propget
which rely on defines set at the top of the file, such as #define wdDISPID_RANGE_START 3
. Its important to be able to get these values. This can be done by querying the COM object for the ID for a name:
idisp = tInfo._rangeObj._comobj
idisp.GetIDsOfNames('hyperlinks')
# should output: [156]
_com_dispatch_raw_method and _com_dispatch_raw_propget
These functions are used by NVDA to perform the method/property calls that we explored above.
Its hard to find any documentation on these functions!
(Adapted from info on a forum: http://www.progtown.com/topic94739-function-comdispatchmethod.html) Here is a short description of the functions:
// Get properties from the object
HRESULT __ cdecl _com_dispatch_raw_propget(IDispatch * pDisp, DISPID dispid, VARTYPE vt, void * pResult);
// Call a method on the object
HRESULT __ cdecl _com_dispatch_raw_method (IDispatch * pDisp, DISPID dispid, WORD w, VARTYPE vt, void * pResult, const wchar_t * szFormat...);
// Where:
pDisp - IDispatch of the method's object. This seems to be the object on which you wish to call a method, access a property.
dispid - The DISPID of the method to call. The ID of the method to call, as returned by `GetIDsOfNames()`
w - DISPATCH_METHOD or DISPATCH_PROPERTYGET.
vt - The return type. Must be a Variant type (one of: VT_I4, VT_DISPATCH, VT_BSTR, VT_BOOL, VT_EMPTY, VT_R4 see below)
pResult - Pointer to the memory location to place the return value. The type should match the vt param.
SzFormat - String where each byte represents the variant type of each of the arguments being passed to the method.
... - var args. The argument(s) to the method, as specified by SzFormat.
w param
When fetching range.Information
use DISPATCH_PROPERTYGET
vt param
VT_I4
- pass in address ofint
type aspResult
(4 bytes)VT_DISPATCH
- pass inIDispatchPtr
aspResult
. Returns a complex data type, which can then be queried further.VT_BSTR
- Some kind of string type. Pass address of aBST
aspResult
VT_BOOL
- Boolean type.VT_EMPTY
- no argument??VT_R4
- Real (floating point) number. (4 bytes)
SzFormat param known values
L"\x0003"
- oneint
L"\x0003\x0003
- twoint
sL"\x0009"
-IDispatchPtr
- The following values were found by inspecting: https://github.com/svn2github/FDM/blob/master/shdocvw.tli
L"\x400c
-VARIANT *
L"\x400b
-VARIANT_BOOL *
L"\x000b
-VARIANT_BOOL
L"\x0008
-BSTR
L"\x4009
-IDispatch * *
L"\x4003
-LONG *
In order to be sure of the types required by a function, you can search for the function in the *.tlh
and *.tli
files that are created via the process documented in the message for commit: e2aa0cc0d2d (on branch: experiment_useCompiledMSWordInterface)