C# 如何使用Win32 API在树视图中选择项目

C# 如何使用Win32 API在树视图中选择项目,c#,api,winapi,c#-4.0,C#,Api,Winapi,C# 4.0,我正在尝试使用Win32 API在C#中自动化用户对已编译应用程序的输入序列。我没有我试图控制的应用程序的任何源代码,它在我试图控制它时正在运行。在我的代码中,我有一个按钮,单击该按钮时,需要对我试图控制的应用程序进行一系列3个输入: 在树视图中选择一个项目 点击按钮 单击另一个按钮 其工作方式是步骤2中的按钮根据步骤1中树状视图中选择的项目执行操作。我可以通过发送一条消息让按钮点击正常工作,但我不知道如何选择我想要的TreeView项目。树视图是静态的,因此项目和布局永远不会更改。其布局如下:

我正在尝试使用Win32 API在C#中自动化用户对已编译应用程序的输入序列。我没有我试图控制的应用程序的任何源代码,它在我试图控制它时正在运行。在我的代码中,我有一个按钮,单击该按钮时,需要对我试图控制的应用程序进行一系列3个输入:

  • 在树视图中选择一个项目
  • 点击按钮
  • 单击另一个按钮
  • 其工作方式是步骤2中的按钮根据步骤1中树状视图中选择的项目执行操作。我可以通过发送一条消息让按钮点击正常工作,但我不知道如何选择我想要的TreeView项目。树视图是静态的,因此项目和布局永远不会更改。其布局如下:

    -项目a
    -项目b
    --项目B1
    -项目c

    其中,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
    
    汉斯


    你能给我举个例子说明我会怎么做吗?我真正遇到的问题是找到要选择的treeview项的句柄。如果我使用Spy++查找当前句柄,并将其硬编码到我的方法中,它工作正常,如下所示:

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

    如果我使用SendMessage并将TVGN_ROOT发送到TreeView句柄,它会返回一个IntPtr,其中包含要在TreeView中选择的项的句柄,或者它是如何工作的?我也在尝试AutoIt,但我希望将所有代码都保存在一个应用程序中。

    您需要使用TVM\u GETNEXTITEM遍历节点,从TVGN\u根开始。然后用TVM\U SELECTITEM选择它。传递TVGN_FIRSTVISIBLE以确保其可见,如果您只是将其自动化,则不必这样做


    请看一下AutoIt,以避免编写像这样冗长的代码。

    我找到了它,所以我将向其他感兴趣的人发布,我很难找到关于它的文档。以下是我的大部分代码:

    //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本身的句柄。第二个参数是要发送的消息。第三个和第四个参数是标志。第三个指定项的类型,第四个是当前树视图项的句柄


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

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

    您能给我一个例子说明我是如何做到这一点的吗?我真正遇到的问题是找到要选择的treeview项的句柄。如果我使用Spy++查找当前句柄并将其硬编码到我的方法中,它工作得很好,如下所示:SendMessage((int)treeChild,TV_SELECTITEM,TVGN_CARET,(IntPtr)0x092DCB30);如果我使用SendMessage并将TVGN_ROOT发送到TreeView句柄,它会返回一个IntPtr,其中包含要在TreeView中选择的项的句柄,或者它是如何工作的?我也在尝试AutoIt,但我希望将所有代码都保存在一个应用程序中。TVGN_ROOT是一个标志,而不是一条消息。TVM_GETNEXTITEM是消息。如果你想得到代码方面的帮助,就把它贴在你的问题上。我错了。第一次发布到论坛。