重拾Csharp操控IE浏览器(二)功夫还在IE外

上篇文章https://www.cnblogs.com/pu369/p/12343259.html主要是对SHDocVw.InternetExplorer的控制,然而有时还需一些win32API才能真正实际完全自动化操作(必要时用spy++查看窗体层次)。

一些DllImport(在 public partial class Form1 : Form中):

 [DllImport("user32.dll")]
        private static extern bool EnumWindows(WNDENUMPROC lpEnumFunc, int lParam);
        private delegate bool WNDENUMPROC(IntPtr hWnd, int lParam);
        //寻找目标进程窗口
        [DllImport("User32.dll", EntryPoint = "FindWindow")]
        public extern static IntPtr FindWindow(string lpClassName, string lpWindowName);
        //设置进程窗口到最前       
        [DllImport("USER32.DLL")]
        public static extern bool SetForegroundWindow(IntPtr hWnd);
        //模拟键盘事件         
        [DllImport("USER32.DLL")]
        public static extern void keybd_event(Byte bVk, Byte bScan, Int32 dwFlags, Int32 dwExtraInfo);
        public delegate bool CallBack(IntPtr hwnd, int lParam);
        [DllImport("USER32.DLL")]
        public static extern int EnumChildWindows(IntPtr hWndParent, CallBack lpfn, int lParam);
        public delegate bool EnumChildWindow(IntPtr WindowHandle, string num);
        //给CheckBox发送信息
        [DllImport("USER32.DLL", EntryPoint = "SendMessage", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern int SendMessage(IntPtr hwnd, UInt32 wMsg, int wParam, int lParam);
        //给Text发送信息
        [DllImport("USER32.DLL", EntryPoint = "SendMessage")]
        private static extern int SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, string lParam);
        [DllImport("USER32.DLL")]
        public static extern IntPtr GetWindow(IntPtr hWnd, int wCmd);

        [DllImport("User32.dll", EntryPoint = "FindWindowEx")]
        public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, 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);


       //函数原型;DWORD GetWindowThreadProcessld(HWND hwnd,LPDWORD lpdwProcessld);
        //参数:
        //hWnd:窗口句柄。
        //lpdwProcessld:接收进程标识的32位值的地址。如果这个参数不为NULL,GetWindwThreadProcessld将进程标识拷贝到这个32位值中,否则不拷贝。
        //返回值:返回值为创建窗口的线程标识。
        //C#中使用该函数首先导入命名空间:using System.Runtime.InteropServices;然后写API引用部分的代码,放入 class 内部
         [DllImport("User32.dll", CharSet = CharSet.Auto)]
          public static extern int GetWindowThreadProcessId(IntPtr hwnd, out int ID);
       

1、寻找系统的全部窗体

 static WindowInfo[] GetAllDesktopWindows()
        {
            List<WindowInfo> wndList = new List<WindowInfo>();
            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();
                Console.WriteLine("Window handle=" + wnd.hWnd.ToString().PadRight(20) + " szClassName=" + wnd.szClassName.PadRight(20) + " szWindowName=" + wnd.szWindowName);
                //add it into list
                wndList.Add(wnd);
                return true;
            }, 0);
            return wndList.ToArray();
        }
//保存窗体信息的struct
    public struct WindowInfo
    {
        public IntPtr hWnd;
        public string szWindowName;
        public string szClassName;
    }

用上面的代码,实现获取所有窗体信息

        private void testToolStripMenuItem_Click_2(object sender, EventArgs e)
        {
            var all = GetAllDesktopWindows();
            string s="" ;
            foreach(var b in all)
            {
                s = s +b.hWnd.ToString() + " ||| " +  b.szClassName +" ||| " +b.szWindowName +"
";
            }
            using (StreamWriter sw = new StreamWriter(@"temp.txt", true)) { sw.WriteLine(s); }
            MessageBox.Show("所有窗体信息保存到当前目录temp.txt ");
        }

