想实现这样的一个试用版的软件给用户体验,如果用户觉得满意的话,会索要激活码激活使用正式版,下面就讲笔者的一个实现方案,可以参考参考

关于能看懂的条件

  • 会使用Visual Studio 开发工具
  • 熟悉WinForm项目
  1. 首先,需要生成一个序列号,必须是设备唯一的ID,通过读取用户的PC设备硬件ID来组合生成,下面是Hardware.cs类的实现,获取硬件信息生成序列号,类似手机的IMEI识别码
using System;
using System.Collections.Generic;
using System.Management;
using System.Text.RegularExpressions;

namespace WindowsFormsApp2.lib
{
    /// <summary>
    /// 硬件信息
    /// </summary>
    public class Hardware
    {
        //获取CPU序列号
        public string GetCPUSerialNumber()
        {
            try
            {
                ManagementObjectSearcher searcher = new ManagementObjectSearcher("Select * From Win32_Processor");
                string sCPUSerialNumber = "";
                foreach (ManagementObject mo in searcher.Get())
                {
                    sCPUSerialNumber = mo["ProcessorId"].ToString().Trim();
                    break;
                }
                return sCPUSerialNumber;
            }
            catch
            {
                return "";
            }
        }


        //获取主板序列号
        public string GetBIOSSerialNumber()
        {
            try
            {
                ManagementObjectSearcher searcher = new ManagementObjectSearcher("Select * From Win32_BIOS");
                string sBIOSSerialNumber = "";
                foreach (ManagementObject mo in searcher.Get())
                {
                    sBIOSSerialNumber = mo.GetPropertyValue("SerialNumber").ToString().Trim();
                    break;
                }
                return sBIOSSerialNumber;
            }
            catch
            {
                return "";
            }
        }


        //获取硬盘序列号
        public string GetHardDiskSerialNumber()
        {
            try
            {
                ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_PhysicalMedia");
                string sHardDiskSerialNumber = "";
                foreach (ManagementObject mo in searcher.Get())
                {
                    sHardDiskSerialNumber = mo["SerialNumber"].ToString().Trim();
                    break;
                }
                return sHardDiskSerialNumber;
            }
            catch
            {
                return "";
            }
        }

		/// <summary>
        /// 获取序列号
        /// </summary>
        /// <returns></returns>
        public String GetTheSerialNumber()
        {
            var h = this;
            String res = h.GetBIOSSerialNumber() + " " + h.GetHardDiskSerialNumber() + " " + h.GetCPUSerialNumber();
            res = Regex.Replace(res, @"[\s+\-\._\/]", "");
            var res2 = "";
            for(int i=0; i<res.Length; i++)
            {
                if (i >= 40) break;
                if (i>0 && i % 4 == 0) res2 += "-";
                res2 += res[i];
            }
            return res2.ToUpper();
        }
        
		/// <summary>
        /// 转换处理,可以说成算法,自己编成独特的
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        public String decode(String text)
        {
        	//...具体实现过程需要自己编写
        }
    }
}
  1. 怎么写一个自己构造的独特算法呢,晒一下笔者的decode()方法实现,计算出激活码就可以跟用户输入的激活码来比对,无问题的话,就在用户的PC设备中存储好,提示用户已激活,需要重启就好
/// <summary>
/// 转换处理,可以说成算法,自己编成独特的
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
public String decode(String text)
{
    var lines = text.Split('-');
    var nums = new List<int>();
    for (int i = 0; i < lines.Length; i++)
    {
        var line = lines[i];
        int num = 0;
        for (int j = 0; j < line.Length; j++)
        {
            int n = 0;
            switch (line[j])
            {
                case 'A':
                case 'a':
                    n = 10;
                    break;
                case 'B':
                case 'b':
                    n = 11;
                    break;
                case 'C':
                case 'c':
                    n = 12;
                    break;
                case 'D':
                case 'd':
                    n = 13;
                    break;
                case 'E':
                case 'e':
                    n = 14;
                    break;
                case 'F':
                case 'f':
                    n = 15;
                    break;
                case 'G':
                case 'g':
                    n = 16;
                    break;
                case 'H':
                case 'h':
                    n = 17;
                    break;
                case 'I':
                case 'i':
                    n = 18;
                    break;
                case 'J':
                case 'j':
                    n = 19;
                    break;
                case 'K':
                case 'k':
                    n = 20;
                    break;
                case 'L':
                case 'l':
                    n = 21;
                    break;
                case 'M':
                case 'm':
                    n = 22;
                    break;
                case 'N':
                case 'n':
                    n = 23;
                    break;
                case 'O':
                case 'o':
                    n = 24;
                    break;
                case 'P':
                case 'p':
                    n = 25;
                    break;
                case 'Q':
                case 'q':
                    n = 26;
                    break;
                case 'R':
                case 'r':
                    n = 27;
                    break;
                case 'S':
                case 's':
                    n = 28;
                    break;
                case 'T':
                case 't':
                    n = 29;
                    break;
                case 'U':
                case 'u':
                    n = 30;
                    break;
                case 'V':
                case 'v':
                    n = 31;
                    break;
                case 'W':
                case 'w':
                    n = 32;
                    break;
                case 'X':
                case 'x':
                    n = 33;
                    break;
                case 'Y':
                case 'y':
                    n = 34;
                    break;
                case 'Z':
                case 'z':
                    n = 35;
                    break;
                default:
                    int.TryParse(line[j].ToString(), out n);
                    break;
            }
            num += n;
            if (j + 1 < line.Length) num += (int)Math.Pow(10, line.Length - j - 1);
        }
        nums.Add(num);
    }

    String res = "";
    foreach (var num in nums)
    {
        var str = num.ToString();
        if (res.Length > 0) res += "-";
        res += str;
    }
    return res;
}
  1. 在程序启动的一个主窗口Form1逻辑中需要做一下处理,参考如下代码段,这样启动程序要先判断是否存在保存的激活码文件,如果存在,就执行算法比对文件中的激活码,对的话,就变成正式版,若不对的话,就是默认试用版,使用功能受限
