• C#控制电脑注销、关机、重启


    实现目标

    通过C#实现电脑的注销、关机、重启功能

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pOdgT8ZR-1663648018817)(C:\Users\buluw\AppData\Roaming\Typora\typora-user-images\image-20220919115753314.png)]

    知识点

    本案例涉及的知识点包含:Process、Shell32.dll、User32.dll、Struct数据结构

    Process

    本案例主要通过Process类调用cmd.exe.使用shell命令实现电机的关机和重启。

    用到的属性和方法有:StartInfo(属性)Start(方法)

    StartInfo.FileName

    获取或设置要启动的应用程序或文档。

    Process.StartInfo.FileName 
    Process.StartInfo.FileName = "cmd.exe"
    

    StartInfo.UseShellExecute

    如果应在启动进程时使用 shell,则为 true;如果直接从可执行文件创建进程,则为 false。 默认值为true。

    以下场景值为True:

    需要打开文档、媒体、网页文件等 需要打开 Url 需要打开脚本执行 需要打开计算机上环境变量中路径中的程序

    以下场景值为False:

    需要明确执行一个已知的程序 需要重定向输入和输出

    UseShellExecute = true 调用的是 ShellExecute

    UseShellExecute = false 调用的是 CreateProcess

    Process.StartInfo.UseShellExecute 
    Process.StartInfo.UseShellExecute = false
    

    StartInfo.RedirectStandardInput

    获取用于写入应用程序输入的流。

    如果应从 StandardInput 读取输入,则为 true;否则为 false。 默认值为 false。

    A Process 可以从其标准输入流(通常是键盘)读取输入文本。 通过重定向 StandardInput 流,可以编程方式指定进程的输入。 例如,你可以从指定文件的内容或从另一个应用程序的输出中提供文本,而不是使用键盘输入。

    StartInfo.RedirectStandardOutput

    获取或设置指示是否将应用程序的文本输出写入 StandardOutput 流中的值。

    如果输出应写入 StandardOutput,则为 true;否则为 false。 默认值为 false。

    Process当将文本写入其标准流时,该文本通常显示在主机上。 通过设置为RedirectStandardOutputtrue重定向StandardOutput流,可以操作或取消进程的输出。 例如,可以筛选文本、以不同的方式设置格式,或将输出写入控制台和指定的日志文件。

    // Run "csc.exe /r:System.dll /out:sample.exe stdstr.cs". UseShellExecute is false because we're specifying
    // an executable directly and in this case depending on it being in a PATH folder. By setting
    // RedirectStandardOutput to true, the output of csc.exe is directed to the Process.StandardOutput stream
    // which is then displayed in this console window directly.
    using (Process compiler = new Process())
    {
        compiler.StartInfo.FileName = "csc.exe";
        compiler.StartInfo.Arguments = "/r:System.dll /out:sample.exe stdstr.cs";
        compiler.StartInfo.UseShellExecute = false;
        compiler.StartInfo.RedirectStandardOutput = true;
        compiler.Start();
    
        Console.WriteLine(compiler.StandardOutput.ReadToEnd());
    
        compiler.WaitForExit();
    }
    

    StartInfo.RedirectStandardError

    获取或设置指示是否将应用程序的错误输出写入 StandardError 流中的值。

    如果错误输出应写入 StandardError,则为 true;否则为 false。 默认值为 false。

    Process当将文本写入其标准错误流时,该文本通常显示在主机上。 通过重定向 StandardError 流,可以操作或禁止进程的错误输出。 例如,可以筛选文本、以不同的方式设置格式,或将输出写入控制台和指定的日志文件.

    StartInfo.CreateNoWindow

    获取或设置指示是否在新窗口中启动该进程的值。

    如果应启动进程而不创建包含它的新窗口,则为true ;否则为 false。 默认值为 false

    对控制面板窗口有效,与 UseShellExecute 结合使用。

    UseShellExecute = true 时此值无效,为正常方式启动。

    UseShellExecute = false;CreateNoWindow = true 时,控制面板窗口不会显示。这种方式下无法通过窗口关闭进程,所以运行的进程最好是可以自己运行完关闭的,不然需要到任务管理器中关闭。

    Start

    启动进程资源并将其与 Process 组件关联。

    StandardInput.WriteLine(cmd)

    获取用于写入应用程序输入的流。

    StreamWriter,可用于写入应用程序的标准输入流。

    shell32.dll

    public static extern bool SendMessage(IntPtr hwdn, int wMsg, int mParam, int lParam);
    //从exe\dll\ico文件中获取指定索引或ID号的图标句柄
    [DllImport("shell32.dll", EntryPoint = "ExtractIcon")]
    
    //获取文件图标的API函数
    [DllImport("shell32.dll", EntryPoint = "SHGetFileInfo")]
    public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttribute, ref SHFILEINFO psfi, uint cbSizeFileInfo, uint Flags);
    
    //从exe\dll\ico文件中生成图标句柄数组
    [DllImport("shell32.dll")]
    public static extern uint ExtractIconEx(string lpszFile, int nIconIndex, int[] phiconLarge, int[] phiconSmall, uint nIcons);
    
    //清空指定驱动器的回收站
    [DllImport("shell32.dll")]
    public static extern int SHEmptyRecycleBin(IntPtr hwnd, int pszRootPath, int dwFlags);
    
    //打开系统的命令窗口
    [DllImport("shell32.dll", EntryPoint = "ShellExecute")]
    public static extern int ShellExecute(int hwnd, String lpOperation, String lpFile, String lpParameters, String lpDirectory, int nShowCmd);
    

    User32.dll

      //用来释放被当前线程中某个窗口捕获的光标
            [DllImport("user32.dll")]
            public static extern bool ReleaseCapture();
            //向指定的窗体发送Windows消息
            [DllImport("user32.dll")]
            public static extern bool SendMessage(IntPtr hwdn, int wMsg, int mParam, int lParam);
            //获取文件夹图标的API函数
            [DllImport("User32.dll", EntryPoint = "DestroyIcon")]
            public static extern int DestroyIcon(IntPtr hIcon);
            //查询或设置系统级参数
            [DllImport("user32.dll", EntryPoint = "SystemParametersInfoA")]
            public static extern Int32 SystemParametersInfo(Int32 uAction, Int32 uParam, string lpvparam, Int32 fuwinIni);
            //定义系统API入口点,用来关闭、注销或者重启计算机
            [DllImport("user32.dll", EntryPoint = "ExitWindowsEx", CharSet = CharSet.Ansi)]
            public static extern int ExitWindowsEx(int uFlags, int dwReserved);
    

    Struct数据结构

    C#中Struct数据类型此处不做更多延伸介绍,这里只说明结构类型的语法定义规则和结构体布局。

    语法定义

    //public为修饰符,People为结构体名称,name、age、sex为结构体成员,每个成员包括修饰符、数据类型。
    public struct People
    {
       public string name;
       public int age;
       public char sex ;
    };  
    

    结构体布局

    *Sequential,顺序布局*

    [StructLayout(LayoutKind.Sequential)]
    struct num
    {
    	int a;
    	int b;
    }
    //默认情况下在内存里是先排a,再排b
    //也就是如果能取到a的地址,和b的地址,则相差一个int类型的长度,4字节
    

    *Explicit,精确布局*

    *需要用FieldOffset()设置每个成员的位置
    这样就可以实现类似c的公用体的功能*

    [StructLayout(LayoutKind.Explicit)]
    struct S1
    {
      [FieldOffset(0)]
      int a;
      [FieldOffset(0)]
      int b;
    }
    //需要用FieldOffset()设置每个成员的位置
    //这样就可以实现类似c的公用体的功能
    

    代码案例

    代码案例中MarshalAs特性,它用于描述字段、方法或参数的封送处理格式。用它作为参数前缀并指定目标需要的数据类型。

    [StructLayout(LayoutKind.Sequential)]
     public struct SHFILEINFO
     {
         public IntPtr hIcon;//图标句柄
         public IntPtr iIcon;//系统图标列表的索引
         public uint dwAttributes;//文件属性
         [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
         public string szDisplayName;//文件的路径
         [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
         public string szTypeName;//文件的类型名
     }
    

    实现步骤

    功能类

    本功能实现逻辑:

    注销:调用windows系统API函数(user32.dll)的方法。

    //定义系统API入口点,用来关闭、注销或者重启计算机
    [DllImport("user32.dll", EntryPoint = "ExitWindowsEx", CharSet = CharSet.Ansi)]
    public static extern int ExitWindowsEx(int uFlags, int dwReserved)
    

    关闭:利用Process,创建新进程,打开cmd.exe,然后使用shell脚本,触发关机动作

     public void CMDOperator(string cmd)
     {
    	 Process myProcess = new Process();//创建进程对象
         myProcess.StartInfo.FileName = "cmd.exe";//设置打开cmd命令窗口
         myProcess.StartInfo.UseShellExecute = false;//不使用操作系统shell启动进程的值
         myProcess.StartInfo.RedirectStandardInput = true;//设置可以从标准输入流读取值
         myProcess.StartInfo.RedirectStandardOutput = true;//设置可以向标准输出流写入值
         myProcess.StartInfo.RedirectStandardError = true;//设置可以显示输入输出流中出现的错误
         myProcess.StartInfo.CreateNoWindow = true;//设置在新窗口中启动进程
         myProcess.Start();//启动进程
         myProcess.StandardInput.WriteLine(cmd);//传入要执行的命令
    }
    

    重启:实现方式和关闭一样,只不过要修改shell脚本

    窗体组态

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d574KNNx-1663647916403)(C:\Users\buluw\AppData\Roaming\Typora\typora-user-images\image-20220920121018530.png)]

    红色边框内为label控件,绿色边框内为Button控件

    事件触发

    窗体中有四个按钮,对应每个按钮有四个事件,事件触发属性都为:click。

    事件程序

    //注销按钮事件程序
    //调用win32类中的ExitWindowsEx方法。
     private void button1_Click(object sender, EventArgs e)
    {
    	Win32.ExitWindowsEx(0, 0);//注销计算机
    }
    //关机按钮事件程序
    //调用Opera类中的CMDOperator方法。使用shell脚本触发
     private void button2_Click(object sender, EventArgs e)
     {
         oper.CMDOperator("shutdown -s -t 0");//关闭计算机
     }
    //重启按钮事件程序
    //调用Opera类中的CMDOperator方法。使用shell脚本触发
    private void button3_Click(object sender, EventArgs e)
    {
        oper.CMDOperator("shutdown -r -t 0");//重启计算机
    }
    

    附件

    源码程序是VS2019编写
    参考链接

  • 相关阅读:
    掌握Java中的FileReader类
    每日五道java面试题之spring篇(五)
    【Linux】《Linux命令行与shell脚本编程大全 (第4版) 》笔记-Chapter17-创建函数
    阿里云视频上传实战
    数据结构初阶——堆
    数据结构之:跳表
    【毕业设计】31-基于单片机的农业蔬菜大棚温度自动控制系统设计(原理图工程+源码工程+仿真工程+答辩论文+答辩PPT)
    机器学习笔记 - 构建自己的视频分类模型的分步教程
    【JavaEE】yapi平台搭建步骤详解
    如何入行软件开发——常见问题及岗位分工
  • 原文地址:https://blog.csdn.net/yue008/article/details/126950792