用上面的代码,实现根据部分标题找窗体

 private void 根据部分标题找窗口ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show("请设置断点查看");
            //枚举窗口,并显示名称和hWnd
            List<string> result = new List<string>();
            WindowInfo[] a = GetAllDesktopWindows();
            int i = 0;
            string s = this.textBox1.Text.Trim();
           
            for (i = 0; i < a.Length; i++)
            {
                if (a[i].szWindowName.Contains(s))
                {
                    string msg = "hwnd:" + a[i].hWnd + "  窗口类:" + a[i].szClassName + "  标题:" + a[i].szWindowName;
                   // MessageBox.Show(msg);
                    result.Add(msg);
                }    
            }
            //请在下一行设置断点           
         }

2、打开另一个窗体Form

     private void button1_Click(object sender, EventArgs e)
        {            
            Form2 f2 = new Form2();
            f2.Show();
        }

3、枚举电脑上所有进程

        private void processToolStripMenuItem_Click_1(object sender, EventArgs e)
        {
            MessageBox.Show("请设置断点查看");
            //枚举进程名和_Handle
            string s = "";
            Process[] app = Process.GetProcesses();
            List<string> li = new List<string>();
            foreach (Process p in app)
            {
                try
                {
                    s = "进程名:" + p.ProcessName + "  ______________ 进程句柄_Handle:" + p.Handle;
                    li.Add(s);
                }
                catch (Exception e1) { e.ToString(); }

            }
            var aproess = li;
            //请在下一行设置断点     
        }

4、用FindWindow根据主窗口标题查找窗体hwnd,再用GetWindowThreadProcessId根据hwnd找进程ID,再用Process.GetProcessById(进程ID).MainWindowTitle得到主窗口标题

 private void poocessIDToolStripMenuItem1_Click(object sender, EventArgs e)
        { 
            //获取计算器窗口句柄 ,需要先打开计算器  
            IntPtr hwnd = FindWindow(null, "计算器");
            if (hwnd != IntPtr.Zero)
            {
                int calcID;
                //获取进程ID   
                GetWindowThreadProcessId(hwnd, out calcID);
                MessageBox.Show("FindWindow找出计算器hwnd,再GetWindowThreadProcessId得到进程ID:" + calcID.ToString());
                string t = Process.GetProcessById(calcID).MainWindowTitle;
                MessageBox.Show("GetProcessById得到计算器MainWindowTitle:" + t);

            }
            else
            {
                MessageBox.Show("没有找到计算器窗口");
            }
        }

5、控制计算器做加法

        private void testToolStripMenuItem_Click_2(object sender, EventArgs e)
        {
            //根据输入框内容,找有窗口标题符合的窗口
            string title = "计算器";           
            //获取窗口句柄   
            IntPtr hwnd = FindWindow(null, title);
            if (hwnd != IntPtr.Zero)
            {
                SetForegroundWindow(hwnd);               
                System.Windows.Forms.SendKeys.SendWait("12");
                System.Threading.Thread.Sleep(1000);
                System.Windows.Forms.SendKeys.SendWait("{ADD}");
                System.Threading.Thread.Sleep(1000);
                System.Windows.Forms.SendKeys.SendWait("23");               
                System.Threading.Thread.Sleep(1000);
                //System.Windows.Forms.SendKeys.SendWait("{TAB}");
                System.Windows.Forms.SendKeys.SendWait("{ENTER}");
            }
            else
            {
                MessageBox.Show("没有找到"+title+"窗口");
            }
        }

6、点击 windows 安全 窗口上的 确定 按钮

        private void testToolStripMenuItem_Click_2(object sender, EventArgs e)
        {
            //查找Windows 安全,点确定确认证书
            IntPtr hwnd = FindWindow(null, "Windows 安全");
            IntPtr childHwnd = FindWindowEx(hwnd, IntPtr.Zero, "DirectUIHWND", null);
            IntPtr childHwnd3_1 = FindWindowEx(childHwnd, IntPtr.Zero, "CtrlNotifySink", null);
            IntPtr childHwnd3_2 = FindWindowEx(childHwnd, childHwnd3_1, "CtrlNotifySink", null);
            IntPtr childHwnd3_3 = FindWindowEx(childHwnd, childHwnd3_2, "CtrlNotifySink", null);
            IntPtr childHwnd3_3_ok = FindWindowEx(childHwnd3_3, IntPtr.Zero, null, null);
            //uint WM_SETTEXT = 0xC;
            //SendMessage(editor, WM_SETTEXT, IntPtr.Zero, "username");
            uint BM_CLICK = 0x00F5;
            SendMessage(childHwnd3_3_ok, BM_CLICK, 0, 0);     //发送点击按钮的消息   
        }

