It is much easier to do the same with UI Automation .
using System.Windows.Automation; //.... var runWindow = AutomationElement.FromHandle(hWndtoolBar); var list = runWindow.FindAll(TreeScope.Subtree, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button)); if (list.Count > 1) { var button = list[1]; // выбираем вторую кнопку if (button.Current.IsEnabled) { var invokePattern = button.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern; invokePattern.Invoke(); } }
Do not forget to connect to the project Reference: UIAutomationClient, UIAutomationTypes.
If you use your approach, you must first obtain the coordinates of the button inside the toolbar window. For this, there is a
TB_GETITEMRECT message. It requires an input pointer. But you can't just pass an ordinary pointer, because are in the address space of another process. You need to allocate memory in the address space of the target process.
Then send WM_LBUTTONDOWN and WM_LBUTTONUP (emulate a click). You can still try TB_PRESSBUTTON, but it works since Vista.
[DllImport("user32.dll")] public static extern int GetWindowThreadProcessId(IntPtr handle, out int processId); [DllImport("kernel32.dll")] public static extern IntPtr OpenProcess( ProcessAccessFlags processAccess, bool bInheritHandle, int processId ); [DllImport("user32.dll")] public static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam); [DllImport("user32.dll", SetLastError = true)] static extern bool PostMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam); [DllImport("kernel32.dll", SetLastError = true)] static extern Int32 ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] buffer, UInt32 size, out IntPtr lpNumberOfBytesRead); [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, AllocationType flAllocationType, MemoryProtection flProtect); [DllImport("kernel32.dll")] public static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint dwFreeType); [DllImport("kernel32.dll")] public static extern bool CloseHandle(IntPtr handle); public enum VirtualFreeExTypes : uint { MEM_DECOMMIT = 0x4000, MEM_RELEASE = 0x8000 } [Flags] public enum AllocationType { Commit = 0x1000, Reserve = 0x2000, Decommit = 0x4000, Release = 0x8000, Reset = 0x80000, Physical = 0x400000, TopDown = 0x100000, WriteWatch = 0x200000, LargePages = 0x20000000 } [Flags] public enum MemoryProtection { Execute = 0x10, ExecuteRead = 0x20, ExecuteReadWrite = 0x40, ExecuteWriteCopy = 0x80, NoAccess = 0x01, ReadOnly = 0x02, ReadWrite = 0x04, WriteCopy = 0x08, GuardModifierflag = 0x100, NoCacheModifierflag = 0x200, WriteCombineModifierflag = 0x400 } [Flags] public enum ProcessAccessFlags : uint { All = 0x001F0FFF, Terminate = 0x00000001, CreateThread = 0x00000002, VirtualMemoryOperation = 0x00000008, VirtualMemoryRead = 0x00000010, VirtualMemoryWrite = 0x00000020, DuplicateHandle = 0x00000040, CreateProcess = 0x000000080, SetQuota = 0x00000100, SetInformation = 0x00000200, QueryInformation = 0x00000400, QueryLimitedInformation = 0x00001000, Synchronize = 0x00100000 } [StructLayout(LayoutKind.Sequential)] public struct RECT { public int Left, Top, Right, Bottom; } const int WM_USER = 0x0400; const int TB_GETITEMRECT = (WM_USER + 29); const int WM_LBUTTONDOWN = 0x0201; const int WM_LBUTTONUP = 0x0202; public static int MAKELONG(int x, int y) { return (x & 0xffff) | ((y & 0xffff) << 16); } public static RECT ByteArrayToRect(byte[] bytes) { GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); RECT stuff = (RECT)Marshal.PtrToStructure( handle.AddrOfPinnedObject(), typeof(RECT)); handle.Free(); return stuff; } static void Main(string[] args) { IntPtr ptr = WinAPI.FindWindow(null, "Выберите файл"); IntPtr window = FindWindowByIndex(ptr, 1, "ToolbarWindow32"); IntPtr nNumberOfBytesRead; int dwProcessID; GetWindowThreadProcessId(window, out dwProcessID); IntPtr hProcess = OpenProcess((ProcessAccessFlags.VirtualMemoryOperation | ProcessAccessFlags.VirtualMemoryRead | ProcessAccessFlags.VirtualMemoryWrite), false, dwProcessID); IntPtr Pointer = VirtualAllocEx(hProcess, (IntPtr)0, 4096, AllocationType.Reserve | AllocationType.Commit, MemoryProtection.ReadWrite); RECT bi; SendMessage(window, TB_GETITEMRECT, (IntPtr)1 /* индекс кнопки*/, (IntPtr)Pointer); byte[] buffer = new byte[16]; ReadProcessMemory(hProcess, (Pointer), buffer, (uint)buffer.Length, out nNumberOfBytesRead); bi = ByteArrayToRect(buffer); PostMessage(window, WM_LBUTTONDOWN, (IntPtr)0, (IntPtr)MAKELONG(bi.Left, bi.Top)); PostMessage(window, WM_LBUTTONUP, (IntPtr)0, (IntPtr)MAKELONG(bi.Left, bi.Top)); VirtualFreeEx(hProcess, Pointer, 0, (uint)VirtualFreeExTypes.MEM_RELEASE); CloseHandle(hProcess); }