C# 软件Licence应用实例

这篇具有很好参考价值的文章主要介绍了C# 软件Licence应用实例。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

我们在使用一些需要购买版权的软件产品时,或者我们做的商业软件需要进行售卖,为了收取费用,一般需要一个软件使用许可证,然后输入这个许可到软件里就能够使用软件。简单的是一串序列码或者一个许可证文件,复杂的是一个定制化插件包。于是有的小伙伴就开始好奇这个许可是怎么实现的,特别是在离线情况下它是怎么给软件授权,同时又能避免被破解的。

C# 软件Licence应用实例

 

License应用场景

 

本文主要介绍的是许可证形式的授权。

 

1. 如何控制只在指定设备上使用

 

如果不控制指定设备,那么下发了许可证,只要把软件复制多份安装则可到处使用,不利于版权维护,每个设备都有唯一标识:mac地址,ip地址,主板序列号等,在许可证中指定唯一标识则只能指定设备使用。

 

2. 如何控制软件使用期限

 

为了版权可持续性收益,对软件使用设置期限,到期续费等,则需要在许可证中配置使用起止日期。

 

Licence实现方案

 

一、流程设计

 

  • 形式:许可证以文件形式下发,放在客户端电脑指定位置
  • 内容:以上控制内容以dom节点形式放在文件中
  • 流程:将控制项加密后写入license文件节点,部署到客户机器,客户机使用时再读取license文件内容与客户机实际参数进行匹配校验

 

二、文件防破解

 

  • 防止篡改:文件内容加密,使用AES加密,但是AES加密解密都是使用同一个key;使用非对称公私钥(本文使用的RSA)对内容加密解密,但是对内容长度有限制;综合方案,将AES的key(内部定义)用RSA加密,公钥放在加密工具中,内部持有,私钥放在解密工具中,引入软件产品解密使用。
  • 防止修改系统时间绕过许可证使用时间:许可证带上发布时间戳,并定时修改运行时间记录到文件,如果系统时间小于这个时间戳,就算大于许可证限制的起始时间也无法使用
  • 提高破解难度:懂技术的可以将代码反编译过来修改代码文件直接绕过校验,所以需要进行代码混淆,有测试过xjar的混淆效果比较好。

 

Licence验证流程图

 

关于Licence验证软件合法性流程图,如下所示:

C# 软件Licence应用实例

 

核心源码

 

本实例主要讲解Licence的实际验证过程,分为三部分:

  1. 测试客户端【LicenceTest】,主要用于模拟客户端验证Licence的过程。
  2. 生成工具【LicenceTool】,主要用于根据客户生成的电脑文件,生成对应的Licence。
  3. LicenceCommon,Licence公共通用类,主要实现电脑信息获取,非对称加密,文件保存等功能。

 

1. LicenceCommon

 

1.1 电脑信息获取

 

主要通过ManagementClass进行获取客户端电脑硬件相关配置信息,如下所示:

using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;

namespace DemoLicence.Common
{
    public class ComputerHelper
    {
        public static Dictionary<string,string> GetComputerInfo()
        {
            var info = new Dictionary<string,string>();
            string cpu = GetCPUInfo();
            string baseBoard = GetBaseBoardInfo();
            string bios = GetBIOSInfo();
            string mac = GetMACInfo();
            info.Add("cpu", cpu);
            info.Add("baseBoard", baseBoard);
            info.Add("bios", bios);
            info.Add("mac", mac);
            return info;
        }
        private static string GetCPUInfo()
        {
            string info = string.Empty;
            info = GetHardWareInfo("Win32_Processor", "ProcessorId");
            return info;
        }
        private static string GetBIOSInfo()
        {
            string info = string.Empty;
            info = GetHardWareInfo("Win32_BIOS", "SerialNumber");
            return info;
        }
        private static string GetBaseBoardInfo()
        {
            string info = string.Empty;
            info = GetHardWareInfo("Win32_BaseBoard", "SerialNumber");
            return info;
        }
        private static string GetMACInfo()
        {
            string info = string.Empty;
            info = GetMacAddress();//GetHardWareInfo("Win32_NetworkAdapterConfiguration", "MACAddress");
            return info;
        }

        private static string GetMacAddress()
        {
            var mac = "";
            var mc = new ManagementClass("Win32_NetworkAdapterConfiguration");
            var moc = mc.GetInstances();
            foreach (var o in moc)
            {
                var mo = (ManagementObject)o;
                if (!(bool)mo["IPEnabled"]) continue;
                mac = mo["MacAddress"].ToString();
                break;
            }
            return mac;
        }

