【问题标题】:How to select an item in a TreeView using Win32 API如何使用 Win32 API 在 TreeView 中选择项目
【发布时间】:2010-09-07 16:24:41
【问题描述】:

我正在尝试使用 Win32 API 将一系列用户输入自动化到 C# 中已编译的应用程序中。我没有我试图控制的应用程序的任何源代码,它在我试图控制它时正在运行。在我的代码中,我有一个按钮,当单击该按钮时,需要对我要控制的应用程序进行 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,但我希望将所有代码保存在一个应用程序中。

【问题讨论】:

    标签: c# api winapi c#-4.0


    【解决方案1】:

    我想通了,所以我会为其他感兴趣的人发帖,我很难找到这方面的文档。这是我的大部分代码:

    //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 返回值将取决于您发送的消息,在这种情况下,它是一个包含 TreeView 项句柄的 int。第一个参数是 TreeView 本身的句柄。第二个参数是您要发送的消息。第三和第四个参数是标志。第3个指定item的类型,第4个是当前treeview item的句柄。

    感谢汉斯的帮助!其他人,请随时详细说明。

    【讨论】:

      【解决方案2】:

      您需要使用 TVM_GETNEXTITEM 遍历节点,从 TVGN_ROOT 开始。然后使用 TVM_SELECTITEM 选择它。传递 TVGN_FIRSTVISIBLE 以确保它是可见的,如果你只是自动化它应该没有必要。

      看看 AutoIt 以避免编写像这样邋遢的代码。

      【讨论】:

      • 你能举个例子说明我会怎么做吗?我真正遇到的问题是找到要选择的树视图项的句柄。如果我使用 Spy++ 查找当前句柄并将其硬编码到我的方法中,它可以正常工作,如下所示: SendMessage((int)treeChild, TV_SELECTITEM, TVGN_CARET, (IntPtr)0x092DCB30);如果我使用 SendMessage 并将 TVGN_ROOT 发送到 TreeView 句柄,它是否会返回一个 IntPtr 以及要在树视图中选择的项目的句柄,或者它是如何工作的?我也在尝试使用 AutoIt,但我希望将所有代码保存在一个应用程序中。
      • TVGN_ROOT 是一个标志,而不是一条消息。 TVM_GETNEXTITEM 是消息。如果您需要有关代码的帮助,请将其发布在您的问题中。
      • 我的错误。第一次在论坛发帖。
      【解决方案3】:

      我知道这已经很晚了,但是如果您遇到类似的问题(我也是)。你可以看看 AutoHotKey,特别是如果你熟悉 SendMessage。这将节省您编译的需要和很多复杂性,但就您而言,可以使用箭头键在结构中导航。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-11-26
        • 2010-10-30
        • 1970-01-01
        • 2011-02-23
        • 1970-01-01
        • 2014-05-21
        • 2010-11-05
        相关资源
        最近更新 更多