c# - 如何使用 Win32 API 在 TreeView 中选择一个项目

标签 c# api winapi c#-4.0

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

  1. 在 TreeView 中选择一个项目
  2. 点击一个按钮
  3. 点击另一个按钮

它的工作方式是第 2 步中的按钮根据第 1 步中在 TreeView 中选择的项目执行操作。我可以通过简单地发送消息来使按钮点击正常工作,但我无法确定了解如何选择我想要的 TreeView 项目。 TreeView 是静态的,因此项目和布局永远不会改变。它具有以下布局:

-itemsA
-元素B
--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

汉斯,

您能举例说明我将如何做到这一点吗?我真正遇到的问题是找到我要选择的 TreeView 项的句柄。如果我使用 Spy++ 找到当前句柄并将其硬编码到我的方法中,它工作正常,如下所示:

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

如果我使用 SendMessage 并将 TVGN_ROOT 发送到 TreeView 句柄,它是否会返回一个 IntPtr 以及 TreeView 中要选择的项目的句柄,或者这是如何工作的?我也在尝试使用 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 本身的句柄。第二个参数是您要发送的消息。第三个和第四个参数是标志。第三个指定项目的类型,第四个是当前 TreeView 项目的句柄。

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

关于c# - 如何使用 Win32 API 在 TreeView 中选择一个项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3660556/

相关文章:

java - 如何为任何网站创建 API?

java - 如何使用 JsonReader 解析嵌套的键和值?

api - Laravel 5.3,使用 api.example.com 到 example.com/api

msbuild - 如何在 MSBuild 中使用特定的 Windows SDK?

c# - .NET 异常窗口 API

c# - 递归与迭代速度的不一致

c# - 如何循环遍历XML中的所有节点并根据C#中的值更改节点值?

c# - 当我在 DataGridTemplateColumn.CellTemplate 中使用 TextBox 时,DataGrid.BeginningEdit 事件未触发

c++ - 单击几下后 WinAPI 菜单卡住

c++ - 使用 WinApi C++ 拖放 outlook 联系人