如果叫你实现远程启动别人的计算机,你首先想到的可能是先做一个在远程计算机上面运行客户端程序,然后在本地计算机上面再做一个服务器端程序,通过这二个程序直接的通讯实现重启远程计算机。这当然是一个方法。但这未免有点麻烦。如果现在只告诉你远程计算机的管理者的登陆帐号,而并不允许你在远程的计算机上面运行一个所谓的客户端程序,让你通过程序来完成重启远程计算机。不知道你是否感觉有些困难了。其实按照上面的这些条件实现重启远程计算机,利用C#可以比较方便的完成。下面就来介绍一下具体的实现方法。 
   
    一. C#重启远程计算机的一些理论知识: 
   
    C#实现启动远程计算机的原理是"视窗管理规范"。就是所谓的"WMI"(Windows Management Instrumentation)。Windows 管理规范 (WMI) 支持通过 Internet 管理系统的结构。通过提供管理环境的一致观察,WMI 为用户提供通用访问管理信息。该管理的一致性使您能够管理整个系统,而不只是组件。从 Microsoft MSDN上,您可以获得有关 WMI 软件开发工具包 (SDK) 的详细信息。 
   
    WMI(Windows 管理规范)支持有限的安全格式,允许用户在本地计算机或远程计算机上连接 WMI 之前要验证每个用户。这种安全性是操作系统已有的安全顶端的另一层。WMI 不覆盖或破坏由操作系统提供的任何现有的安全性。在默认情况下,管理员组的所有成员都可以完全控制它管理的计算机上的 WMI 服务。其他所有用户在其本地计算机上只有读取/写入/执行的权限。可以通过向被管理的计算机上的管理员组添加用户,或者在 WMI 中授权用户或组并设置权限级别来更改权限。访问基于 WMI 名称空间。在一般情况下,脚本程序的默认命名空间是"root\cimv2"。 
   
    在WMI中有着许多足以令我们感觉惊奇的功能。重启远程计算机只是一个很小的功能。在程序中使用WMI可以编写出许多远程管理类型的应用程序。由于在.Net FrameWork SDK中提供了可以直接操作WMI的名称空间,所以C#就可以利用在这些名称空间中定义了的类来充分使用WMI控制给我们带来的各种方便。 
   
    二.程序设计和运行的环境设置: 
   
    (1).视窗2000服务器版 
   
    (2). .Net FrameWork SDK Beta 2 
   
    (3).远程计算机的管理者帐号 
   
    以上这些不仅是本地计算机配置,还是远程计算机的配置。 
   
    三.实现重启远程计算机所使用到在.Net FrameWork SDK Beta 2用以操作WMI名称空间和类: 
   
    在.Net FrameWork SDK Beta 2中用来操作WMI的名称空间主要是"System.Management"。要实现重启远程计算机所使用到的类主要有六个: 
   
    . "ConnectionOptions"类主要定义远程计算机的管理员帐号; 
   
    . "ManagementScope"主要是以给定的管理员帐号连接给定计算机名或者IP地址的计算机; 
   
    . "ObjectQuery"类功能是定义对远程计算机要实现那些地远程操作; 
   
    . "ManagementObjectSearcher"类从已经完成远程连接的计算机中,得到有那些WMI操作; 
   
    . "ManagementObjectCollection"类存放得到WMI操作; 
   
    . "ManagementObject"类调用远程计算机可进行WMI操作。 
   
    在本文介绍的操作就是重启操作。 
    四.C#重启远程计算机的重要步骤和实现方法: 
   
    (1).连接远程计算机: 
   
    按照下列语句可以实现连接远程计算机: 
   
   
  ConnectionOptions options = new ConnectionOptions ( ) ; 
  options.Username ="管理者帐号用户名"; 
  options.Password = "管理者帐号口令" ; 
  ManagementScope scope = new ManagementScope( "\\\\" + "远程计算机名或IP地址" + "\\root\\cimv2", options ) ; 
  //用给定管理者用户名和口令连接远程的计算机 
  scope.Connect ( ) ; 
   
    (2).得到在远程计算机中可以进行WMI控制: 
   
  System.Management.ObjectQuery oq = new System.Management.ObjectQuery ( "SELECT * FROM Win32_OperatingSystem" ) ; 
  ManagementObjectSearcher query1 = new ManagementObjectSearcher ( scope , oq ) ; 
  //得到WMI控制 
  ManagementObjectCollection queryCollection1 = query1.Get ( ) ; 
   
    (3).调用WMI控制,实现重启远程计算机: 
   
  foreach ( ManagementObject mo in queryCollection1 ) 
  { 
  string [ ] ss= { "" } ; 
  //重启远程计算机 
  mo.InvokeMethod ( "Reboot" , ss ) ; 
  } 

