C#WinAPI单击菜单项

Imr*_*arr 4 c# winapi automation menu

我试图点击一个名为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);
Run Code Online (Sandbox Code Playgroud)

谢谢你的帮助!

Moh*_*han 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

...
Run Code Online (Sandbox Code Playgroud)

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

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

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


小智 5

您还可以使用System.Windows.Automation命名空间完成所有这些操作:http : //msdn.microsoft.com/zh-cn/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;
}
Run Code Online (Sandbox Code Playgroud)

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

希望这可以帮助!