刚开始到现在公司的时候接到一个任务:开发一个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();
WindowsAPI.PostMessage(cwnd, (int)WindowsAPI.WndMsg.WM_RBUTTONDOWN, (int)WindowsAPI.WndMsg.MK_RBUTTON, WindowsAPI.MAKELONG(, ));
WindowsAPI.PostMessage(cwnd, (int)WindowsAPI.WndMsg.WM_RBUTTONUP, (int)WindowsAPI.WndMsg.MK_RBUTTON, WindowsAPI.MAKELONG(, ));
}
System.Threading.Thread.Sleep();
hand = WindowsAPI.FindWindow("#32768", null);
IntPtr hMenu = WindowsAPI.SendMessage(hand, 0x01E1, , ); int n = WindowsAPI.GetMenuItemCount(hMenu);
var meg = new StringBuilder();
n = WindowsAPI.GetMenuString(hMenu, (uint)WindowsAPI.GetMenuItemID(hMenu, ), meg, , (uint));
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();
//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;
}, );
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();
//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;
}, ); return wndList;
}
源码就懒得发了,就这么几句,但是为了这几句代码,折腾的够呛,虽然以前用过VC++但是这么底层的API还真是没用过。。。