Как нажатие на кнопку из .NET в хитром нативном окне?
От: StarLancer  
Дата: 08.07.11 09:41
Оценка:
Здравствуйте!

Переду сразу к делу, столкнулся с такой проблемой:
Как правильно нажать на кнопку в радной программе "Удаленный помощник" из Windows7.
Пытаюсь ее нажать следующим образом:
Освновной код:
namespace ConsoleFindWindows {
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Threading;

    internal sealed class Program {


        static void Main(string[] args) {
            Process[] ms = Process.GetProcessesByName("msra");
            Process msra = ms.Length > 0 ? ms[0] : Process.Start("msra", "/offerra");

            //Дожидаемся запуска
            Thread.Sleep(300);
            IntPtr hWndParent = msra.MainWindowHandle;

            #region Тут отрабатывает нажатие на кнопку Обзор в открытом окне Выполнить, если заранее его открыть

            IntPtr runWindowHandle = WinApi.FindWindow(null, "Выполнить");
            if (runWindowHandle != IntPtr.Zero) {
                IntPtr hButton = WinApi.FindWindowEx(runWindowHandle, IntPtr.Zero, "Button", "Об&зор...");
                PushButton(hButton);
            }

            #endregion

            //Получение списка всех handle-ов процесса
            List<IntPtr> handles = WinApi.GetChildWindows(hWndParent);

            //Перебераем список в поиска нужного handle
            foreach (IntPtr intPtr in handles) {
                //Поиска handle нужной кнопки
                IntPtr hWndChild = WinApi.FindWindowEx(intPtr, IntPtr.Zero, "Button", "Отмена");

                //Нашли нужный нам handle
                if (hWndChild != IntPtr.Zero) {
                    WinApi.SetForegroundWindow(hWndChild);

                    //Отправляем сообщение о нажатие кнопки
                    PushButton(hWndChild);
                }
            }

            Console.WriteLine("Нажмите любую клавишу для закрытия процесса");
            Console.ReadKey();
        }

        private static void PushButton(IntPtr handle) {
            //Переводим фокус на кнопку
            WinApi.SetFocus(handle);

            WinApi.PostMessage((Int32)handle, (int)WinApi.ButtonControlMessages.BM_CLICK, 0, IntPtr.Zero);
        }
    }
}


Вспомогательный код:
namespace ConsoleFindWindows {
    using System;
    using System.Collections.Generic;
    using System.Runtime.InteropServices;

    public static class WinApi {
        #region Delegates

        public delegate bool EnumWindowProc(IntPtr hWnd, IntPtr parameter);

        #endregion

        #region Enums

        public enum ButtonControlMessages : uint {
            BM_GETCHECK = 0x00F0,
            BM_SETCHECK = 0x00F1,
            BM_GETSTATE = 0x00F2,
            BM_SETSTATE = 0x00F3,
            BM_SETSTYLE = 0x00F4,
            BM_CLICK = 0x00F5,
            BM_GETIMAGE = 0x00F6,
            BM_SETIMAGE = 0x00F7
        }

        public enum GetWindow_Cmd : uint {
            GW_HWNDFIRST = 0,
            GW_HWNDLAST = 1,
            GW_HWNDNEXT = 2,
            GW_HWNDPREV = 3,
            GW_OWNER = 4,
            GW_CHILD = 5,
            GW_ENABLEDPOPUP = 6
        }

        public enum WindowsMessage : uint {
            WM_KEYDOWN = 256,
            WM_LBUTTONDOWN = 0x0201,
            WM_LBUTTONUP = 0x0202,
            WM_RBUTTONDOWN = 0x0204,
            WM_RBUTTONUP = 0x0205,
            WM_SETFOCUS = 0x0007,
            WM_ACTIVATE = 0x0006,
            WM_ENABLE = 0x000A
        }

        #endregion

        #region Public Methods

        [DllImport("user32")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr i);

        [DllImport("user32.dll")]
        public static extern IntPtr FindWindow(String lpClassName, String lpWindowName);

        [DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr FindWindowEx(
            IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);

        public static List<IntPtr> GetChildWindows(IntPtr parent) {
            var result = new List<IntPtr>();
            GCHandle listHandle = GCHandle.Alloc(result);
            try {
                EnumWindowProc childProc = EnumWindow;
                EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle));
            }
            finally {
                if (listHandle.IsAllocated) {
                    listHandle.Free();
                }
            }
            return result;
        }

        [DllImport("user32.dll", SetLastError = true)]
        public static extern int PostMessage(int hWnd, int msg, int wParam, IntPtr lParam);

        [DllImport("user32.dll")] //, CharSet = CharSet.Auto)]
        public static extern int SendMessage(int hWnd, UInt32 msg, Int32 wParam, IntPtr lParam);

        [DllImport("user32.dll")]
        public static extern IntPtr SetFocus(IntPtr hWnd);

        [DllImport("user32.dll")]
        public static extern int SetForegroundWindow(IntPtr hWnd);

        #endregion

        #region Methods

        private static bool EnumWindow(IntPtr handle, IntPtr pointer) {
            GCHandle gch = GCHandle.FromIntPtr(pointer);
            var list = gch.Target as List<IntPtr>;
            if (list == null) {
                throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");
            }
            list.Add(handle);
            //  You can modify this to check to see if you want to cancel the operation, then return a null here
            return true;
        }

        #endregion
    }
}


В чем может быть нюанс при отправке события о нажатии кнопки в "Удаленном помощнике"?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.