        private static string GetHardWareInfo(string typePath, string key)
        {
            try
            {
                ManagementClass managementClass = new ManagementClass(typePath);
                ManagementObjectCollection mn = managementClass.GetInstances();
                PropertyDataCollection properties = managementClass.Properties;
                foreach (PropertyData property in properties)
                {
                    if (property.Name == key)
                    {
                        foreach (ManagementObject m in mn)
                        {
                            return m.Properties[property.Name].Value.ToString();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                //这里写异常的处理
            }
            return string.Empty;
        }
    }
}

 

1.3 RSA非对称加密

 

主要对客户端提供的电脑信息及有效期等内容,进行非对称加密,如下所示:

public class RSAHelper
{

	private static string keyContainerName = "star";

	private static string m_PriKey = string.Empty;

	private static string m_PubKey = string.Empty;


	public static string PriKey
	{
		get
		{
			return m_PriKey;
		}

		set
		{
			m_PriKey = value;
		}
	}

	public static string PubKey
	{
		get
		{
			return m_PubKey;
		}

		set
		{
			m_PubKey = value;
		}
	}

	public static string Encrypto(string source)
	{
		if (string.IsNullOrEmpty(m_PubKey) && string.IsNullOrEmpty(m_PriKey))
		{
			generateKey();
		}
		return getEncryptoInfoByRSA(source);
	}

	public static string Decrypto(string dest)
	{
		if (string.IsNullOrEmpty(m_PubKey) && string.IsNullOrEmpty(m_PriKey))
		{
			generateKey();
		}
		return getDecryptoInfoByRSA(dest);
	}

	public static void generateKey()
	{
		CspParameters m_CspParameters;
		m_CspParameters = new CspParameters();
		m_CspParameters.KeyContainerName = keyContainerName;
		RSACryptoServiceProvider asym = new RSACryptoServiceProvider(m_CspParameters);
		m_PriKey = asym.ToXmlString(true);
		m_PubKey = asym.ToXmlString(false);
		asym.PersistKeyInCsp = false;
		asym.Clear();
	}

	private static string getEncryptoInfoByRSA(string source)
	{
		byte[] plainByte = Encoding.ASCII.GetBytes(source);
		//初始化参数
		RSACryptoServiceProvider asym = new RSACryptoServiceProvider();
		asym.FromXmlString(m_PubKey);
		int keySize = asym.KeySize / 8;//非对称加密,每次的长度不能太长,否则会报异常
		int bufferSize = keySize - 11;
		if (plainByte.Length > bufferSize)
		{
			throw new Exception("非对称加密最多支持【" + bufferSize + "】字节,实际长度【" + plainByte.Length + "】字节。");
		}
		byte[] cryptoByte = asym.Encrypt(plainByte, false);
		return Convert.ToBase64String(cryptoByte);
	}

	private static string getDecryptoInfoByRSA(string dest)
	{
		byte[] btDest = Convert.FromBase64String(dest);
		//初始化参数
		RSACryptoServiceProvider asym = new RSACryptoServiceProvider();
		asym.FromXmlString(m_PriKey);
		int keySize = asym.KeySize / 8;//非对称加密,每次的长度不能太长,否则会报异常
									   //int bufferSize = keySize - 11;
		if (btDest.Length > keySize)
		{
			throw new Exception("非对称解密最多支持【" + keySize + "】字节,实际长度【" + btDest.Length + "】字节。");
		}
		byte[] cryptoByte = asym.Decrypt(btDest, false);
		return Encoding.ASCII.GetString(cryptoByte);
	}
}

 

1.3 生成文件

 

主要是加密后的信息,和解密秘钥等内容,保存到文件中,如下所示:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DemoLicence.Common
{
    public class RegistFileHelper
    {
        public static string ComputerInfofile = "ComputerInfo.key";
        public static string RegistInfofile = "Licence.key";
        public static void WriteRegistFile(string info,string keyFile)
        {
            string tmp = string.IsNullOrEmpty(keyFile)?RegistInfofile:keyFile;
            WriteFile(info, tmp);
        }
        public static void WriteComputerInfoFile(string info)
        {
            WriteFile(info, ComputerInfofile);
        }
        public static string ReadRegistFile(string keyFile)
        {
            string tmp = string.IsNullOrEmpty(keyFile) ? RegistInfofile : keyFile;
            return ReadFile(tmp);
        }
        public static string ReadComputerInfoFile(string file)
        {
            string tmp = string.IsNullOrEmpty(file) ? ComputerInfofile : file;
            return ReadFile(tmp);
        }

        private static void WriteFile(string info, string fileName)
        {
            try
            {
                using (StreamWriter sw = new StreamWriter(fileName, false))
                {
                    sw.Write(info);
                    sw.Close();
                }
            }
            catch (Exception ex)
            {
            }
        }
        private static string ReadFile(string fileName)
        {
            string info = string.Empty;
            try
            {
                using (StreamReader sr = new StreamReader(fileName))
                {
                    info = sr.ReadToEnd();
                    sr.Close();
                }
            }
            catch (Exception ex)
            {
            }
            return info;
        }
    }
}

以上这三部分,各个功能相互独立,通过LicenceHelper相互调用,如下所示:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;

namespace DemoLicence.Common
{
    public class LicenceHelper
    {
        /// <summary>
        /// 获取电脑信息,并生成文件
        /// </summary>
        public static string GetComputerInfoAndGenerateFile()
        {
            string computerKeyFile = string.Empty;
            try
            {
                var info = GetComputerInfo();
                if (info != null && info.Count > 0)
                {
                    //获取到电脑信息
                    var strInfo = new StringBuilder();
                    foreach (var computer in info)
                    {
                        strInfo.AppendLine($"{computer.Key}={computer.Value}");
                    }
                    RegistFileHelper.WriteComputerInfoFile(strInfo.ToString());
                    computerKeyFile = RegistFileHelper.ComputerInfofile;
                }
            }catch(Exception ex)
            {
                throw ex;
            }
            return computerKeyFile;
        }

        public static Dictionary<string,string> GetComputerInfo()
        {
            var info = ComputerHelper.GetComputerInfo();
            return info;
        }

        public static bool CheckLicenceKeyIsExists()
        {
            var keyFile = RegistFileHelper.RegistInfofile;
            if (File.Exists(keyFile))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public static string GetComputerInfo(string computerInfoFile)
        {
            return RegistFileHelper.ReadComputerInfoFile(computerInfoFile);
        }

        public static void GenerateLicenceKey(string info,string keyfile)
        {
            string encrypto = RSAHelper.Encrypto(info);
            string priKey = RSAHelper.PriKey;//公钥加密,私钥解密
            byte[] priKeyBytes = Encoding.ASCII.GetBytes(priKey);
            string priKeyBase64=Convert.ToBase64String(priKeyBytes);
            StringBuilder keyInfo= new StringBuilder();
            keyInfo.AppendLine($"prikey={priKeyBase64}");
            keyInfo.AppendLine($"encrypto={encrypto}");
            RegistFileHelper.WriteRegistFile(keyInfo.ToString(), keyfile);
        }

        public static string ReadLicenceKey(string keyfile)
        {
            var keyInfo = RegistFileHelper.ReadRegistFile(keyfile);
            if (keyInfo == null)
            {
                return string.Empty;
            }
            string[] keyInfoArr = keyInfo.Split("\r\n");
            var priKeyBase64 = keyInfoArr[0].Substring(keyInfoArr[0].IndexOf("=")+1);
            var encrypto = keyInfoArr[1].Substring(keyInfoArr[1].IndexOf("=")+1);
            var priKeyByte= Convert.FromBase64String(priKeyBase64);
            var priKey = Encoding.ASCII.GetString(priKeyByte);
            RSAHelper.PriKey= priKey;
            var info = RSAHelper.Decrypto(encrypto);
            return info;
        }

        public static string GetDefaultRegisterFileName()
        {
            return RegistFileHelper.RegistInfofile;
        }

        public static string GetDefaultComputerFileName()
        {
            return RegistFileHelper.ComputerInfofile;
        }
        
        public static string GetPublicKey()
        {
            if (string.IsNullOrEmpty(RSAHelper.PubKey))
            {
                RSAHelper.generateKey();
            }
            return RSAHelper.PubKey;
        }

        public static string GetPrivateKey()
        {
            if (string.IsNullOrEmpty(RSAHelper.PriKey))
            {
                RSAHelper.generateKey();
            }
            return RSAHelper.PriKey;
        }
    }
}

 

2. 客户端LicenceTest

 

客户端验证Licence的有效性,当Licence有效时,正常使用软件,当Licence无效时,则不能正常使用软件。如下所示:

using DemoLicence.Common;

namespace LicenceTest
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            try
            {

                string info = string.Empty;
                string msg = string.Empty;
                //初始化加载
                if (LicenceHelper.CheckLicenceKeyIsExists())
                {
                    string keyFile = LicenceHelper.GetDefaultRegisterFileName();
                    info = LicenceHelper.ReadLicenceKey(keyFile);
                }
                else
                {
                    var dialogResult = MessageBox.Show("没有找到默认首选文件,是否手动选择授权文件?", "询问", MessageBoxButtons.YesNo);
                    if (dialogResult == DialogResult.Yes)
                    {
                        OpenFileDialog openFileDialog = new OpenFileDialog();
                        openFileDialog.Title = "请选择授权文件";
                        openFileDialog.FileName = LicenceHelper.GetDefaultRegisterFileName();
                        if (openFileDialog.ShowDialog() == DialogResult.OK)
                        {
                            var keyFile = openFileDialog.FileName;
                            info = LicenceHelper.ReadLicenceKey(keyFile);
                            //验证成功后,将手动选择的文件复制到程序根目录,且修改为默认名称
                            File.Copy(keyFile, LicenceHelper.GetDefaultRegisterFileName());

                        }
                        else
                        {
                            string computerFile = LicenceHelper.GetComputerInfoAndGenerateFile();
                            if (!string.IsNullOrEmpty(computerFile))
                            {
                                msg = $"您还没有被授权,请将程序根目录下的{computerFile}文件,发送到管理员,获取Licence.";
                            }
                        }
                    }
                    else
                    {
                        string computerFile = LicenceHelper.GetComputerInfoAndGenerateFile();
                        if (!string.IsNullOrEmpty(computerFile))
                        {
                            msg = $"您还没有被授权,请将程序根目录下的{computerFile}文件,发送到管理员,获取Licence.";
                        }
                    }
                }
                if (!string.IsNullOrEmpty(info) && string.IsNullOrEmpty(msg))
                {
                    string[] infos = info.Split("\r\n");
                    if (infos.Length > 0)
                    {
                        var dicInfo = new Dictionary<string, string>();
                        foreach (var info2 in infos)
                        {
                            if (string.IsNullOrEmpty(info2))
                            {
                                continue;
                            }
                            var info2Arr = info2.Split("=");
                            dicInfo.Add(info2Arr[0], info2Arr[1]);
                        }
                        if (dicInfo.Count > 0)
                        {
                            string localMacAddress = string.Empty;
                            var computerInfo = LicenceHelper.GetComputerInfo();
                            if (computerInfo != null)
                            {
                                localMacAddress = computerInfo["mac"];
                            }
                            //比较本地信息和Licence中的信息是否一致
                            if (localMacAddress == dicInfo["mac"])
                            {
                                var endTime = DateTime.Parse(dicInfo["endTime"]);
                                if (DateTime.Now < endTime)
                                {
                                    //在有效期内,可以使用
                                }
                                else
                                {
                                    msg = $"软件授权使用时间范围:[{endTime}之前],已过期";
                                }
                            }
                            else
                            {
                                msg = "软件Licence不匹配";
                            }
                        }
                        else
                        {
                            msg = $"软件Licence非法.";
                        }
                    }
                    else
                    {
                        msg = $"软件Licence非法.";
                    }
                }
                if (!string.IsNullOrEmpty(msg))
                {
                    MessageBox.Show(msg);
                    foreach (var control in this.Controls)
                    {
                        (control as Control).Enabled = false;
                    }
                    return;
                }
            }
            catch (Exception ex)
            {
                string error = $"程序异常,请联系管理人员:{ex.Message}\r\n{ex.StackTrace}";
                MessageBox.Show(error);
                foreach (var control in this.Controls)
                {
                    (control as Control).Enabled = false;
                }
            }
        }
    }
}

 

3. Licence生成工具

 

LicenceTool主要根据客户端提供的电脑信息,生成对应的Licence,然后再发送给客户端,以此达到客户端电脑的授权使用软件的目的。如下所示:

using DemoLicence.Common;
using System.Text;

namespace LicenceTool
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        }


        private void MainForm_Load(object sender, EventArgs e)
        {
            this.txtPublicKey.Text=LicenceHelper.GetPublicKey();
            this.txtPrivateKey.Text=LicenceHelper.GetPrivateKey();
        }



        private void btnBrowser_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = "电脑信息文件|*.key";
            ofd.Multiselect = false;
            ofd.Title = "请选择电脑信息文件";
            ofd.FileName=LicenceHelper.GetDefaultComputerFileName();
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                this.txtSourceFile.Text = ofd.FileName;
            }
        }

        private void btnGenerate_Click(object sender, EventArgs e)
        {

            try
            {
                if (string.IsNullOrEmpty(this.txtSourceFile.Text))
                {
                    MessageBox.Show("请先选择电脑信息文件");
                    return;
                }
                if (File.Exists(this.txtSourceFile.Text))
                {
                    //读取电脑文件
                    var info = LicenceHelper.GetComputerInfo(this.txtSourceFile.Text);
                    int days = GetLicenceDays();
                    var keyInfos = new StringBuilder(info);
                    var beginTime = DateTime.Now;
                    var endTime = DateTime.Now.AddDays(days);
                    //keyInfos.AppendLine($"beginTime={beginTime.ToString("yyyy-MM-dd HH:mm:ss")}");
                    keyInfos.AppendLine($"endTime={endTime.ToString("yyyy-MM-dd HH:mm:ss")}");
                    //
                    info = keyInfos.ToString();
                    SaveFileDialog saveFileDialog = new SaveFileDialog();
                    saveFileDialog.Title = "保存生成的Licence文件";
                    saveFileDialog.FileName = LicenceHelper.GetDefaultRegisterFileName();
                    if (saveFileDialog.ShowDialog() == DialogResult.OK)
                    {
                        LicenceHelper.GenerateLicenceKey(info, saveFileDialog.FileName);
                        MessageBox.Show("生成成功");
                    }
                }
                else
                {
                    MessageBox.Show("电脑信息文件不存在!");
                    return;
                }
            }catch(Exception ex)
            {
                string error = $"生成出错:{ex.Message}\r\n{ex.StackTrace}";
                MessageBox.Show(error);
            }
        }

        /// <summary>
        /// 获取有效期天数
        /// </summary>
        /// <returns></returns>
        private int GetLicenceDays()
        {
            int days = 1;
            RadioButton[] rbtns = new RadioButton[] { this.rbtSeven, this.rbtnTen, this.rbtnFifteen, this.rbtnThirty, this.rbtnSixty, this.rbtnSixMonth, this.rbtnNinety, this.rbtnSixMonth, this.rbtnForver };
            foreach (RadioButton rb in rbtns)
            {
                if (rb.Checked)
                {
                    if (!int.TryParse(rb.Tag.ToString(), out days))
                    {
                        days = 0;
                    }
                    break;
                }
            }
            days = days == -1 ? 9999 : days;//永久要转换一下
            return days;
        }
    }
}

 

