【问题标题】:How can I read the text from this label using WinAPI calls?如何使用 WinAPI 调用从该标签中读取文本?
【发布时间】:2020-04-29 19:49:27
【问题描述】:

有一个窗口,我想使用 WinAPI 调用从中读取特定文本(下面的屏幕截图中的10.024)。

这是这个窗口在 Spy++ 中的样子:

要从该标签中读取值,我首先确定窗口的句柄:

private TargetWindowInfo FindScrivenerWindow()
{
    IntPtr targetWindowHandle = new IntPtr(0);
    String windowTitle = "";
    Process[] scrivenerProcesses = Process.GetProcessesByName("scrivener");
    if (scrivenerProcesses.Length < 1)
    {
        return null; // Scrivener is not started
    }
    foreach (var handle in EnumerateProcessWindowHandles(scrivenerProcesses.First().Id))
    {
        StringBuilder message = new StringBuilder(1000);
        SendMessage(handle, WM_GETTEXT, message.Capacity, message);
        String curWindowTitle = message.ToString();

        if (curWindowTitle.EndsWith("Project Targets"))
        {
            bool windowVisible = IsWindowVisible(handle);

            if (windowVisible)
            {
                windowTitle = curWindowTitle;
                targetWindowHandle = handle;

                var result = new TargetWindowInfo();

                result.ProjectName = windowTitle.Substring(0, windowTitle.IndexOf(" Project Targets"));
                result.Handle = handle;
                return result;
            }

        }
    }
    return null;
}


var targetWindowInfo = FindScrivenerWindow();

然后我尝试应用this answer 来读取窗口中的所有字符串,并希望在其中找到所需的字符串(10.024)(targetWindowInfo.HandleFindScrivenerWindow 的结果):

List<WinText> windows = new List<WinText>();

//find the "first" window
IntPtr hWnd = targetWindowInfo.Handle;

while (hWnd != IntPtr.Zero)
{
    //find the control window that has the text
    IntPtr hEdit = FindWindowEx(hWnd, IntPtr.Zero, null, null);

    //initialize the buffer.  using a StringBuilder here
    System.Text.StringBuilder sb = new System.Text.StringBuilder(255);  // or length from call with GETTEXTLENGTH

    //get the text from the child control
    int RetVal = SendMessage(hEdit, WM_GETTEXT, sb.Capacity, sb);

    windows.Add(new WinText() { hWnd = hWnd, Text = sb.ToString() });

    //find the next window
    hWnd = FindWindowEx(IntPtr.Zero, hWnd, "scrivener", null);
}

//do something clever
windows.OrderBy(x => x.Text).ToList().ForEach(y => Console.Write("{0} = {1}\n", y.hWnd, y.Text));

Console.Write("\n\nFound {0} window(s).", windows.Count);

windows 始终只有一个元素,文本为空字符串。

如何读取标签的值?考虑到窗口的属性,是否有可能?

更新 1: UI Automation Inspect 报告标签的以下值:

How found:  Selected from tree...
Name:   ""
BoundingRectangle:  {l:1437 t:455 r:1484 b:475}
IsEnabled:  true
IsOffscreen:    false
IsKeyboardFocusable:    false
HasKeyboardFocus:   false
AccessKey:  ""
ProcessId:  6488
ProviderDescription:    "[pid:6488,providerId:0x0 Main(parent link):Microsoft: MSAA Proxy (unmanaged:uiautomationcore.dll)]"
IsPassword: false
HelpText:   ""
IsDialog:   false
LegacyIAccessible.ChildId:  0
LegacyIAccessible.DefaultAction:    "SetFocus"
LegacyIAccessible.Description:  ""
LegacyIAccessible.Help: ""
LegacyIAccessible.KeyboardShortcut: ""
LegacyIAccessible.Name: ""
LegacyIAccessible.Role: Client (0xA)
LegacyIAccessible.State:    normal (0x0)
LegacyIAccessible.Value:    ""
IsAnnotationPatternAvailable:   false
IsDragPatternAvailable: false
IsDockPatternAvailable: false
IsDropTargetPatternAvailable:   false
IsExpandCollapsePatternAvailable:   false
IsGridItemPatternAvailable: false
IsGridPatternAvailable: false
IsInvokePatternAvailable:   false
IsItemContainerPatternAvailable:    false
IsLegacyIAccessiblePatternAvailable:    true
IsMultipleViewPatternAvailable: false
IsObjectModelPatternAvailable:  false
IsRangeValuePatternAvailable:   false
IsScrollItemPatternAvailable:   false
IsScrollPatternAvailable:   false
IsSelectionItemPatternAvailable:    false
IsSelectionPatternAvailable:    false
IsSpreadsheetItemPatternAvailable:  false
IsSpreadsheetPatternAvailable:  false
IsStylesPatternAvailable:   false
IsSynchronizedInputPatternAvailable:    false
IsTableItemPatternAvailable:    false
IsTablePatternAvailable:    false
IsTextChildPatternAvailable:    false
IsTextEditPatternAvailable: false
IsTextPatternAvailable: false
IsTextPattern2Available:    false
IsTogglePatternAvailable:   false
IsTransformPatternAvailable:    false
IsTransform2PatternAvailable:   false
IsValuePatternAvailable:    false
IsVirtualizedItemPatternAvailable:  false
IsWindowPatternAvailable:   false
IsCustomNavigationPatternAvailable: false
IsSelectionPattern2Available:   false
FirstChild: [null]
LastChild:  [null]
Next:   "" 
Previous:   "" 
Other Props:    Object has no additional properties
Children:   Container has no children
Ancestors:  "short-story-4 Project Targets" Fenster
    "short-story-4 - Scrivener" Fenster
    "Desktop 1" Bereich
    [ No Parent ]

【问题讨论】:

  • 如果不回避UI Automation,您会看到更少的惊喜。使用 Inspect.exe 工具快速验证目标窗口是否合适。
  • @IInspectable 我从 Inspect.exe 粘贴了这个特定控件的值。是否可以使用通常的 WinAPI/UIAutomation 方法从该标签中提取文本?
  • 您的第一个 Spy++ 屏幕截图显示“short-story-4 Project Targets”窗口没有任何子窗口,这意味着它正在使用无窗口控件(即,它们是直接自定义绘制的到父对话框窗口上),在这种情况下 UIAutomation 是远程访问它们的唯一方法,如果 UI 框架甚至实现了对它的支持(Inspect.exe 似乎说不是这种情况)。 QToolQWidget 表明 Qt 是使用的 UI 框架,它确实可以选择使用无窗口控件 (doc.qt.io/qt-5/qwidget.html#native-widgets-vs-alien-widgets)
  • @RemyLebeau 谢谢。如果您提交您的评论作为答案,我会接受。
  • @DmitriiPisarenko 随时回答你自己,Accept Your Own Answers 结束这个话题。

标签: c# winforms winapi


【解决方案1】:

如果不使用诸如DLL injection 之类的奇特且昂贵的技术,就不可能从该字段中读取文本,这可能是一种矫枉过正。简单地制作窗口的屏幕截图,裁剪图像的相关部分并在其上运行 OCR 会便宜得多。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-17
    • 2014-09-29
    • 1970-01-01
    • 1970-01-01
    • 2019-02-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多