Search code examples
ui-automationmicrosoft-ui-automation

Text from UIAutomation property value truncated to 4k


I'm using UIAutomation from a 32-bit C++ application on Windows 7 to get the text content of windows of other processes. I noticed that the API always returns strings truncated to exactly 4096 characters if the text in the windows is longer than that. This happens both with the GetCachedPropertyValue() and the GetCurrentPropertyValue() calls, for both the UIA_ValueValuePropertyId and UIA_LegacyIAccessibleValuePropertyId property Ids. Tested, among others, against 32- and 64-bit Notepad. When I retrieve the text using SendMessage and the WM_GETTEXTLENGTH and WM_GETTEXT messages, the complete, untruncated text is returned. (This I currently use as a workaround.)

Looking through the documentation, I can nowhere find any mention of this limitation or how to get around it, which I would expect if truncation was by design. I found a similar question on stackoverflow but there truncation was apparently due to the Visual Studio debugger, not to the UIAutomation API. However, this question makes it clear that UIAutomation should be able to return very long texts. Googling the issue leads to another question on stackoverflow that also mentions the 4096 character limit, but unfortunately that question and any possible answer is deleted.

Perhaps the properties UIA_ValueValuePropertyId or UIA_LegacyIAccessibleValuePropertyId are not the correct one to use, but I failed to identify a better one.

Can anyone point me out what I'm doing wrong, or have suggestions for what I could try? Pointers to pieces of documentation that I obviously missed are welcome, too.

TIA


Solution

  • The exposition of the value is here for convenience but has limited capabilities. Instead, you must use TextPattern and it's DocumentRange property. This is explicitly specified here. From it you can use the GetText(-1) method to retrieve your data.

    You can code it like that :

    string GetText(AutomationElement ae)
    {
        return (ae.GetCurrentPattern(TextPattern.Pattern) as TextPattern)?.DocumentRange.GetText(-1);
    }