C # WinAPI By clicking on menu items

I am trying to click a menu item inside a program called Media Subtitler and all I am trying to do is not working.

At first I tried to use the GetMenu function, but it returned IntPtr.Zero. Then I tried using the ALT + key using the first letter of my menu (F means file), but did nothing. Then I tried using the simple messages MOUSEDOWN and MOUSEUP, but did nothing again (I also tried to create a loop that clicks on everything in this range, but there was no click in this area).

I clearly know that I am working on the right window.

What am I doing wrong?

If someone wants to test it, you can download Media Subtitler for free, and it is not so strong.

Also, here is the code I tested:

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); 

Thanks for any help!

+4
source share
3 answers

Controlling the messages sent to the main application window, I extracted the menu identifiers for the menu items. You can send WM_COMMAND message to the window with the identifier of the menu items as 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 ... 

I tested the code with Media Subtitler and it works like a charm! The only situation where this will not work is when in Windows Vista or Seven your target program works as Administrator, and you do not have a C # program. Remember this!

Menu identifiers can be easily verified by tracking the WM_COMMAND message (using Spy ++).
You can also use SendMessage instead of PostMessage , but then your program freezes until the user closes the window opened by the menu action.

You can use the same approach to send another command to other application windows. For example, by clicking the "Open" button in the "Open Video" window.

+6
source

You can also use all of this using the System.Windows.Automation namespace: http://msdn.microsoft.com/en-us/library/ms590934.aspx

Using this namespace, you do not need to interact with the Win32 API. Here is an example of how to get a window by searching for a string containing its name:

 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; } 

After you have a window as an AutomationElement object, you can search for it for controls and perform operations on these controls, etc.

Hope this helps!

+4
source

Visual Studio has a Spy ++ tool with which you can see an object descriptor. If you see it there, you can access it using the user32.dll function

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

to get to them (the descriptor will be different every time your application starts) If you get the correct descriptor, you can use SendMessage to send input or click.

I tried this in only one application, and I used it only for reading and writing text, so sorry if it does not work

0
source

Source: https://habr.com/ru/post/1397843/


All Articles