简体   繁体   English

如何使用Win32 API在TreeView中选择项目

[英]How to select an item in a TreeView using Win32 API

I am trying to automate a sequence of user inputs to a compiled application in C# using Win32 API. 我试图使用Win32 API自动将一系列用户输入自动输入到C#中的已编译应用程序。 I do not have any source code for the application I am trying to control and it is running while I am trying to control it. 我没有任何我试图控制的应用程序的源代码,它正在运行,而我正在尝试控制它。 In my code, I have a single button that, when clicked, needs to make a sequence of 3 inputs to the application I am trying to control: 在我的代码中,我有一个按钮,当单击时,需要为我试图控制的应用程序生成3个输入的序列:

  1. Select an item in a treeview 在树视图中选择一个项目
  2. Click a button 单击按钮
  3. Click another button 单击另一个按钮

The way it works is the button in step 2 performs an action depending on the item selected in the treeview in step 1. I am able to get the button clicks to work just fine by simply sending a message, but I cannot figure out how to select the TreeView item I want. 它的工作方式是步骤2中的按钮根据在步骤1中的树视图中选择的项目执行操作。我能够通过简单地发送消息使按钮单击工作得很好,但我无法弄清楚如何选择我想要的TreeView项目。 The TreeView is static, so the items and layout will never change. TreeView是静态的,因此项目和布局永远不会改变。 It has the following layout: 它有以下布局:

-itemsA -itemsA
-itemsB -itemsB
--itemB1 --itemB1
-itemsC -itemsC

Where itemB1 is the item that needs to be selected in order for the button clicks in steps 2 and 3 to work. 其中itemB1是需要选择的项目,以便步骤2和3中的按钮单击工作。 By default ItemsB is collapsed, so I probably need to expand it before I can select ItemB1? 默认情况下,ItemsB已折叠,因此我可能需要先展开它才能选择ItemB1? Here is my code. 这是我的代码。 I really appreciate any help!! 我非常感谢任何帮助!!

//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

Hans, 汉斯,

Can you give me an example of how I would do this? 你能给我一个如何做到这一点的例子吗? The problem I am really having is finding the handle for the treeview item I want to select. 我真正遇到的问题是找到我想要选择的树视图项的句柄。 If I use Spy++ to find the current handle and hardcode it into my method, it works fine, like this: 如果我使用Spy ++查找当前句柄并将其硬编码到我的方法中,它可以正常工作,如下所示:

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

If I use SendMessage and send TVGN_ROOT to the TreeView Handle, will it return an IntPtr with the handle for the item to select in the treeview, or how does that work? 如果我使用SendMessage并将TVGN_ROOT发送到TreeView句柄,它是否会返回一个IntPtr,其中包含要在树视图中选择的项目的句柄,或者它是如何工作的? I am also experimenting with AutoIt, but I was hoping to keep all of my code in one application. 我也在尝试使用AutoIt,但我希望将所有代码保存在一个应用程序中。

I figured it out, so Ill post for anyone else who is interested, I have had a hard time finding documentation on this. 我想通了,所以对于其他感兴趣的人来说,我发帖很难,我很难找到这方面的文件。 Here is the majority of my code: 这是我的大部分代码:

//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

I may still not understand this 100%, but hopefully this helps. 我可能仍然不理解这100%,但希望这有帮助。 The SendMessage return value will depend on what message you are sending, in this case, it was an int containing the handle of a TreeView item. SendMessage返回值取决于您发送的消息,在这种情况下,它是一个包含TreeView项的句柄的int。 The first argument is the handle to the TreeView itself. 第一个参数是TreeView本身的句柄。 The second argument is the Message you want to send. 第二个参数是您要发送的消息。 The 3rd and 4th arguments are flags. 第3和第4个参数是标志。 the 3rd specifys the type of item, the 4th is the handle of the current treeview item. 第3个指定项目的类型,第4个是当前树视图项目的句柄。

Thanks for the help Hans! 谢谢Hans的帮助! Anyone else, please feel free to elaborate. 其他人,请随时详细说明。

You'll need to walk the nodes with TVM_GETNEXTITEM, starting at TVGN_ROOT. 从TVGN_ROOT开始,您需要使用TVM_GETNEXTITEM遍历节点。 Then select it with TVM_SELECTITEM. 然后使用TVM_SELECTITEM选择它。 Pass the TVGN_FIRSTVISIBLE to ensure it is visible, shouldn't be necessary if you just automate it. 通过TVGN_FIRSTVISIBLE以确保它是可见的,如果您只是自动化它就不是必需的。

Take a look at AutoIt to avoid writing grungy code like this. 看看AutoIt,以避免像这样编写蹩脚的代码。

I know this is quite late in coming, but if you are having a similar issue (as am I). 我知道现在已经很晚了,但是如果你有类似的问题(就像我一样)。 You might take a look at AutoHotKey, especially if you are familiar with SendMessage. 您可以查看AutoHotKey,特别是如果您熟悉SendMessage。 This would save you the need to compile and a lot of complexity, but to your point it would be possible to navigate through the structure using arrow key presses. 这样可以节省编译的需要和很多复杂性,但是对于您的观点,可以使用箭头键按下导航结构。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM