C#WinAPI单击菜单项

C#WinAPI单击菜单项,c#,winapi,menu,automation,C#,Winapi,Menu,Automation,我试着点击一个叫做Media Subtitler的程序中的菜单项,不管我想做什么,它都不起作用 首先,我尝试使用函数GetMenu,但它返回IntPtr.Zero。 然后,我尝试使用ALT键+使用我菜单的第一个字母(F代表文件),但没有任何效果。 然后,我尝试使用一个简单的MOUSEDOWN和MOUSEUP消息,但同样,它没有做任何事情(我还尝试创建一个循环,单击该范围内的所有内容,但在该区域没有单击) 我清楚地知道,我正在使用正确的窗口 我做错了什么 若有人想测试它,你们可以免费下载媒体字幕,

我试着点击一个叫做Media Subtitler的程序中的菜单项,不管我想做什么,它都不起作用

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

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

我做错了什么

若有人想测试它,你们可以免费下载媒体字幕,它的重量并没有那个么大

此外,以下是我一直在测试的代码:

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);
Process p=Process.Start(@“C:\Program Files\DivXLand\Media subtitr\MediaSub.exe”);
p、 等待输入(1500);
睡眠(3000);
SetForegroundWindow(p.MainWindowHandle);
显示窗口(p.MainWindowHandle,SW_最大化);
IntPtr handle=p.MainWindowHandle;
SendMessage(handle,WM_NCHITTEST,0,MakeLParam(18,29));
//对于(int i=0;i<200;i++)
//{
//对于(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);
返回;
//SendMessage(p.MainWindowHandle,WM_命令,6,0);
SendMessage(p.MainWindowHandle,WM_键下,VK_菜单,0);
SendMessage(p.MainWindowHandle,WM_键控,VK_菜单,0);
SendMessage(p.MainWindowHandle,WM_KEYDOWN,VK_F,0);
SendMessage(p.MainWindowHandle,WM_KEYUP,VK_F,0);

谢谢你的帮助

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

[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string className, string lpszWindow);
访问它们(每次运行应用程序时,句柄都会不同) 如果获得了正确的句柄,则应该能够使用SendMessage发送enter或单击


仅在一个应用程序上尝试了此操作,我仅将其用于读取和写入文本,因此,如果此操作不起作用,很抱歉

您也可以使用System.Windows.Automation命名空间执行所有操作:

使用此命名空间,您不需要与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对象后,可以在其中搜索控件并对这些控件执行操作,等等


希望这有帮助

通过监视发送到应用程序主窗口的消息,我提取了菜单项的菜单标识符。您可以将
WM_命令
消息发布到窗口,菜单项的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

...
我已经用媒体字幕测试了代码,它工作起来很有魅力!唯一的情况是,在windows Vista或7上,您的目标程序以管理员身份运行,而您的C#程序不运行。请注意这一点

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


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

另一个有用的工具是使用Insptect对象(或旧版本中的UISpy)查看窗口之间的关系。在编写自动化代码时非常有用。谢谢回复。当我用spy++查看程序时,我看不到菜单处理程序,您是如何找到它的?您还可以编写获取菜单处理程序的代码吗?谢谢。不需要获取菜单处理程序(尽管它在spy++的窗口属性中可用)。我只是监视窗口的消息。在spy++中刷新窗口列表,单击
查找窗口
工具,并将十字线拖动到您的窗口。找到它后,右键单击它并选择
消息
。在此窗口中,spy++显示所有发送并发布到窗口的消息。您可以通过从
消息
菜单(Ctrl+O)中选择
日志记录选项
来过滤消息。另一个相关程序存在另一个小问题:我无法选中“添加”选项卡和“字幕”区域中AvireMap程序中的复选框。那里的复选框称为启用/禁用。您可以选中其他复选框吗?请发布另一个问题。当然。这是一个很好的提示,但是请注意,这个名称空间只与WPF窗口相关