刚开始到现在公司的时候接到一个任务:开发一个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 ListGetAllChildWindows(IntPtr handle) { List wndList = new List (); 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 GetAllDesktopWindows() { List wndList = new List (); //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还真是没用过。。。