测试验证

 

启动软件时会进行校验,在没有Licence时,会有信息提示,且无法使用软件,如下所示:

C# 软件Licence应用实例

Lincence生成工具

根据客户提供的电脑信息文件,生成对应的Licence,如下所示:

C# 软件Licence应用实例

生成Licence放在客户端默认目录下,即可正常使用软件,如下所示:
C# 软件Licence应用实例

注意:非对称加密每次生成的秘钥都是不同的,所以需要将解密秘钥一起保存到生成的Licence文件中,否则秘钥不同,则无法解密。

生成的电脑信息文件ComputerInfo.key示例如下所示:

C# 软件Licence应用实例

生成的Licence.key文件内容,如下所示:

C# 软件Licence应用实例

 

源码下载

 

源码下载可以通过以下3种方式,

 

1. 公众号关键词回复

 

关注个人公众号,回复关键字【Licence】获取源码,如下所示:

C# 软件Licence应用实例

 

2. 通过gitee(码云)下载

 

本示例中相关源码,已上传至gitee(码云),链接如下:

C# 软件Licence应用实例

 

3. 通过CSDN进行下载

 

通过CSDN上的资源进行付费下载,不贵不贵,也就一顿早餐的钱。

https://download.csdn.net/download/fengershishe/88294433?spm=1001.2014.3001.5501

C# 软件Licence应用实例

以上就是软件Licence应用实例的全部内容,希望可以抛砖引玉,一起学习,共同进步。学习编程,从关注【老码识途】开始!!!文章来源地址https://www.toymoban.com/news/detail-692287.html

到了这里,关于C# 软件Licence应用实例的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 为什么kafka 需要 subscribe 的 group.id?我们是否需要使用 commitSync 手动提交偏移量?

    消费概念: Kafka 使用消费者组的概念来实现主题的并行消费 - 每条消息都将在每个消费者组中传递一次,无论该组中实际有多少个消费者。所以 group 参数是强制性的,如果没有组,Kafka 将不知道如何对待订阅同一主题的其他消费者。 偏移量 : 每当我们启动一个消费者时,

    2024年02月12日
    浏览(57)
  • C# Web应用调用EXE文件的一些实践

    目录 需求 范例运行环境 可执行文件的设计 调用可执行文件方法 RunExecuteFile RunShellExecuteFile 方法的区别 WEB调用举例 小结 最近同事使用Python开发了一款智能文字转语音的程序,经讨论部署在WINDOWS环境服务器下,因此需要生成目标为可执行程序文件,即EXE文件。需要在WEB应用

    2024年04月09日
    浏览(39)
  • C# DataGridView控件的基础应用实例

      DataGridView我把他叫做网格数据控件 。我们在显示表格数据的时候,经常会用想到用它, 他就像Excel表格一样。我们知道只要是数据表,就一定逃不掉表的增删查改操作。   该篇,我在VS2019的环境下通过demo实例来实现DataGridView控件的一系列功能,包括添加一行数据、切

    2023年04月09日
    浏览(48)
  • 【golang】使用通道时需要注意的一些问题

    Go 1.20 Windows 11 1.定义通道变量: 2.通道遵循FIFO先入先出规则,可以保证元素的顺序 3.通道是并发安全的,不会因多个协程的同时写入而发生数据错乱 下面的代码例子会经常出现调用 display 函数,这是我自己定义的一个函数,主要用于打印信息,代码如下: 为了减少代码冗余

    2024年02月12日
    浏览(95)
  • Ant-Design 官方网站总是打不开,那么我们则需要使用以下该官网的镜像地址来打开;

      1、 Ant-Design 官网原地址: https://ant.design/index-cn Ant-Design 官网镜像地址:http://ant-design.gitee.io/index-cn 或者  Ant Design - 一套企业级 UI 设计语言和 React 组件库   2、 Ant-Design-Pro 原地址: https://pro.ant.design/index-cn Ant-Design-Pro 镜像地址:http://ant-design-pro.gitee.io/index-cn   3、

    2024年02月12日
    浏览(48)
  • C#实例:多功能Windows窗体应用程序Helloworld_WinForm

    有了创建一个Windows窗体应用程序的经验,就可以开始尝试运用更多的控件实现更多丰富的功能界面。以下分享我基于项目Helloworld_WinForm 使用常用C#Windows窗体控件 实现一些小功能。 每一节标题为所用到的控件,全文以实际制作过程为序编制。 1、创建窗体Form 项目创建时会默

    2024年02月04日
    浏览(59)
  • C# 使用Interop.Excel一些报错的对应

    1.报错:C# 必须添加对程序集“office, Version=15.0.0.0, …… 在开发环境,右击引用,选“添加引用”,如图 选中红线内容 2.报错:程序集“Microsoft.Office.Interop.Excel”所使用的“office, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c”版本高于所引用的标识为“office, Version=14.

    2024年02月05日
    浏览(51)
  • Linux分布式应用 Zabbix监控软件实例:监控NGINX的性能

        测试 访问设置的网站 获取NGINX状态统计 过滤结果获取需要的值     服务器端验证     ​​​创建模板 点击左边菜单栏【配置】中的【模板】,点击【创建模板】 【模板名称】设置成 Template NGINX Status 【可见的名称】设置成 Template NGINX Status 【群组】选择 Template 【描述

    2024年02月15日
    浏览(51)
  • HALCON的综合应用案例【01】: 3D 算法处理在 Visual Studio 2019 C# 环境中的集成实例

    HALCON 为一款比较流行的商业视觉处理软件,他提供了多种开发的模式,可以在HALCON中开发,也可以将HALCON的设计通过导出库的形式集成到其他开发环境里面,以方便系统集成。本文为笔者自己的一个3D 视觉检测项目,利用HALCON的3D 库开发算法,然后,将算法集成到 MS-VS-C#的环

    2024年02月06日
    浏览(49)
  • C#使用IronPython调用Python脚本实例

    本文 详细讲解在C#中调用Python脚本的 实例 。 首先 本文假设您已经安装好了Python环境和对应的库。 目录 一、IronPython简述

    2024年02月10日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包