7、批量生成目录

       private void 生成目录名ToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            List<string> lis = new List<string>() { "目录1", "目录2", "目录3" };
            foreach (string li in lis)
            {
                if (!Directory.Exists(@"Y:" + li))
                {
                    Directory.CreateDirectory(@"Y:" + li);
                }
            }
        }

8、窗口前置

SetForegroundWindow(hwnd);  

9、发邮件

 private void 发邮件ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //实例化一个发送邮件类。
            MailMessage mailMessage = new MailMessage();
            //发件人邮箱地址,方法重载不同,可以根据需求自行选择。
            mailMessage.From = new MailAddress("XXX@qq.com");
            //收件人邮箱地址。
            mailMessage.To.Add(new MailAddress("XXX@qq.com"));
            //邮件标题。
            mailMessage.Subject = "发送邮件测试-发给自己";
            //邮件内容。
            mailMessage.Body = "这是我给我自己发送的第一份邮件哦!";

            //实例化一个SmtpClient类。
            SmtpClient client = new SmtpClient();
            //在这里我使用的是qq邮箱,所以是smtp.qq.com,如果你使用的是126邮箱,那么就是smtp.126.com。
            client.Host = "smtp.qq.com";
            //使用安全加密连接。
            client.EnableSsl = true;
            //不和请求一块发送。           
            client.UseDefaultCredentials = false;
            //验证发件人身份(发件人的邮箱,邮箱里的生成授权码);
            client.Credentials = new NetworkCredential("XX@qq.com", "apueXXXd");
            //发送
            client.Send(mailMessage);
            MessageBox.Show("发送成功");
        }

10、鼠标模拟点击

        private void testToolStripMenuItem_Click_2(object sender, EventArgs e)
        {
            MouseMove m = new MouseMove();
            m.MouseMoveAndClick(1436, 357);
        }
    class MouseMove
    {
        #region MouseEvent
        [System.Runtime.InteropServices.DllImport("user32")]
        private static extern int mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);
        //移动鼠标 
        const int MOUSEEVENTF_MOVE = 0x0001;
        //模拟鼠标左键按下 
        const int MOUSEEVENTF_LEFTDOWN = 0x0002;
        //模拟鼠标左键抬起 
        const int MOUSEEVENTF_LEFTUP = 0x0004;
        //模拟鼠标右键按下 
        const int MOUSEEVENTF_RIGHTDOWN = 0x0008;
        //模拟鼠标右键抬起 
        const int MOUSEEVENTF_RIGHTUP = 0x0010;
        //模拟鼠标中键按下 
        const int MOUSEEVENTF_MIDDLEDOWN = 0x0020;
        //模拟鼠标中键抬起 
        const int MOUSEEVENTF_MIDDLEUP = 0x0040;
        //标示是否采用绝对坐标 
        const int MOUSEEVENTF_ABSOLUTE = 0x8000;
        #endregion
        //这个区域包括任务栏,就是屏幕显示的物理范围
        struct ScreenWH
        {
            //非静态变量不能直接赋值
            public static int x = Screen.PrimaryScreen.Bounds.Width;  //屏幕宽度 
            public static int y = Screen.PrimaryScreen.Bounds.Height;  //屏幕宽度 
        }       
        //x,y是鼠标在屏幕的位置,屏幕左上角为0,0点
        public void MouseMoveAndClick(int _x, int _y)
        {
            mouse_event(MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE, _x * 65535 / ScreenWH.x, _y * 65535 / ScreenWH.y, 0, 0);
            mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
        }
    }