解决方案 »

  1.   


        五.C#实现重启远程计算机的源程序代码(boot.cs)和执行界面: 
       
        在了解了C#实现重启远程计算机的这些重要步骤后,就可以从容的得到重启远程计算机的完整代码,具体如下: 
       
      using System ; 
      using System.Drawing ; 
      using System.Collections ; 
      using System.ComponentModel ; 
      using System.Windows.Forms ; 
      using System.Data ; 
      using System.Management ; 
      public class Form1 : Form 
      { 
      private TextBox textBox1 ; 
      private TextBox textBox2 ; 
      private TextBox textBox3 ; 
      private Label label1 ; 
      private Label label2 ; 
      private Label label3 ; 
      private Button button1 ; 
      private System.ComponentModel.Container components = null ; 
      public Form1 ( ) 
      { 
      //初始化窗体中的各个组件 
      InitializeComponent ( ) ; 
      } 
      //清除程序中使用过的资源 
      protected override void Dispose ( bool disposing ) 
      { 
      if ( disposing ) 
      { 
      if ( components != null ) 
      { 
      components.Dispose ( ) ; 
      } 
      } 
      base.Dispose ( disposing ) ; 
      } 
      private void InitializeComponent ( ) 
      { 
      textBox1 = new TextBox ( ) ; 
      textBox2 = new TextBox ( ) ; 
      textBox3 = new TextBox ( ) ; 
      label1 = new Label ( ) ; 
      label2 = new Label ( ) ; 
      label3 = new Label ( ) ; 
      button1 = new Button ( ) ; 
       
      SuspendLayout ( ) ; 
      textBox1.Location = new System.Drawing.Point ( 140 , 46 ) ; 
      textBox1.Name = "textBox1" ; 
      textBox1.Size = new System.Drawing.Size ( 172 , 21 ) ; 
      textBox1.TabIndex = 0 ; 
      textBox1.Text = "" ; 
       
      textBox2.Location = new System.Drawing.Point ( 138 , 85 ) ; 
      textBox2.Name = "textBox2" ; 
      textBox2.Size = new System.Drawing.Size ( 174 , 21 ) ; 
      textBox2.TabIndex = 1 ; 
      textBox2.Text = "" ; 
       
      textBox3.Location = new System.Drawing.Point ( 139 , 120 ) ; 
      textBox3.Name = "textBox3" ; 
      textBox3.PasswordChar = ‘*‘ ; 
      textBox3.Size = new System.Drawing.Size ( 173 , 21 ) ; 
      textBox3.TabIndex = 2 ; 
      textBox3.Text = "" ; 
       
      label1.Location = new System.Drawing.Point ( 24 , 50 ) ; 
      label1.Name = "label1" ; 
      label1.Size = new System.Drawing.Size ( 120 , 16 ) ; 
      label1.TabIndex = 1 ; 
      label1.Text = "机器名称或IP地址:" ; 
       
      label2.Location = new System.Drawing.Point ( 37 , 88 ) ; 
      label2.Name = "label2" ; 
      label2.TabIndex = 1 ; 
      label2.Text = "管理者名称:" ; 
      label2.TextAlign = System.Drawing.ContentAlignment.TopRight ; 
       
      label3.Location = new System.Drawing.Point ( 37 , 125 ) ; 
      label3.Name = "label3" ; 
      label3.Size = new System.Drawing.Size ( 100 , 16 ) ; 
      label3.TabIndex = 1 ; 
      label3.Text = "管理者密码:" ; 
      label3.TextAlign = System.Drawing.ContentAlignment.TopRight ; 
       
      button1.Location = new System.Drawing.Point ( 95 , 168 ) ; 
      button1.Name = "button1" ; 
      button1.Size = new System.Drawing.Size ( 136 , 32 ) ; 
      button1.TabIndex = 3 ; 
      button1.Text = "重新启动远程计算机" ; 
      button1.Click += new System.EventHandler ( button1_Click ) ; 
       
      this.AutoScaleBaseSize = new System.Drawing.Size ( 6 , 14 ) ; 
      this.ClientSize = new System.Drawing.Size ( 336 , 245 ) ; 
      this.Controls.Add ( button1 ) ; 
      this.Controls.Add ( textBox1 ) ; 
      this.Controls.Add ( textBox2 ) ; 
      this.Controls.Add ( textBox3 ) ; 
      this.Controls.Add ( label1 ) ; 
      this.Controls.Add ( label2 ) ; 
      this.Controls.Add ( label3 ) ; 
       
      this.Name = "Form1" ; 
      this.Text = "利用C#重新启动远程计算机" ; 
      this.ResumeLayout(false) ; 
       
      } 
      static void Main ( ) 
      { 
      Application.Run ( new Form1 ( ) ) ; 
      } 
      private void button1_Click ( object sender , System.EventArgs e ) 
      { 
      //定义连接远程计算机的一些选项 
      ConnectionOptions options = new ConnectionOptions ( ) ; 
      options.Username = textBox2.Text ; 
      options.Password = textBox3.Text ; 
      ManagementScope scope = new ManagementScope( "\\\\" + textBox1.Text + "\\root\\cimv2", options ) ; 
      try { 
      //用给定管理者用户名和口令连接远程的计算机 
      scope.Connect ( ) ; 
      System.Management.ObjectQuery oq = new System.Management.ObjectQuery ( "SELECT * FROM Win32_OperatingSystem" ) ; 
      ManagementObjectSearcher query1 = new ManagementObjectSearcher ( scope , oq ) ; 
      //得到WMI控制 
      ManagementObjectCollection queryCollection1 = query1.Get ( ) ; 
      foreach ( ManagementObject mo in queryCollection1 ) 
      { 
      string [ ] ss= { "" } ; 
      //重启远程计算机 
      mo.InvokeMethod ( "Reboot" , ss ) ; 
      } 
      } 
      //报错 
      catch ( Exception ee ) { 
      MessageBox.Show ( "连接" + textBox1.Text + "出错,出错信息为:" + ee.Message ) ; 
      } 
      } 
      } 
       
       
        下图是编译上面代码后得到的程序运行界面: 
       
       
       
      图01:用C#实现重启远程计算机的程序运行界面 
       
        六.总结: 
       
        其实WMI控制可以实现很多以前让我们很头痛的操作。并且使用WMI编写的管理程序也比不用WMI来实现同样功能的程序在设计难度上大大减轻。WMI内容十分丰富,重新启动远程计算机只是其中的一个最为基本的操作。在使用WMI控制之前有一点必须记住,就是你必须知道你所要进行操作的远程计算机的超级管理者的帐号,这是使用WMI的一个前提。 
      

  2.   

    直接调用api也行
    Imports System
    Imports System.Text
    Imports System.Diagnostics
    Imports System.Runtime.InteropServicesPublic Class ExWindowsController
        Public Enum RestartOptions
            LogOff = 0
            PowerOff = 8
            Reboot = 2
            ShutDown = 1
            Suspend = -1
            Hibernate = -2
        End Enum    Public Structure LUID
            Dim LowPart As Integer
            Dim HighPart As Integer
        End Structure    Public Structure LUID_AND_ATTRIBUTES        Dim pLuid As LUID        Dim Attributes As Integer
        End Structure
        Public Structure TOKEN_PRIVILEGES        Dim PrivilegeCount As Integer        Dim Privileges As LUID_AND_ATTRIBUTES
        End Structure    Private Const TOKEN_ADJUST_PRIVILEGES = &H20
        Private Const TOKEN_QUERY = &H8
        Private Const SE_PRIVILEGE_ENABLED = &H2
        Private Const FORMAT_MESSAGE_FROM_SYSTEM = &H1000
        Private Const EWX_FORCE = 4
        Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As IntPtr
        Declare Function FreeLibrary Lib "kernel32" (ByVal hLibModule As IntPtr) As Integer
        Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As IntPtr, ByVal lpProcName As String) As IntPtr
        Declare Function SetSuspendState Lib "Powrprof" (ByVal Hibernate As Integer, ByVal ForceCritical As Integer, ByVal DisableWakeEvent As Integer) As Integer
        Declare Function OpenProcessToken Lib "advapi32.dll" (ByVal ProcessHandle As IntPtr, ByVal DesiredAccess As Integer, ByRef TokenHandle As IntPtr) As Integer
        Declare Function LookupPrivilegeValue Lib "advapi32.dll" Alias "LookupPrivilegeValueA" (ByVal lpSystemName As String, ByVal lpName As String, ByRef lpLuid As LUID) As Integer
        Declare Function AdjustTokenPrivileges Lib "advapi32.dll" (ByVal TokenHandle As IntPtr, ByVal DisableAllPrivileges As Integer, ByRef NewState As TOKEN_PRIVILEGES, ByVal BufferLength As Integer, ByRef PreviousState As TOKEN_PRIVILEGES, ByRef ReturnLength As Integer) As Integer
        Declare Function ExitWindowsEx Lib "user32" (ByVal uFlags As Integer, ByVal dwReserved As Integer) As Integer
        Declare Function FormatMessage Lib "kernel32" Alias "FormatMessageA" (ByVal dwFlags As Integer, ByVal lpSource As IntPtr, ByVal dwMessageId As Integer, ByVal dwLanguageId As Integer, ByVal lpBuffer As StringBuilder, ByVal nSize As Integer, ByVal Arguments As Integer) As Integer    Public Sub ExitWindows(ByVal how As RestartOptions, ByVal force As Boolean)
            Select Case how
                Case RestartOptions.Suspend
                    SuspendSystem(False, force)
                Case RestartOptions.Hibernate
                    SuspendSystem(True, force)
                Case Else
                    ExitWindows(Convert.ToInt32(how), force)
            End Select
        End Sub    Protected Sub ExitWindows(ByVal how As Integer, ByVal force As Boolean)
            EnableToken("SeShutdownPrivilege")
            If force Then how = how Or EWX_FORCE
            If (ExitWindowsEx(how, 0) = 0) Then Throw New PrivilegeException(FormatError(Marshal.GetLastWin32Error()))
        End Sub    Protected Sub EnableToken(ByVal privilege As String)
            If Not CheckEntryPoint("advapi32.dll", "AdjustTokenPrivileges") Then Return
            Dim tokenHandle As IntPtr = IntPtr.Zero
            Dim privilegeLUID = New LUID()
            Dim newPrivileges = New TOKEN_PRIVILEGES()
            Dim tokenPrivileges As TOKEN_PRIVILEGES
            If (OpenProcessToken(Process.GetCurrentProcess().Handle, TOKEN_ADJUST_PRIVILEGES Or TOKEN_QUERY, tokenHandle)) = 0 Then Throw New PrivilegeException(FormatError(Marshal.GetLastWin32Error()))
            If (LookupPrivilegeValue("", privilege, privilegeLUID)) = 0 Then Throw New PrivilegeException(FormatError(Marshal.GetLastWin32Error()))
            tokenPrivileges.PrivilegeCount = 1
            tokenPrivileges.Privileges.Attributes = SE_PRIVILEGE_ENABLED
            tokenPrivileges.Privileges.pLuid = privilegeLUID
            Dim Size As Integer = 4
            If (AdjustTokenPrivileges(tokenHandle, 0, tokenPrivileges, 4 + (12 * tokenPrivileges.PrivilegeCount), newPrivileges, Size)) = 0 Then Throw New PrivilegeException(FormatError(Marshal.GetLastWin32Error()))
        End Sub    Protected Sub SuspendSystem(ByVal hibernate As Boolean, ByVal force As Boolean)
            If Not CheckEntryPoint("powrprof.dll", "SetSuspendState") Then Throw New PlatformNotSupportedException("The SetSuspendState method is not supported on this system!")
            SetSuspendState(Convert.ToInt32(IIf(hibernate, 1, 0)), Convert.ToInt32(IIf(force, 1, 0)), 0)
        End Sub    Protected Function CheckEntryPoint(ByVal library As String, ByVal method As String) As Boolean
            Dim libPtr As IntPtr = LoadLibrary(library)
            If Not libPtr.Equals(IntPtr.Zero) Then
                If Not GetProcAddress(libPtr, method).Equals(IntPtr.Zero) Then
                    FreeLibrary(libPtr)
                    Return True
                End If
                FreeLibrary(libPtr)
            End If
            Return False
        End Function    Protected Function FormatError(ByVal number As Integer) As String
            Dim Buffer = New StringBuilder(255)
            FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, IntPtr.Zero, number, 0, Buffer, Buffer.Capacity, 0)
            Return Buffer.ToString()
        End Function
    End ClassPublic Class PrivilegeException
        Inherits Exception    Public Sub New()
            MyBase.New()
        End Sub    Public Sub New(ByVal message As String)
            MyBase.New(message)
        End Sub
    End Class