Как выбрать элемент в TreeView с помощью Win32 API - PullRequest
12 голосов
/ 07 сентября 2010

Я пытаюсь автоматизировать последовательность пользовательских вводов в скомпилированное приложение на C # с использованием Win32 API. У меня нет исходного кода для приложения, которым я пытаюсь управлять, и оно работает, пока я пытаюсь его контролировать. В моем коде у меня есть одна кнопка, при нажатии которой необходимо выполнить последовательность из 3 входов в приложение, которым я пытаюсь управлять:

  1. Выберите элемент в виде дерева
  2. Нажмите кнопку
  3. Нажмите другую кнопку

Как это работает, кнопка на шаге 2 выполняет действие в зависимости от элемента, выбранного в древовидной структуре на шаге 1. Я могу заставить кнопки работать так же просто, просто отправив сообщение, но не могу понять как выбрать нужный элемент TreeView. TreeView является статическим, поэтому элементы и макет никогда не изменятся. Имеет следующую компоновку:

-itemsA
-itemsB
--itemB1
-itemsC

Где itemB1 - это элемент, который необходимо выбрать, чтобы сработали нажатия кнопок на шагах 2 и 3. По умолчанию ItemsB свернут, поэтому мне, вероятно, нужно расширить его, прежде чем я смогу выбрать ItemB1? Вот мой код Я действительно ценю любую помощь !!

//Find Window API
[DllImport("User32.dll")]
public static extern Int32 FindWindow(String lpClassName, String lpWindowName);

//Find WindowEx API
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);

//Send Message API
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SendMessage(int hWnd, int msg, int wParam, IntPtr lParam);


private const int BN_CLICKED = 245;

//Method called by button click
public static void Start()
{
    int hwnd = 0;
    int prod = 0;
    IntPtr hwndChild = IntPtr.Zero;
    IntPtr treeChild = IntPtr.Zero;
    IntPtr prodChild = IntPtr.Zero;

    hwnd = FindWindow(null, "Application");
    if (hwnd > 0)
    {
        //Get Handle for TreeView, THIS IS WHERE I AM STUCK!!
        treeChild = FindWindowEx((IntPtr)hwnd, IntPtr.Zero, "AfxMDIFrame80", null);
        treeChild = FindWindowEx((IntPtr)treeChild, IntPtr.Zero, "AfxMDIFrame80", null);
        treeChild = FindWindowEx((IntPtr)treeChild, IntPtr.Zero, "SysTreeView32", null);
        //Need to Add code to select item in TreeView ???

        //Click First Button
        hwndChild = FindWindowEx((IntPtr)hwnd, IntPtr.Zero, "AfxMDIFrame80", null);
        hwndChild = FindWindowEx((IntPtr)hwndChild, IntPtr.Zero, "AfxMDIFrame80", null);
        hwndChild = FindWindowEx((IntPtr)hwndChild, IntPtr.Zero, "#32770", null);
        IntPtr scanBtn = FindWindowEx((IntPtr)hwndChild, IntPtr.Zero, "Button", "&Scan");
        SendMessage((int)scanBtn, BN_CLICKED, 0, IntPtr.Zero);

        //Click Second Button
        prod = FindWindow("#32770", "Product: WPC");
        prodChild = FindWindowEx((IntPtr)prod, IntPtr.Zero, "Button", "&Collect");
        SendMessage((int)prodChild, BN_CLICKED, 0, IntPtr.Zero);
    }
    }//END Start

Ганс, * * тысяча двадцать-одна

Можете ли вы дать мне пример того, как я это сделаю? Проблема, которую я действительно испытываю, заключается в поиске дескриптора для элемента дерева, который я хочу выбрать. Если я использую Spy ++, чтобы найти текущий дескриптор и жестко закодировать его в своем методе, он работает нормально, например:

SendMessage((int)treeChild, TV_SELECTITEM, TVGN_CARET, (IntPtr)0x092DCB30); 

Если я использую SendMessage и отправляю TVGN_ROOT в дескриптор TreeView, он вернет IntPtr с дескриптором для элемента, который нужно выбрать в древовидном представлении, или как это работает? Я также экспериментирую с AutoIt, но я надеялся сохранить весь мой код в одном приложении.

