• C#制作windows屏保实战


    想用C#制作一个windows屏保,网上的文章大都泛泛而谈,语焉不详,特别是涉及到windows屏保设置的时候,怎样在屏保预览窗口显示屏保,没有找到详细的说明,胡乱测试了一通,还真做出来了,分享一下。

    画面是这样的,就是简单的随机画点线条,代码都是别人写现成的,本身也简单。关键是怎么转为屏保。

    using System;
    using System.Diagnostics;
    using System.Drawing;
    using System.Windows.Forms;
    
    namespace 屏幕保护程序
    {
        public partial class Form1 : Form
        {
            public PictureBox pictureBox;
            Timer timer;
            Graphics graphics;
            Random random;
            Point start = new Point(0, 0);
    
            public Form1()
            {
                InitializeComponent();
                this.FormBorderStyle = FormBorderStyle.None;    //窗体运行后无边界
                this.ShowInTaskbar = false;     //程序运行后不显示在任务栏上
                this.WindowState = FormWindowState.Maximized;    //窗体运行后,最大化,充满整个屏幕
                pictureBox = new PictureBox();
                pictureBox.Parent = this;
                pictureBox.Dock = DockStyle.Fill;
                pictureBox.BackColor = Color.Black;
                this.KeyDown += new KeyEventHandler(this.Form1_KeyDown);
                this.MouseMove += new MouseEventHandler(this.Conctrol_MouseMove);    // 控件充满窗体时没用
                pictureBox.MouseMove += new MouseEventHandler(Conctrol_MouseMove);
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {
                graphics = pictureBox.CreateGraphics();   // 在构造函数中使用时画图区域为窗体初始大小
                random = new Random();
                timer = new Timer();
                timer.Interval = 20;
                timer.Enabled = true;
                timer.Tick += new EventHandler(Timer_Tick);
                Cursor.Hide();
            }
    
            private Pen GetPen()
            {
                // make a random color
                int A = random.Next(0, 256);
                int R = random.Next(0, 256);
                int G = random.Next(0, 256);
                int B = random.Next(0, 256);
                Color color = Color.FromArgb(A, R, G, B);
                // make pen out of color
                int width = random.Next(2, 8);
                return new Pen(color, width);
            }
    
            public void DrawShape(Graphics graphics)    // 画随机线
            {
                Pen pen = GetPen();
                int x1 = random.Next(0, (int)graphics.VisibleClipBounds.Width);
                int y1 = random.Next(0, (int)graphics.VisibleClipBounds.Height);
                int x2 = random.Next(0, (int)graphics.VisibleClipBounds.Width);
                int y2 = random.Next(0, (int)graphics.VisibleClipBounds.Height);
                graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                graphics.DrawLine(pen, x1, y1, x2, y2);
            }
    
            private void Timer_Tick(object source, EventArgs e)
            {
                DrawShape(graphics);
            }
    
            private void Form1_FormClosed(object sender, FormClosedEventArgs e)
            {
                graphics.Dispose();
                timer.Dispose();
            }
    
            private void Form1_KeyDown(object sender, KeyEventArgs e)    // 检测有按键退出屏保
            {
                Cursor.Show();
                Application.Exit();
            }
    
            private void Conctrol_MouseMove(object sender, MouseEventArgs e)    // 控件充满窗体时窗体检测不到鼠标移动
            {
                Debug.WriteLine("MouseMove: {0}", e.Location);    // 窗体打开时鼠标即使不动也会不停触发MouseMove事件
                if (start == new Point(0, 0))    // 程序开始运行后,把鼠标当前的位置记录下来
                {
                    start = e.Location;
                    return;
                }
                else if (start != e.Location)    // 判断自程序运行后,鼠标的位置是否变动
                {
                    Cursor.Show();
                    Application.Exit();
                };
            }
        }
    }
    

      主要输出画面的代码根据注释一看就明白了,稍微麻烦的是在windows里怎么设置,如下:

    using System;
    using System.Drawing;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;
    
    namespace 屏幕保护程序
    {
        static class Program
        {
            /// <summary>
            ///  The main entry point for the application.
            /// </summary>
            [STAThread]
            static void Main(string[] args)
            {
                if (args != null && args.Length != 0)
                {
                    //for (int i = 0; i < args.Length; i++)    // 测试scr文件右键以及系统的屏幕保护程序设置使用的调用参数
                    //{
                    //    MessageBox.Show(i + ": " + args[i], "系统提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    //}
                    if (args[0].StartsWith("/c") || args[0].StartsWith("/C") || args[0].StartsWith("-c") || args[0].StartsWith("-C"))
                    {
                        MessageBox.Show("此屏幕保护没有可供设置的选项!", "系统提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                        return;
                    }
                    if (args[0].Equals("/p") || args[0].Equals("/P") || args[0].Equals("-p") || args[0].Equals("-P"))
                    {
                        if (args.Length < 2) return;
                        if (!int.TryParse(args[1], out int result)) return;    // 参数/p之后有紧随另一个整数参数(句柄)
                        IntPtr handle = new IntPtr(result);
                        Form1 form1 = new Form1();    // 必须有此句预览窗口才有显示输出(到底起了什么作用?很奇怪!)
                        //form1.Show();    // 正常显示窗体,会盖住"屏幕保护程序设置"窗口
                        Graphics graphics = Graphics.FromHwnd(handle);
                        while (IsWindowVisible(handle))     // 在系统的"屏幕保护程序设置"的预览窗口显示输出
                        {
                            //form1.DrawShape(graphics);    // 这样调用(无论是实例化还是静态)死活不行
                            DrawShape(graphics);
                            System.Threading.Thread.Sleep(100);    // 间隔一定时间形成动画效果
                        }
                        form1.Close();
                        return;
                    }
                }
                Application.SetHighDpiMode(HighDpiMode.SystemAware);
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form1());
            }
    
            [DllImport("user32.dll")]
            private static extern bool IsWindowVisible(IntPtr handle);
    
            static Random random = new Random();
            static private Pen GetPen()
            {
                // make a random color
                int A = random.Next(0, 256);
                int R = random.Next(0, 256);
                int G = random.Next(0, 256);
                int B = random.Next(0, 256);
                Color color = Color.FromArgb(A, R, G, B);
                // make pen out of color
                int width = random.Next(2, 8);
                return new Pen(color, width);
            }
    
            static public void DrawShape(Graphics graphics)    // 画随机线
            {
                Pen pen = GetPen();
                int x1 = random.Next(0, (int)graphics.VisibleClipBounds.Width);
                int y1 = random.Next(0, (int)graphics.VisibleClipBounds.Height);
                int x2 = random.Next(0, (int)graphics.VisibleClipBounds.Width);
                int y2 = random.Next(0, (int)graphics.VisibleClipBounds.Height);
                graphics.DrawLine(pen, x1, y1, x2, y2);
            }
        }
    }

     

    生成Windows屏幕保护程序,正常编译得到exe文件,把"exe"改名为"scr",可拷贝到Windows的"System32"目录中
     scr文件右键对应的菜单传递的参数:Test为/s,安装为/p和句柄参数,配置为空(不是/c)
     系统的"屏幕保护程序设置":下图的按钮"设置"和"预览"点击后分别被系统调用了两次,

    "设置"第一次对应 (/c加一个整数句柄)参数调用(一个参数) ,第二次对应 (/p)和(句柄参数)参数调用(两个参数)

    "预览"第一次对应(/s)参数调用 ,第二次对应 (/p)和(句柄参数)参数调用(两个参数)
    "设置"点击后根据句柄参数可以打开设置窗体,"预览"点击后在主屏幕上预览,两者完毕后都在"预览"窗口显示预览(实际上是以预览参数又一次调用我们的屏保程序)

      微软官方设置参数说明

     存在的疑问是:怎么在屏保预览窗口显示屏保,如下

    这是我偶然试出来的,不明白为啥。就是必须在预览参数的代码段里实例化屏保窗体但却不使用:Form1 form1 = new Form1();    // 必须有此句预览窗口才有显示输出(到底起了什么作用?很奇怪!)

     最开始确实是要实例化窗体的,因为要重复使用窗体类画图的代码,结果不行,没办法才在Main方法里重新搞了一遍,结果无意中可以预览了,真是神奇。

    点我下载源码

    点我下载现成的屏保

  • 相关阅读:
    新书推荐——《How We Test Software at Microsoft》
    [ZZ]采访与书摘:使用C#进行基于模型的软件测试和分析
    Adding Different Types of Data Sources to a Web Test
    [ZZ]为什么传统的自动化测试工具会扼杀敏捷?
    很久没有这么High了
    留图以纪念这次地震
    white——Automate windows applications
    WatiN、Wax、WatiN Test Recorder开源自动化测试框架
    绝版的T61普屏
    有感于公司搬家
  • 原文地址:https://www.cnblogs.com/chengyb/p/14016161.html
Copyright © 2020-2023  润新知