11、模拟键盘CTRL+V粘贴操作

       private void textBox1_DoubleClick(object sender, EventArgs e)
        {
            Clipboard.SetDataObject("HELLO WORLD!!!", true);
            KeyBordClick k = new KeyBordClick();
            k.KeyBordPaste();

        }
    class KeyBordClick
    {
        [DllImport("user32.dll", EntryPoint = "keybd_event", SetLastError = true)]
        private static extern void keybd_event(Keys bVk, byte bScan, uint dwFlags, uint dwExtraInfo);
        const int KEYEVENTF_KEYUP = 0x02;
        const int KEYEVENTF_KEYDOWN = 0x00;

        //相当于按下ctrl+v,然后回车
        public void KeyBordPaste()
        {
            keybd_event(Keys.ControlKey, 0, KEYEVENTF_KEYDOWN, 0);
            keybd_event(Keys.V, 0, 0, 0);
            keybd_event(Keys.ControlKey, 0, KEYEVENTF_KEYUP, 0);
            keybd_event(Keys.Enter, 0, 0, 0);
        }
    }

12、屏幕截图,并设为当前form的背景

      private void testToolStripMenuItem_Click_2(object sender, EventArgs e)
        {
            this.BackgroundImage = CaptureScreen.CaptureScreenA();
        }
    class CaptureScreen
    {
        /// <summary>
        /// 截屏幕成为图像返回
        /// </summary>
        /// <returns></returns>
        public static Image CaptureScreenA()
        {
            //屏幕宽
            int iWidth = Screen.PrimaryScreen.Bounds.Width;
            //屏幕高
            int iHeight = Screen.PrimaryScreen.Bounds.Height;
            //按照屏幕宽高创建位图
            Image img = new Bitmap(iWidth, iHeight);
            //从一个继承自Image类的对象中创建Graphics对象
            Graphics gc = Graphics.FromImage(img);
            //抓屏并拷贝到myimage里
            gc.CopyFromScreen(new Point(0, 0), new Point(0, 0), new Size(iWidth, iHeight));
              //保存位图
            //img.Save(@"E:" + Guid.NewGuid().ToString() + ".jpg");
            return img;          
        }
       
    }

13、图片剪裁类

    public class ImageManager
    {
        /// <summary>
        /// 图像切割
        /// </summary>
        /// <param name="url">图像文件名称</param>
        /// <param name="width">切割后图像宽度</param>
        /// <param name="height">切割后图像高度</param>
        /// <param name="savePath">切割后图像文件保存路径</param>
        /// <param name="fileExt">切割后图像文件扩展名</param>
        public static void Cut(string url, int width, int height, string savePath, string fileExt, string logofile)
        {
            Bitmap bitmap = new Bitmap(url);
            Decimal MaxRow = Math.Ceiling((Decimal)bitmap.Height / height);
            Decimal MaxColumn = Math.Ceiling((decimal)bitmap.Width / width);
            for (decimal i = 0; i < MaxRow; i++)
            {
                for (decimal j = 0; j < MaxColumn; j++)
                {
                    string filename = i.ToString() + "," + j.ToString() + "." + fileExt;
                    Bitmap bmp = new Bitmap(width, height);
                    for (int offsetX = 0; offsetX < width; offsetX++)
                    {
                        for (int offsetY = 0; offsetY < height; offsetY++)
                        {
                            if (((j * width + offsetX) < bitmap.Width) && ((i * height + offsetY) < bitmap.Height))
                            {
                                bmp.SetPixel(offsetX, offsetY, bitmap.GetPixel((int)(j * width + offsetX), (int)(i * height + offsetY)));
                            }
                        }
                    }
                    Graphics g = Graphics.FromImage(bmp);
                    g.DrawString("脚本之家", new Font("黑体", 20), new SolidBrush(Color.FromArgb(70, Color.WhiteSmoke)), 60, height / 2);//加水印
                    ImageFormat format = ImageFormat.Png;
                    switch (fileExt.ToLower())
                    {
                        case "png":
                            format = ImageFormat.Png;
                            break;
                        case "bmp":
                            format = ImageFormat.Bmp;
                            break;
                        case "gif":
                            format = ImageFormat.Gif;
                            break;
                    }
                    bmp.Save(savePath + "//" + filename, format);
                }
            }
        }
    }
原文地址:https://www.cnblogs.com/pu369/p/12346370.html