Ответы [ 3 ]

11 голосов
/ 08 сентября 2010

Я понял это, поэтому я отправлю сообщение для всех, кто заинтересован, мне было трудно найти документацию по этому вопросу.Вот большая часть моего кода:

//Define TreeView Flags and Messages
private const int BN_CLICKED = 0xF5;
private const int TV_FIRST = 0x1100;
private const int TVGN_ROOT = 0x0;
private const int TVGN_NEXT = 0x1;
private const int TVGN_CHILD = 0x4;
private const int TVGN_FIRSTVISIBLE = 0x5;
private const int TVGN_NEXTVISIBLE = 0x6;
private const int TVGN_CARET = 0x9;
private const int TVM_SELECTITEM = (TV_FIRST + 11);
private const int TVM_GETNEXTITEM = (TV_FIRST + 10);
private const int TVM_GETITEM = (TV_FIRST + 12);

//Find Window API
[DllImport("User32.dll")]
public static extern Int32 FindWindow(String lpClassName, String lpWindowName);

//Find WindowEx API
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);

//Send Message API
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SendMessage(int hWnd, int msg, int wParam, IntPtr lParam);

 public static void Start()
        {
            //Handle variables
            int hwnd = 0;
            int treeItem = 0;
            IntPtr hwndChild = IntPtr.Zero;
            IntPtr treeChild = IntPtr.Zero;

            hwnd = FindWindow(null, "Application"); //Handle for the application to be controlled
            if (hwnd > 0)
            {
                //Select TreeView Item
                treeChild = FindWindowEx((IntPtr)hwnd, IntPtr.Zero, "AfxMDIFrame80", null);
                treeChild = FindWindowEx((IntPtr)treeChild, IntPtr.Zero, "AfxMDIFrame80", null);
                treeChild = FindWindowEx((IntPtr)treeChild, IntPtr.Zero, "SysTreeView32", null);
                treeItem = SendMessage((int)treeChild, TVM_GETNEXTITEM, TVGN_ROOT, IntPtr.Zero);
                treeItem = SendMessage((int)treeChild, TVM_GETNEXTITEM, TVGN_NEXT, (IntPtr)treeItem);
                treeItem = SendMessage((int)treeChild, TVM_GETNEXTITEM, TVGN_CHILD, (IntPtr)treeItem);
                SendMessage((int)treeChild, TVM_SELECTITEM, TVGN_CARET, (IntPtr)treeItem);

                // ...Continue with my automation...
             }
        }//END Scan

Я все еще не могу понять это 100%, но, надеюсь, это поможет.Возвращаемое значение SendMessage будет зависеть от того, какое сообщение вы отправляете, в данном случае это было int, содержащее дескриптор элемента TreeView.Первый аргумент - это дескриптор самого TreeView.Второй аргумент - это сообщение, которое вы хотите отправить.3-й и 4-й аргументы являются флагами.3-й указывает тип элемента, 4-й - дескриптор текущего элемента дерева.

Спасибо за помощь, Ганс!Кто-нибудь еще, пожалуйста, не стесняйтесь уточнять.

2 голосов
/ 07 сентября 2010

Вам нужно пройтись по узлам с TVM_GETNEXTITEM, начиная с TVGN_ROOT.Затем выберите его с помощью TVM_SELECTITEM.Передайте TVGN_FIRSTVISIBLE, чтобы убедиться, что он виден, в этом нет необходимости, если вы просто автоматизируете его.

Взгляните на AutoIt, чтобы избежать написания такого шероховатого кода.

0 голосов
/ 01 апреля 2016

Я знаю, что это уже слишком поздно, но если у вас возникла похожая проблема (как и у меня). Вы можете взглянуть на AutoHotKey, особенно если вы знакомы с SendMessage. Это избавило бы вас от необходимости компиляции и значительно усложнило бы, но, по вашему мнению, было бы возможно перемещаться по структуре с помощью нажатия клавиш со стрелками.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...