我正在尝试点击名为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);
感谢您的帮助!
答案 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发送回车,或点击。
仅在一个应用程序上尝试过此操作,我只用它来读取和写入文本,如果它不能正常工作,那就很抱歉