namespace WindowsFormsApp2
{
    /// <summary>
    /// 启动主窗口
    /// </summary>
    public partial class Form1 : Form, CommonListener
    {
        public Form1()
        {
            InitializeComponent();
        }
        
        bool isActive = false;
        //激活窗口
		Form2 f = new Form2();

        private void Form1_Load(object sender, EventArgs e)
        {
        	//h 就是 Hardware 对象
            var h = f.h;
			//这里是使用激活窗口里的方法来获取用户设备序列号
            f.serialNuber = h.GetTheSerialNumber();
            //存有激活码的文件
            var path = Form2.getKeyFilePath();
            if (File.Exists(path))
            {
                var lines = File.ReadAllLines(path);
                if (lines.Length > 0)
                {
                	//激活码放在第一行了
                    var key = lines[0];
                    //判断是否跟计算得出激活码的一致
                    if (key == h.decode(f.serialNuber))
                    {
                        f.keyNuber = key;
                        //改为已激活状态
                        isActive = true;

                        if (lines.Length > 1)
                        {
                            //...这里可处理其它的
                        }
                        return;
                    }
                }
            }

            Text += "(试用版)";
        }
   }
}
  1. 基本激活窗口Form2就只有三个组件,一个输入框为序列号并设为只读属性,另一个输入框由用户输入激活码,还有一个点击激活按钮
namespace WindowsFormsApp2
{
    /// <summary>
    /// 激活窗口
    /// </summary>
    public partial class Form2 : Form
    {
        public Hardware h = new Hardware();

        public Form2()
        {
            InitializeComponent();
        }

        public String serialNuber = "";
        public String keyNuber = "";

        private void Form2_Load(object sender, EventArgs e)
        {
            //初始化显示
            Text = "激活";

            label1.Text = "序列号:";
            label2.Text = "激活码:";
            label3.Text = "激活后,系统使用无限制,请激活找******";

            //判断序列号长度
            if (serialNuber.Length>0)
            {
                textBox1.Text = serialNuber;
                textBox1.ReadOnly = true;
            }
            //判断激活码长度
            if (keyNuber.Length>0)
            {
                textBox2.Text = keyNuber;
                textBox2.ReadOnly = true;

                button1.Text = "已激活";
                button1.Enabled = false;
            }
            else
            {
                button1.Text = "确定激活";
            }
        }

        /// <summary>
        /// 点击 确定激活 按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            //计算激活码
            var resutl = h.decode(textBox1.Text);
            
            //核对用户输入的激活码是否一致
            if (textBox2.Text!=resutl)
            {
                MessageBox.Show("激活码不正确!", "激活失败!", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                Close();
                return;
            }

            //激活成功,生成一个文件key.ini,写入激活码,下次启动就读取该文件验证是否可激活使用
            var path = getKeyFilePath();
            File.WriteAllText(path, resutl);

            MessageBox.Show("写入在key.ini文件中,请保留它,关闭程序重新打开,可激活使用!", "激活成功!", MessageBoxButtons.OK, MessageBoxIcon.Information);
            Close();
        }

        public static String getKeyFilePath()
        {
            return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "key.ini");
        }
    }
}
  1. 激活的过程大致思路已实现,接下来讲讲激活工具窗口Form3,和上面的激活窗口Form2看着一样,也许有读书会想:激活工具窗口 放在一起会不会不太合适呢,放心吧,目前这个窗口是隐藏的,具体怎么用,后面会讲
namespace WindowsFormsApp2
{
    public partial class Form3 : Form
    {
        public Form3()
        {
            InitializeComponent();
        }

        private void Form3_Load(object sender, EventArgs e)
        {
            Text = "激活工具";
            label1.Text = "序列号:";
            label2.Text = "激活码:";
            button1.Text = "激活";
        }

        /// <summary>
        /// 点击激活
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            var h = new Hardware();

            textBox2.Text = h.decode(textBox1.Text);
        }
    }
}
  1. 在程序入口Program处, 添加一个判断,这里有加了小动作,不曾想尝试自己独立弄一个激活工具自己保管,结果那一天自己忙到想不起放哪里却找不到,或者不小心搞丢,那只能在桌上发呆😳,小动作自己拿到小本本记到,从此心里有个小秘密🤭
namespace WindowsFormsApp2
{
    static class Program
    {
        /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        [STAThread]
        static void Main(String[] args)
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            //通过CMD窗口对程序输入命令,格式 WindowsFormsApp2 -activate bibibibibibi...
            if (args.Length==2 && args[0]=="-activate" && args[1]=="bibibibibibi...")
            {
            	//打开激活工具
                Application.Run(new Form3());
            }
            else
            {
            	//运行主程序
                Application.Run(new Form1());
            }
        }
    }
}