【问题标题】:C# WinAPI Clicking on menu itemsC# WinAPI 单击菜单项
【发布时间】:2012-03-12 22:51:18
【问题描述】:

我正在尝试单击名为 Media Subtitler 的程序中的菜单项,但无论我尝试做什么,它都不起作用。

首先,我尝试使用函数 GetMenu,但它返回 IntPtr.Zero。 然后,我尝试使用 ALT 键 + 使用菜单的第一个字母(F 代表文件),但它什么也没做。 然后,我尝试使用简单的 MOUSEDOWN 和 MOUSEUP 消息,但又一次,它什么也没做(我还尝试创建一个循环,点击该范围内的所有内容,但该区域没有点击)。

我清楚地知道我正在使用正确的窗口。

我做错了什么?

如果有人想测试它,你可以免费下载 Media Subtitler,它的重量并不大。

另外,这是我一直在测试的代码:

Process p = Process.Start(@"C:\Program Files\DivXLand\Media Subtitler\MediaSub.exe");
        p.WaitForInputIdle(1500);
        Thread.Sleep(3000);

        SetForegroundWindow(p.MainWindowHandle);
        ShowWindow(p.MainWindowHandle, SW_MAXIMIZE);

        IntPtr handle = p.MainWindowHandle;

        SendMessage(handle, WM_NCHITTEST, 0, MakeLParam(18, 29));

        //for (int i = 0; i < 200; i++)
        //{
        //    for (int x = 0; x < 200; x++)
        //    {
        //        SendMessage(p.MainWindowHandle, WM_LBUTTONDOWN, 0, MakeLParam(i, x));
        //        SendMessage(p.MainWindowHandle, WM_LBUTTONUP, 0, MakeLParam(i, x));
        //    }
        //}
        //IntPtr menuItems = GetMenu(p.MainWindowHandle);
        return;
        //SendMessage(p.MainWindowHandle, WM_COMMAND, 6, 0);
        SendMessage(p.MainWindowHandle, WM_KEYDOWN, VK_MENU, 0);
        SendMessage(p.MainWindowHandle, WM_KEYUP, VK_MENU, 0);
        SendMessage(p.MainWindowHandle, WM_KEYDOWN, VK_F, 0);
        SendMessage(p.MainWindowHandle, WM_KEYUP, VK_F, 0);

感谢您的帮助!

【问题讨论】:

    标签: c# winapi menu automation


    【解决方案1】:

    通过监视发送到应用程序主窗口的消息,我提取了菜单项的菜单标识符。您可以将WM_COMMAND消息发布到窗口,菜单项的ID为wParam

    [DllImport("user32.dll")]
    public static extern IntPtr PostMessage(IntPtr hWnd, Message msg, int wParam, int lParam);
    
    PostMessage(handle, WM_COMMAND, 2, 0); // File->New subtitle
    
    PostMessage(handle, WM_COMMAND, 3, 0); // File->New from clipboard
    
    PostMessage(handle, WM_COMMAND, 5, 0); // File->Open text or subtitle
    
    PostMessage(handle, WM_COMMAND, 6, 0); // File->Open video
    
    ...
    

    我已经使用 Media Subtitler 测试了代码,它就像一个魅力!唯一不起作用的情况是,在 Windows Vista 或 7 上,您的目标程序以管理员身份运行,而您的 C# 程序不是。请注意这一点!

    可以通过监视WM_COMMAND 消息(使用 Spy++)轻松检查菜单 ID。
    您也可以使用SendMessage 代替PostMessage,但您的程序会冻结,直到用户关闭菜单操作打开的窗口。

    您可以使用相同的方法将其他命令发送到应用程序的其他窗口。例如,单击“打开视频”窗口的“打开”按钮。

    【讨论】:

    • 感谢您的回复。当我用 spy++ 查看程序时,我看不到菜单处理程序,你是如何找到它的?您还可以编写获取菜单处理程序的代码吗?谢谢。
    • 不需要获取菜单处理程序(尽管它在 spy++ 的窗口属性中可用)。我只是监视了窗口的消息。在 spy++ 中刷新窗口列表,单击Find Window 工具并将十字准线拖到您的窗口中。找到它后,右键单击它并选择Messages。在此窗口中,spy++ 显示所有消息已发送并发布到窗口。您可以通过从Messages 菜单 (Ctrl+O) 中选择 Logging options 来过滤消息。
    • 我在另一个相关程序中遇到了另一个小问题:我无法在“添加”选项卡和“字幕”区域中选中 AviReComp 程序中的复选框。那里的复选框称为启用/禁用。
    • 你能选中另一个复选框吗?请为此发布另一个问题。
    【解决方案2】:

    您也可以使用 System.Windows.Automation 命名空间来完成所有这些操作:http://msdn.microsoft.com/en-us/library/ms590934.aspx

    使用此命名空间,您无需与 Win32 API 进行任何互操作。下面是一个如何通过搜索其名称包含的字符串来获取窗口的示例:

    public static AutomationElement GetWindowByName(string name)
    {
        AutomationElement root = AutomationElement.RootElement;
        foreach (AutomationElement window in root.FindAll(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Window)))
        {
            if (window.Current.Name.Contains(name) && window.Current.IsKeyboardFocusable)
            {
                return window;
            }
        }
        return null;
    }
    

    将窗口作为 AutomationElement 对象后,您可以在其中搜索控件并对这些控件执行操作等。

    希望这会有所帮助!

    【讨论】:

    • 很好的提示,但请注意,此命名空间仅与 WPF Windows 相关
    【解决方案3】:

    在 Visual Studio 中有一个工具 Spy++,您应该可以使用它查看对象的句柄。 如果您在那里看到它,您应该可以使用 user32.dll 函数访问它

    [DllImport("user32.dll", SetLastError = true)]
    private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string className, string lpszWindow);
    

    找到它们(每次运行应用程序时,句柄都会有所不同) 如果你掌握了正确的句柄,你应该可以使用 SendMessage 发送回车,或者点击。

    只在一个应用上试过这个,我只用它来读写文本,如果它不起作用,很抱歉

    【讨论】:

    • 另一个有用的工具是如果你有Windows SDK 使用Insptect Objects(或旧版本中调用的UISpy)来查看窗口之间的关系。在编写自动化代码时非常有用。
    猜你喜欢
    • 2018-12-29
    • 2011-08-27
    • 2021-06-20
    • 2020-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-08
    • 2021-11-25
    相关资源
    最近更新 更多