局域网控制(三)——远程关机重启等
3、其他
凡在本地计算机上通过编程可以实现的,在远程计算机上也可以实现,只不过是事件的执行或调用需要指定一个标志或信号即可。下面就介绍几个常用功能的实现过程:
1)关闭计算机
关闭计算机可以采用Windows API中的ExitWindowsEx()函数来实现,也可以直接通过新建Windows的cmd进程来调用Shutdown命令实现,使用ExitWindowsEx()函数时要先结束一些正在使用的进程才能正常运行,所以在此介绍采用Shutdown来实现关闭计算机。
由于使用Shutdown命令来执行,首先来看一下Shutdown命令的一些相关参数,如下:
shutdown [-i | -l | -s | -r | -a] [-f] [-m computername] [-t xx] [-c "comment"] [-d up:xx:yy]
其中:i表示显示GUI界面;l表示注销;s表示关闭此计算机;r表示关闭并重新启动此计算机;a表示放弃系统关机; m表示远程计算机关机等操作,后面的参数computername表示计算机名称;t表示设置关闭的时间;c表示注释,后面的参数comment表示注释内容;d表示关闭原因代码。
下面举例来说明一下,如果要60秒后关闭一个计算机直接点击“开始”菜单,打开“运行”,输入“shutdown -s -t 60”,如下图所示,然后点击“确定”按钮:
输入“shutdown –a”,即可取消关闭计算机。
下面就可以通过新建一个cmd的进程,然后再输入Shutdown的关机命令即可实现。新建进程需要使用Process类,所以需要引用命名空间System.Diagnostics,如下:
【客户端】:
using System.Diagnostics;
要调用cmd进程,直接新建一个进程对象,设置其FileName,然后在其WriteLine方法中写入关机命令,如下:
Process p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.RedirectStandardError = true;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.UseShellExecute = false;
p.Start();
p.StandardInput.WriteLine("shutdown -s");
p.StandardInput.WriteLine("Exit");
p.WaitForExit();
p.Close();
按此思路可以设计关闭计算机、重启计算机和注销。如下关闭计算机代码:
【客户端】:
DialogResult dialogResult = MessageBox.Show("是否关闭计算机?", "警告!", MessageBoxButtons.YesNo);
if (dialogResult.ToString() == "Yes")
{
Process p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.RedirectStandardError = true;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.UseShellExecute = false;
p.Start();
p.StandardInput.WriteLine("shutdown -s");
p.StandardInput.WriteLine("Exit");
p.WaitForExit();
p.Close();
}
重新启动计算机:
【客户端】:
DialogResult dialogResult = MessageBox.Show("是否重新启动计算机?", "警告!", MessageBoxButtons.YesNo);
if (dialogResult.ToString() == "Yes")
{
Process p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.RedirectStandardError = true;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.UseShellExecute = false;
p.Start();
p.StandardInput.WriteLine("shutdown -r");
p.StandardInput.WriteLine("Exit");
p.WaitForExit();
p.Close();
}
注销计算机:
【客户端】:
DialogResult dialogResult = MessageBox.Show("是否重新启动计算机?", "警告!", MessageBoxButtons.YesNo);
if (dialogResult.ToString() == "Yes")
{
Process p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.RedirectStandardError = true;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.UseShellExecute = false;
p.Start();
p.StandardInput.WriteLine("shutdown -l");
p.StandardInput.WriteLine("Exit");
p.WaitForExit();
p.Close();
}
2)远程关机
由于防火墙等原因,直接使用Shutdown命令不一定能实现远程关机,所以要实现远程关机还需要向客户端发送指定指令,在客户端根据该指令来执行相应操作。如在控制端添加一个按钮,设置其Name和text属性都为“远程关闭计算机”,为其Click()事件添加如下代码:
【控制端】:
private void 远程关闭计算机_Click(object sender, EventArgs e)
{
string message = "SHUTDOWN -S";
SendMessage(message);
}
这样控制端就将命令发送至客户端了,同时客户端还需要对这句指令进行解析与识别,然后执行相应操作。首先更改客户端的监听函数Listen(),如下(斜体部分为修改的部分):
【客户端】:
private void Listen()
{
try
{
Int32 port = Int32.Parse(portTextBox.Text);
tcpListener = new TcpListener(port);
tcpListener.Start();
while (true)
{
TcpClient client = tcpListener.AcceptTcpClient();
NetworkStream stream = client.GetStream();
if (stream.CanRead)
{
string mouseEvent = "";
byte[] bytes = new byte[1024];
stream.Read(bytes, 0, bytes.Length);
mouseEvent = Encoding.ASCII.GetString(bytes);
//分解字符串
if (mouseEvent.Contains("SHUTDOWN"))
{
RunWindowsEvent(mouseEvent);
}
else
{
int i, mouseX, mouseY, mouseClick;
i = mouseEvent.IndexOf(",");
mouseX = int.Parse(Microsoft.VisualBasic.Strings.Left(mouseEvent, i));
mouseEvent = Microsoft.VisualBasic.Strings.Right(mouseEvent, mouseEvent.Length - i - 1);
i = mouseEvent.IndexOf(",");
mouseY = int.Parse(Microsoft.VisualBasic.Strings.Left(mouseEvent, i));
i = mouseEvent.IndexOf(",");
mouseEvent = Microsoft.VisualBasic.Strings.Right(mouseEvent, mouseEvent.Length - i - 1);
mouseClick = int.Parse(mouseEvent);
//设置鼠标
mouseClickEvent(mouseX, mouseY, mouseClick);
}
}
client.Close();
}
}
finally
{
tcpListener.Stop();
}
}
其中,函数RunWindowsEvent()为自定义的用于执行关机等操作的函数,该函数的具体定义如下:
【客户端】:
private void RunWindowsEvent(string message)
{
Process p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.RedirectStandardError = true;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.UseShellExecute = false;
p.Start();
if (message.Contains("-S"))
{
p.StandardInput.WriteLine("SHUTDOWN -S");
}
else if (message.Contains("-R"))
{
p.StandardInput.WriteLine("SHUTDOWN -R");
}
else if (message.Contains("-A"))
{
p.StandardInput.WriteLine("SHUTDOWN -A");
}
p.StandardInput.WriteLine("Exit");
p.WaitForExit();
p.Close();
}
3)开机自动运行
开机自动运行程序主要是在注册表中新建一个字符串值,设置其值为客户端程序。实现该功能需要使用RegistryKey类来实现,所以首先需要引用命名空间,如下:
using Microsoft.Win32;
然后定义是否开机自动运行的函数SetAutoExec(),其代码如下:
【客户端】:
public void SetAutoExec(bool IsAuto)
{
RegistryKey Reg = Registry.LocalMachine.OpenSubKey(@"SOFTWARE/Microsoft/Windows/CurrentVersion/Run", true);
if (IsAuto)
{
string sFilePath = Application.ExecutablePath;
Reg.SetValue("局域网控制", sFilePath);
}
else
{
if (IsAuto == false) Reg.DeleteValue("局域网控制");
}
}
4)使用XML保存客户端的设置
客户端在启动时,如果服务器地址或端口变动了,则客户端无法连接到服务器上。为了避免这种情况发送,在客户端启动时,通过一个XML文件将一些主要的参数设置到客户端上,在客户端退出时将这些主要的参数又保存至该XML文件中。这样就不需要每次都去设置如服务器IP地址、端口等,每次客户端启动时就自动根据XML配置文件来设置参数。该配置文件名称为Config.xml,其文件内容如下:
【Config.xml】:
<?xml version="1.0"?>
<control>
<IPAddress>192.168.134.195</IPAddress>
<Port>5000</Port>
<TimeInterval>1000</TimeInterval>
<AutoRun>False</AutoRun>
<UnderControl>True</UnderControl>
</control>
其中<IPAddress>标记的值表示服务器IP地址,<Port>标记的值为端口,<TimeInterval>标记的值表示返回服务器数据的时间间隔,<AutoRun>标记的值表示客户端是否开机自动运行,<UnderControl>标记的值表示客户端是否启动后就开始受控。
所以在Form的Load()事件中要读取该配置文件,如下代码:
【客户端】:
//先读取配置文件
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("Config.xml");
XmlNode root = xmlDoc.SelectSingleNode("control");
IPAddressTextBox.Text = root.ChildNodes[0].InnerText;//查找<IPAddress>
portTextBox.Text = root.ChildNodes[1].InnerText;//查找<Port>
timeIntervalTextBox.Text = root.ChildNodes[2].InnerText;//查找<TimeInterval>
autoRunCheckBoxX.Checked = bool.Parse(root.ChildNodes[3].InnerText);//查找<AutoRun>
timer1.Enabled = bool.Parse(root.ChildNodes[4].InnerText);//查找<UnderControl>
autoControlCheckBoxX.Checked = timer1.Enabled;
在Form的FormClosing()事件中需要对客户端修改的参数进行保存,以便下次启动客户端时自动加载设置,如下代码:
//写入修改配置文件
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("Config.xml");
XmlNode root = xmlDoc.SelectSingleNode("control");
root.ChildNodes[0].InnerText = IPAddressTextBox.Text;//查找<IPAddress>
root.ChildNodes[1].InnerText = portTextBox.Text;//查找<Port>
root.ChildNodes[2].InnerText=timeIntervalTextBox.Text;//查找<TimeInterval>
root.ChildNodes[3].InnerText=autoRunCheckBoxX.Checked.ToString();//查找<AutoRun>
root.ChildNodes[4].InnerText = autoControlCheckBoxX.Checked.ToString();//查找<UnderControl>
xmlDoc.Save("Config.xml");
运行程序,其界面如下图所示: