C#WinAPI单击菜单项

时间:2012-02-22 15:26:46

标签: c# winapi menu automation

我正在尝试点击名为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);

感谢您的帮助!

3 个答案:

答案 0 :(得分:6)

通过监控发送到应用程序主窗口的消息,我提取了菜单项的菜单标识符。您可以将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或Seven上,你的目标程序是以管理员身份运行而你的C#程序不是。请注意这一点!

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

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

答案 1 :(得分:5)

您还可以使用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对象后,可以在其中搜索控件并对这些控件执行操作等。

希望这有帮助!

答案 2 :(得分:0)

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

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

到达他们(每次运行你的应用程序时句柄都会有所不同) 如果你得到了正确的句柄,你应该能够使用SendMessage发送回车,或点击。

仅在一个应用程序上尝试过此操作,我只用它来读取和写入文本,如果它不能正常工作,那就很抱歉