C# 實現遠程控制軟件的關鍵技術
編者:wyl
一、服務器端多線程Socket技術
用TcpListener進行偵聽,接受客戶端連接,有客戶端連進來后開啟處理線程處理數據,代碼如下:
using System; using System.Threading; using System.Net.Sockets; using System.Text; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { // 在8888端口偵聽 TcpListener serverSocket = new TcpListener(8888); TcpClient clientSocket = default(TcpClient); int counter = 0; serverSocket.Start(); Console.WriteLine(" >> " + "Server Started"); counter = 0; while (true) { counter += 1; // 接受客戶端連接 clientSocket = serverSocket.AcceptTcpClient(); Console.WriteLine(" >> " + "Client No:" + Convert.ToString(counter) + " started!"); // 啟動客戶端處理代碼 handleClinet client = new handleClinet(); client.startClient(clientSocket, Convert.ToString(counter)); } clientSocket.Close(); serverSocket.Stop(); Console.WriteLine(" >> " + "exit"); Console.ReadLine(); } } // 客戶端連接處理類 public class handleClinet { TcpClient clientSocket; string clNo; public void startClient(TcpClient inClientSocket, string clineNo) { this.clientSocket = inClientSocket; this.clNo = clineNo; // 開啟處理線程 Thread ctThread = new Thread(doChat); ctThread.Start(); } private void doChat() { int requestCount = 0; byte[] bytesFrom = new byte[10025]; string dataFromClient = null; Byte[] sendBytes = null; string serverResponse = null; string rCount = null; requestCount = 0; while ((true)) { try { requestCount = requestCount + 1; // 讀取內容 NetworkStream networkStream = clientSocket.GetStream(); networkStream.Read(bytesFrom, 0, (int)clientSocket.ReceiveBufferSize); dataFromClient = System.Text.Encoding.ASCII.GetString(bytesFrom); dataFromClient = dataFromClient.Substring(0, dataFromClient.IndexOf("$")); Console.WriteLine(" >> " + "From client-" + clNo + dataFromClient); rCount = Convert.ToString(requestCount); serverResponse = "Server to clinet(" + clNo + ") " + rCount; sendBytes = Encoding.ASCII.GetBytes(serverResponse); networkStream.Write(sendBytes, 0, sendBytes.Length); networkStream.Flush(); Console.WriteLine(" >> " + serverResponse); } catch (Exception ex) { Console.WriteLine(" >> " + ex.ToString()); } } } } }
二、鼠標控制技術
鼠標的控制用到了 mouse_event 這個API函數,參考代碼如下:
using System; using System.Threading; using System.Runtime.InteropServices; using System.Windows.Forms; namespace MouseControl { class MouseControl { /// <summary> /// 鼠標控制參數 /// </summary> const int MOUSEEVENTF_LEFTDOWN = 0x2; const int MOUSEEVENTF_LEFTUP = 0x4; const int MOUSEEVENTF_MIDDLEDOWN = 0x20; const int MOUSEEVENTF_MIDDLEUP = 0x40; const int MOUSEEVENTF_MOVE = 0x1; const int MOUSEEVENTF_ABSOLUTE = 0x8000; const int MOUSEEVENTF_RIGHTDOWN = 0x8; const int MOUSEEVENTF_RIGHTUP = 0x10; /// <summary> /// 鼠標的位置 /// </summary> public struct PONITAPI { public int x, y; } [DllImport("user32.dll")] public static extern int GetCursorPos(ref PONITAPI p); [DllImport("user32.dll")] public static extern int SetCursorPos(int x, int y); [DllImport("user32.dll")] public static extern int mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo); [STAThread] static void Main() { PONITAPI p = new PONITAPI(); GetCursorPos(ref p); Console.WriteLine("鼠標現在的位置X:{0}, Y:{1}", p.x, p.y); Console.WriteLine("Sleep 1 sec..."); Thread.Sleep(1000); p.x = (new Random()).Next(Screen.PrimaryScreen.Bounds.Width); p.y = (new Random()).Next(Screen.PrimaryScreen.Bounds.Height); Console.WriteLine("把鼠標移動到X:{0}, Y:{1}", p.x, p.y); SetCursorPos(p.x, p.y); GetCursorPos(ref p); Console.WriteLine("鼠標現在的位置X:{0}, Y:{1}", p.x, p.y); Console.WriteLine("Sleep 1 sec..."); Thread.Sleep(1000); Console.WriteLine("在X:{0}, Y:{1} 按下鼠標左鍵", p.x, p.y); mouse_event(MOUSEEVENTF_LEFTDOWN, p.x, p.y, 0, 0); Console.WriteLine("Sleep 1 sec..."); Thread.Sleep(1000); Console.WriteLine("在X:{0}, Y:{1} 釋放鼠標左鍵", p.x, p.y); mouse_event(MOUSEEVENTF_LEFTUP, p.x, p.y, 0, 0); Console.WriteLine("程序結束,按任意鍵退出...."); Console.ReadKey(); } } }
三、鍵盤控制技術
鍵盤的控制用到了 keybd_event 這個API函數,參考代碼段如下:
[DllImport("user32.dll", EntryPoint = "keybd_event")] public static extern void keybd_event( byte bVk, byte bScan, int dwFlags, int dwExtraInfo ); keybd_event((byte)Keys.F11, 0, 0, 0);//按下F11 keybd_event((byte)Keys.F11, 0, 0x2, 0); //彈起F11
四、運行程序
4.1
public static void RunProcess(string name, string command) { Process myProcess = new Process(); myProcess.StartInfo.FileName = name; myProcess.StartInfo.Arguments = command; myProcess.Start(); return; }
4.2 運行CMD並取得命令執行結果
public static string RunCmd(string command)//運行一個cmd命令 { Process p = new Process(); //p.StartInfo.WorkingDirectory = "c:\\"; // 工作目錄 p.StartInfo.FileName = "cmd.exe"; // 程序名 p.StartInfo.Arguments = "/c " + command; // 執行參數 p.StartInfo.UseShellExecute = false; // 關閉Shell的使用 p.StartInfo.RedirectStandardInput = true; // 重定向標准輸入 p.StartInfo.RedirectStandardOutput = true; // 重定向標准輸出 p.StartInfo.RedirectStandardError = true; // 重定向錯誤輸出 p.StartInfo.CreateNoWindow = true; // 設置不顯示窗口 p.Start(); //啟動 //p.StandardInput.WriteLine(command); // 也可以用這種方式輸入要執行的命令 //p.StandardInput.WriteLine("exit"); // 不過要記得加上Exit,要不然下一行執行的時候會出錯 return p.StandardOutput.ReadToEnd(); // 從輸出流取得命令執行結果 }
五、取得屏幕拷貝
取得屏幕拷貝的代碼直接用了bitmap格式,性能不高,在實際使用中應該考慮進行壓縮。
public Image GetScreen( ) { //this.Hide(); IntPtr dc1 = CreateDC("DISPLAY", null, null, (IntPtr)null); //創建顯示器的DC Graphics g1 = Graphics.FromHdc(dc1); //由一個指定設備的句柄創建一個新的Graphics對象 Bitmap MyImage = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, g1); //根據屏幕大小創建一個與之相同大小的Bitmap對象 Graphics g2 = Graphics.FromImage(MyImage); //獲得屏幕的句柄 IntPtr dc3 = g1.GetHdc(); //獲得位圖的句柄 IntPtr dc2 = g2.GetHdc(); //把當前屏幕捕獲到位圖對象中 BitBlt(dc2, 0, 0, Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, dc3, 0, 0, 13369376); //把當前屏幕拷貝到位圖中 g1.ReleaseHdc(dc3); //釋放屏幕句柄 g2.ReleaseHdc(dc2); //釋放位圖句柄 return MyImage; //this.Show(); }
