C#製作掛機程式V2.0—刷滑鼠單擊類線上視訊

2022-01-04 13:01:00


往期內容回顧

前面已經寫過兩篇相關的部落格了:
1.C#製作網站掛機程式:
(https://blog.csdn.net/stwzx/article/details/121042382)
2.Python構建自動線上刷視訊—一個只能做不能說的專案:
(https://blog.csdn.net/stwzx/article/details/121519322)
3.【C#製作掛機程式V2.0—刷滑鼠單擊類線上視訊程式】下載地址:
(https://download.csdn.net/download/stwzx/73742286)
第一篇文章主要在教大家怎樣用C#來做一個掛機程式,程式碼也相對簡樸,主要是完成了一個簡單的功能,可以處理網頁中的彈出的alert對話方塊。第二篇文章採用Python語言,完全控制瀏覽器,並能抓取網頁中的Tag、id、name或者CSS等標記並進行鍵盤、滑鼠輸入,應該是比較完美的程式。但今天為什麼又再次回到C#開發的老路上走自動化鍵盤、滑鼠單擊事件的掛機程式呢?Python不香嗎?程式碼君不禁呵呵了,Python的坑不可謂不多啊,反爬技術直接讓Python驅動瀏覽器bye bye了。

還是直接上乾貨吧

一、程式介面

在這裡插入圖片描述
程式還挺簡潔的,不過不要小看它,功能可不小!

二、功能說明

1.程式已經整合了Microsoft Spy++的功能

2.通過拖動工具自動獲取表單的Title

3.拖動工具自動獲取滑鼠準備單擊點的座標

4.通過時間設定單擊事件後等待時間(刷視訊必備)

5.瀏覽器應用程式不再侷限於FireFox

6.適應性增加,只要是通過滑鼠單擊完成的操作都可以交給它。

7.對錶單程式的自動化單擊也適用

強調一下,拖動工具得到座標和表單標題的做法,在C#開發中的實現,有可能僅此一家哦。因為本碼農搜遍百度都沒找到,有此功能的都是C++開發的。所以這個創意在C#應用完全是本人獨有。

三、程式使用步驟

核心使用功能展示:

1.程式執行後單擊【獲取瀏覽器標題:】,將出現工具如下:

在這裡插入圖片描述

2.拖動放大鏡工具到對應的程式表單,將自動獲取到表單標題

這個功能主要目的還是為了獲取到應用程式的控制程式碼,有了控制程式碼可以把表單設定為最上層顯示。(不被其它表單遮蓋)

3.單擊【獲取座標】按鈕,將出現工具如下:

在這裡插入圖片描述

4.拖動放大鏡工具到需要自動單擊的第一個點,鬆開,將彈出如下視窗:

在這裡插入圖片描述
座標不用設定,就是剛才滑鼠鬆開的位置,停頓時間是單擊後停多少時間,進行下一個操作的時間。

5.迴圈3和4的操作,可以得到一系列的座標點和相應停頓時間

6.全部設定完成後,直接單擊【Start】按鈕啟動自動化操作。

7.注意,這個自動化操作將周而復始的進行,直接關閉這個程式。也可以單擊【儲存座標】會把座標點和時間儲存到檔案中,重新啟動是會自動載入。

三、程式關鍵程式碼

1.API參照及成員變數

 #region API及成員變數
        /// <summary>
        /// 根據座標獲取視窗控制程式碼
        /// </summary>
        /// <param name="point">座標</param>
        /// <returns></returns>
        [DllImport("user32.dll")]
        private static extern IntPtr WindowFromPoint(Point point);
        public delegate bool EnumChildWindow(IntPtr WindowHandle, string num);
        /// <summary>
        /// 傳遞訊息給記事本
        /// </summary>
        /// <param name="hWnd"></param>
        /// <param name="Msg"></param>
        /// <param name="wParam"></param>
        /// <param name="lParam"></param>
        /// <returns></returns>
        [DllImport("User32.DLL")]
        public static extern int SendMessage(IntPtr hWnd, uint Msg, int wParam, string lParam);
        [DllImport("user32.dll", EntryPoint = "keybd_event", SetLastError = true)]
        public static extern void keybd_event(Keys bVk, byte bScan, uint dwFlags, uint dwExtraInfo);
        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
        public static extern int ShowWindow(IntPtr hwnd, int nCmdShow);
        [DllImport("user32.dll")]
        public static extern bool SetForegroundWindow(int hWnd);
        [DllImport("User32.dll")]
        public static extern int EnumChildWindows(IntPtr WinHandle, EnumChildWindow ecw, string name);
        [DllImport("User32.dll")]
        public static extern int GetWindowText(IntPtr WinHandle, StringBuilder Title, int size);
        [DllImport("user32.dll")]
        public static extern int GetClassName(IntPtr WinHandle, StringBuilder Type, int size);
        [DllImport("user32")]
        private static extern int GetWindowThreadProcessId(IntPtr handle, out int pid);
        [DllImport("user32")]
        public static extern IntPtr SetActiveWindow(IntPtr hWnd);
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);
        [DllImport("user32.dll", EntryPoint = "FindWindow")]
        private static extern IntPtr FindWindow(string IpClassName, string IpWindowName);
        //查詢表單控制元件
        public int iSecond = 30;
        public delegate bool CallBack(int hwnd, int lParam);
        public RECT rectMain = new RECT();
        private string typeName;
        private IntPtr mainHwnd;
        public IntPtr ip;
        private string BSType = "Chrome_WidgetWin_1";
        bool Flag = false;
        int X;
        int Y;
        int times;
        private IntPtr mainWindowHandle;
        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            public int X; //最左座標
            public int Y; //最上座標
            public int Height; //最右座標
            public int Width; //最下座標
        }
        /// <summary>
        /// 查詢控制程式碼
        /// </summary>
        /// <param name="hwndParent"></param>
        /// <param name="hwndChildAfter"></param>
        /// <param name="lpszClass"></param>
        /// <param name="lpszWindow"></param>
        /// <returns></returns>
        [DllImport("User32.DLL")]
        public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
        [DllImport("User32")]
        public extern static void mouse_event(int dwFlags, int dx, int dy, int dwData, IntPtr dwExtraInfo);
        [DllImport("user32.dll")]
        static extern bool SetCursorPos(int X, int Y);
        public const uint WM_SETTEXT = 0x000C;
        public System.Diagnostics.Process Proc;
        public System.Windows.Forms.Timer myTimer;
        public List<Opt> optList = new List<Opt>();
        public Queue<Opt> optQueue = new Queue<Opt>();
        #endregion

2.移動滑鼠程式碼

public void MoveTo(int x1, int y1, int x2, int y2)
{
    float k = (float)(y2 - y1) / (float)(x2 - x1);
    float b = y2 - k * x2;


    for (int x = x2; x != x1; x = x + Math.Sign(x1 - x2))
    {
        //MoveTo(x1,y1,x,(k*x+b));
        SetCursorPos(x, (int)(k * x + b));
        Thread.Sleep(3);
    }
}

程式碼如下(範例):

3.Start事件程式碼

private void btnStart_Click(object sender, EventArgs e)
{
            
    foreach (string strLine in richTextBox1.Lines)
    {
        string[] strInt = strLine.Split(new string[] { "," }, StringSplitOptions.None);
        if (strInt.Length <= 2)//小於2個引數:一個Point由X,Y組成
        {
            continue;
        }
        int x = int.Parse(strInt[0]);
        int y = int.Parse(strInt[1]);
        int times = int.Parse(strInt[2]);
        optList.Add(new Opt(x, y, times));
    }
    foreach (Opt opt in optList)
    {
        optQueue.Enqueue(opt);
    }
    IntPtr hnd = FindWindow(null, txtTitle.Text);
    IntPtr ip = hnd;
    lblMessage.Text = ip.ToString();
    iSecond = 1;
    //myTimer.Interval = 1000 * iSecond;
    myTimer.Interval = 1000 * 60 * iSecond;
    myTimer.Enabled = false;
    FindWindowClass.TopMostWindow.SetTopomost(ip);
    SetForegroundWindow((int)ip);
    if (optQueue.Count > 0)
    {
        Opt opt = optQueue.Dequeue();
        X = opt.x;
        Y = opt.y;
        times = opt.Times;
        System.Timers.Timer t = new System.Timers.Timer();//範例化 
        t.Elapsed += new System.Timers.ElapsedEventHandler(CallBack2);
        t.AutoReset = false;
        t.Interval = 1000 * times;
        t.Enabled = true;
    }
}

4.定時器事件程式碼

private void CallBack2(object sender, EventArgs e)
{
    MoveTo(X, Y, MousePosition.X, MousePosition.Y);
    mouse_event((int)(MouseEventFlags.LeftDown | MouseEventFlags.Absolute), X, Y, 0, IntPtr.Zero);
    //Thread.Sleep(200);
    mouse_event((int)(MouseEventFlags.LeftUp | MouseEventFlags.Absolute), X, Y, 0, IntPtr.Zero);
    if (optQueue.Count > 0)
    {
        Opt opt = optQueue.Dequeue();
        X = opt.x;
        Y = opt.y;
        times = opt.Times;
        System.Timers.Timer t = new System.Timers.Timer();//範例化 
        t.Elapsed += new System.Timers.ElapsedEventHandler(CallBack2);
        t.AutoReset = false;
        t.Interval = 1000 * times;
        t.Enabled = true;
    }
    else
    {
        foreach (Opt opt1 in optList)
        {
            optQueue.Enqueue(opt1);
        }
        Opt opt = optQueue.Dequeue();
        X = opt.x;
        Y = opt.y;
        times = opt.Times;
        System.Timers.Timer t = new System.Timers.Timer();//範例化 
        t.Elapsed += new System.Timers.ElapsedEventHandler(CallBack2);
        t.AutoReset = false;
        t.Interval = 1000 * times;
        t.Enabled = true;
    }
}

5.啟動瀏覽器事件程式碼

private void btnStartBrowser_Click(object sender, EventArgs e)
{
    if (string.IsNullOrEmpty(txtFile.Text)) return;
    try
    {
        // 瀏覽器程式啟動執行緒
        Proc = new System.Diagnostics.Process();
        Proc.StartInfo.FileName = txtFile.Text;
        Proc.StartInfo.Arguments = txtNetAddr.Text;  //瀏覽器開啟URL引數
        Proc.StartInfo.UseShellExecute = false;
        Proc.StartInfo.RedirectStandardInput = true;
        Proc.StartInfo.RedirectStandardOutput = true;
        Proc.Start();
    }
    catch
    {
        Proc = null;
    }
}

總結

掛機程式的開發本身是存在著侷限性的。往往只能針對某一個或某一類應用程式。但只要你注重思考和挖掘,不管什麼樣的應用程式,總能找到對應的點開發出相應的掛機程式。要想用一個掛機程式一招吃遍天下是不可行的。