剛開始到現在公司的時候接到一個任務:開發一個activex控件,自動操作本地exe程序,當時遇到彈出菜單無法獲取的問題,還好不影響,最近又遇到這個問題,繞不過去了,於是昨天花了一個上午百度了個遍,總算解決了。。。網上也有人遇到類似的問題,但是都沒人給出一個完整解決方案來,所以記錄下來,以備后用。
核心代碼:windows系統其實只有一個彈出菜單,類型為#32768,但是FindWindow獲取的是窗口句柄,需要發送MN_GETHMENU 0x01E1消息轉換成菜單句柄,然后通過菜單的API進行其他操作,這里是獲取的菜單的文字內容
var hand = WindowsAPI.FindWindow("Notepad", "無標題 - 記事本"); WindowsAPI.SetForegroundWindow(hand); var cwnd = WindowsAPI.FindWindowEx(hand, IntPtr.Zero, "Edit", null); { System.Threading.Thread.Sleep(100); WindowsAPI.PostMessage(cwnd, (int)WindowsAPI.WndMsg.WM_RBUTTONDOWN, (int)WindowsAPI.WndMsg.MK_RBUTTON, WindowsAPI.MAKELONG(100, 100)); WindowsAPI.PostMessage(cwnd, (int)WindowsAPI.WndMsg.WM_RBUTTONUP, (int)WindowsAPI.WndMsg.MK_RBUTTON, WindowsAPI.MAKELONG(100, 100)); } System.Threading.Thread.Sleep(100); hand = WindowsAPI.FindWindow("#32768", null); IntPtr hMenu = WindowsAPI.SendMessage(hand, 0x01E1, 0, 0); int n = WindowsAPI.GetMenuItemCount(hMenu); var meg = new StringBuilder(100); n = WindowsAPI.GetMenuString(hMenu, (uint)WindowsAPI.GetMenuItemID(hMenu, 0), meg, 100, (uint)0); MessageBox.Show(meg.ToString());
API封裝
//查找指定窗體 [DllImport("User32.dll", EntryPoint = "FindWindow")] public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); //發送窗口消息 [DllImport("user32.dll", EntryPoint = "SendMessage")] public static extern IntPtr SendMessage(IntPtr hwnd, int wMsg, int wParam, uint lParam); public enum WndMsg { WM_CLICK = 0x00F5, WM_LBUTTONDOWN = 0x0201, WM_LBUTTONUP = 0x202, WM_RBUTTONDOWN = 0x0204, WM_RBUTTONUP = 0x205, MK_LBUTTON = 0x0001, MK_RBUTTON = 0x0002, WM_SETTEXT = 0x000C, BM_CLICK = 0xF5 } [DllImport("USER32.dll", EntryPoint = "GetMenuItemCount", CharSet = CharSet.Unicode)] public static extern int GetMenuItemCount(IntPtr hMenu); [DllImport("User32.dll")] public static extern IntPtr GetSystemMenu(IntPtr hWnd, Int32 bRevert); [DllImport("User32.dll")] public static extern int GetMenuString(IntPtr hMenu, uint uIDItem, StringBuilder lpString, int nMaxCount, uint uFlag); [DllImport("User32.dll")] public static extern int GetMenuItemID(IntPtr hMenu, int nPos);
其他一些常用API封裝
//讀寫ini文件 [DllImport("kernel32")] public static extern bool WritePrivateProfileString(string section, string key, string val, string filePath); [DllImport("kernel32")] public static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retStr, int size, string filePath); private delegate bool WNDENUMPROC(IntPtr hWnd, int lParam); [DllImport("user32.dll", ExactSpelling = true)] private static extern bool EnumChildWindows(IntPtr hwndParent, WNDENUMPROC lpEnumFunc, int lParam); [DllImport("user32.dll")] private static extern bool EnumWindows(WNDENUMPROC lpEnumFunc, int lParam); //[DllImport("user32.dll")] //private static extern IntPtr FindWindowW(string lpClassName, string lpWindowName); [DllImport("user32.dll")] private static extern int GetWindowTextW(IntPtr hWnd, [MarshalAs(UnmanagedType.LPWStr)]StringBuilder lpString, int nMaxCount); [DllImport("user32.dll")] private static extern int GetClassNameW(IntPtr hWnd, [MarshalAs(UnmanagedType.LPWStr)]StringBuilder lpString, int nMaxCount); public struct WindowInfo { public IntPtr hWnd; public string szWindowName; public string szClassName; } //遍歷窗口子窗口控件 public static List<WindowInfo> GetAllChildWindows(IntPtr handle) { List<WindowInfo> wndList = new List<WindowInfo>(); EnumChildWindows(handle, delegate(IntPtr hWnd, int lParam) { WindowInfo wnd = new WindowInfo(); StringBuilder sb = new StringBuilder(256); //get hwnd wnd.hWnd = hWnd; //get window name GetWindowTextW(hWnd, sb, sb.Capacity); wnd.szWindowName = sb.ToString(); //get window class GetClassNameW(hWnd, sb, sb.Capacity); wnd.szClassName = sb.ToString(); //add it into list wndList.Add(wnd); return true; }, 0); return wndList; } public static List<WindowInfo> GetAllDesktopWindows() { List<WindowInfo> wndList = new List<WindowInfo>(); //enum all desktop windows EnumWindows(delegate(IntPtr hWnd, int lParam) { WindowInfo wnd = new WindowInfo(); StringBuilder sb = new StringBuilder(256); //get hwnd wnd.hWnd = hWnd; //get window name GetWindowTextW(hWnd, sb, sb.Capacity); wnd.szWindowName = sb.ToString(); //get window class GetClassNameW(hWnd, sb, sb.Capacity); wnd.szClassName = sb.ToString(); //add it into list wndList.Add(wnd); return true; }, 0); return wndList; }
源碼就懶得發了,就這么幾句,但是為了這幾句代碼,折騰的夠嗆,雖然以前用過VC++但是這么底層的API還真是沒用過。。。