惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

L
LangChain Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Attack and Defense Labs
Attack and Defense Labs
T
Tor Project blog
Scott Helme
Scott Helme
Schneier on Security
Schneier on Security
Security Archives - TechRepublic
Security Archives - TechRepublic
S
Security @ Cisco Blogs
GbyAI
GbyAI
Help Net Security
Help Net Security
T
Troy Hunt's Blog
Recent Announcements
Recent Announcements
Engineering at Meta
Engineering at Meta
L
LINUX DO - 最新话题
TaoSecurity Blog
TaoSecurity Blog
AWS News Blog
AWS News Blog
Y
Y Combinator Blog
SecWiki News
SecWiki News
Microsoft Azure Blog
Microsoft Azure Blog
Spread Privacy
Spread Privacy
A
About on SuperTechFans
Stack Overflow Blog
Stack Overflow Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
Google DeepMind News
Google DeepMind News
NISL@THU
NISL@THU
T
Threat Research - Cisco Blogs
S
Securelist
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
雷峰网
雷峰网
H
Help Net Security
AI
AI
The Hacker News
The Hacker News
B
Blog
罗磊的独立博客
L
Lohrmann on Cybersecurity
爱范儿
爱范儿
C
Cisco Blogs
有赞技术团队
有赞技术团队
Project Zero
Project Zero
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
S
Secure Thoughts
A
Arctic Wolf
Blog — PlanetScale
Blog — PlanetScale
腾讯CDC
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Latest news
Latest news
Cloudbric
Cloudbric
D
Docker
博客园 - 叶小钗
月光博客
月光博客

Kenvix's Blog

实现带有Nvidia GPU+Rootless Podman+Docker+Systemd+自动驱动注入支持的systemd nspawn容器 | Kenvix's Blog 手动保留常用端口,解决 Windows 端口被 Hyper-V / WinNAT 占用的问题 免Telent/TTL屏蔽运营商新版光猫的远控、TR069和RMS,获取动态随机超级管理员密码并固化权限 | Kenvix's Blog 利用Windows卷影副本(Volume Shadow)找回被覆盖和删除的数据 | Kenvix's Blog 在Windows下实现WireGuard动态DNS解析(DDNS)的正确方法:避免无意义的开销 | Kenvix's Blog OpenWRT/DNSMasq 配置DHCP静态路由主动推送 实现流量直达和旁路由流量零代价分载 | Kenvix's Blog 解决 Windows 打开视频/图片文件夹很慢的问题 | Kenvix's Blog AltA2DP - 向支持Sony LDAC协议的耳机提供Windows下蓝牙LDAC音频编码器支持 | Kenvix's Blog (2024更新)修复黑群晖 DSM7.0 + Btrfs 存储空间/磁盘损毁/堪用 的问题 校园网白嫖思路分享:局域网中转-不花钱、不认证、高速上网 | Kenvix's Blog 在 Windows 上配置网卡多个 VLAN、多个虚拟网卡、实现单线多拨网速叠加(无需驱动支持) | Kenvix's Blog 解决视频彩铃、语音通话自动转视频通话导致打电话自动挂断的问题 | Kenvix's Blog 超低成本廉价考研教程:如何用小于¥500甚至¥300的开销考个研 | Kenvix's Blog 在 Ubuntu 21.10 上启用蓝牙 LDAC/AAC/AptX 高质量音频编码支持 在 VMware Workstation 桥接模式的网卡上让虚拟机使用 VLAN 的正确方法 在 Windows 上设置 NAT 或网络共享的正确方法——避免Wi-Fi热点无法使用 自编译 红米 AC2100 OpenWRT R21.7.26 Linux 内核结构和子系统简介 | Kenvix's Blog Java 快速读取文本 (算法竞赛适用) | Kenvix's Blog 利用 ThreadLocal + Lambda,实现有状态变量的单例模式 | Kenvix's Blog 状态压缩的动态规划问题:骨牌完全覆盖棋盘问题 | Kenvix's Blog 我的 Windows 10 2004 新增 Bug 解决办法记录 解决 Android Studio 及 IDEA 中 Gradle 错误信息乱码的问题 Kotlin 的那些骚操作 | Kenvix's Blog 在普通的 Gradle Java/Kotlin 项目中使用 BuildConfig 修复国行 MIUI 打开 Google Play 始终提示 DF-DFERH-01 的问题 解决 VSCode 持续调用 WMIC 导致一个 CPU 核心完全被占满的问题 扔鸡蛋问题 | Kenvix's Blog 计算机幻觉从入门到入土 | Kenvix's Blog Java 注解预处理 Annotation Processing & 代码生成 Ubuntu 上通过以太网分享网络连接(NAT) | Kenvix's Blog Windows 选择指定的网卡来开承载网络型热点 | Kenvix's Blog 修复升级 Windows10 版本后所有内置应用闪退+第三方应用参数错误的问题 | Kenvix's Blog 配置用于 Gradle6.x + MySQL 8 的 jOOQ 3.14 代码自动生成 (已更新) 修复 Windows 环境下的程序访问 WSL 中的 MySQL 提示 Access Denied 的问题 修复 WSL 下 PHP+FastCGI 卡死的问题 使用任意磁盘或路径保存 Windows 文件历史记录 | Kenvix's Blog [1.12.2+Mod] MoeCraft :: 自由开放的科技向公益 Mod 服务器 Kenvix's Blog 禁用使用Intel核显的Windows笔记本自动调节亮度功能 | Kenvix's Blog 真正实现Minecraft高级登录(外置登录)的几种方案 | Kenvix's Blog 谈谈神舟的两艘贼船,Z7M-KP7S1 / Z7M-KP7SC USBCopyer: 插上U盘自动按需复制文件 | Kenvix's Blog USBCopyer 回调功能详细说明 | Kenvix's Blog Win10 资源管理器为所有格式激活“编辑”按钮并修改文本文件“编辑”按钮的编辑器 | Kenvix's Blog 留言板 | Kenvix's Blog 又一次 Hello world | Kenvix's Blog Java 学习笔记 (仍在更新) | Kenvix's Blog 在Win10 Pro下挂载NFS(网络文件系统) | Kenvix's Blog Nginx 反向代理 Aria2 JSONRPC | Kenvix's Blog (Android6.0~9.0) 清除锁屏密码 | Kenvix's Blog WordPress 更换站点地址后批量修改文章/评论中的旧地址 | Kenvix's Blog 修复一加3/3T因固件过老导致刷入ROM时提示错误7的问题 | Kenvix's Blog 修复Android DM-Verity 警告 | Kenvix's Blog 贴吧云签到 资源索引(下载|文档|插件) | Kenvix's Blog 继续监控!使用树莓派+Motion实现实时视频监控并通过浏览器查看 | Kenvix's Blog 自动获取Pixiv每日排行榜第一张图片(600x600 | 可用于博客背景图) | Kenvix's Blog 使用树莓派实现定时拍照监控并发送邮件到邮箱 | Kenvix's Blog 好压 V2.7 Beta1 绿色版——功能强大,良心的压缩软件 | Kenvix's Blog 任意语言实现读取压缩包注释 | Kenvix's Blog 自己实现QQ群自定义分享(管理员开启了群交易?) | Kenvix's Blog MoeCDN - 加速Gravatar/GoogleAPIs等无法在国内访问的资源 | Kenvix's Blog [Minecraft] WebLogin-连接到你的服务器来检查玩家是否可以登录 | Kenvix's Blog Android卡刷包提示This package is for device: ... this device is ...的解决方案 Kenvix's Blog 给EMLOG评论框加上复选框[√]防止垃圾评论 | Kenvix's Blog 欢迎使用emlog | Kenvix's Blog
C# 实现自定义"应用程序设置"的配置文件(user.config)存储路径 | Kenvix's Blog
2018-06-21 · via Kenvix's Blog

关于“应用程序设置”: 前往MSDN查看

默认提供的 SettingsProvider 不允许我们修改应用程序设置的配置文件的路径,这就导致了以下问题:

  1. 设置保存在了 %appdata% 目录下,使应用程序不够绿色化
  2. 当用户把程序拷贝到其他电脑上时,设置将丢失
  3. 当用户升级程序时,设置将丢失(自带的 Upgrade() 过于复杂)

要解决上述问题,就需要由我们自己来定义在哪里存储应用程序设置
MSDN给出的方法是:自己实现一个 SettingsProvider

动手

“应用程序设置” 在 C# 2.0 就已经被引入,但网上关于 SettingsProvider 的轮子并不多,我自己找到了一个比较完整的,用 vb.net 写的轮子,并人力翻译成了 c#,代码如下:

using System;
using System.Collections;
using System.Configuration;
using System.Collections.Specialized;
using System.Xml;
using System.Windows.Forms;
using System.IO;

namespace Kenvix
{
    public class AppConfigProvider : SettingsProvider
    {
        const string SettingsRootNode = "Settings"; // XML Root Node
        const bool SkipRoamingCheck = false; //if true, all settings will be forcely marked as Roaming 

        /// <summary>
        /// Used to determine where to store the settings
        /// </summary>
        /// <returns></returns>
        public virtual string GetAppSettingsPath()
        {
            return (new FileInfo(Application.ExecutablePath)).DirectoryName; //Use application path
        }

        /// <summary>
        /// Used to determine the filename to store the settings
        /// </summary>
        /// <returns></returns>
        public virtual string GetAppSettingsFilename()
        {
            return ApplicationName + ".config";
        }


        public override void Initialize(string name, NameValueCollection col)
        {
            base.Initialize(ApplicationName, col);
        }

        public override string ApplicationName
        {
            get
            {
                return Application.ProductName;
            }
            set { }
        }

        /// <summary>
        /// Iterate through the settings to be stored
        /// Only dirty settings are included in propvals, and only ones relevant to this provider
        /// </summary>
        /// <param name="context"></param>
        /// <param name="propvals"></param>
        public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection propvals)
        {
            foreach (SettingsPropertyValue propval in propvals)
                SetValue(propval);

            SettingsXML.Save(Path.Combine(GetAppSettingsPath(), GetAppSettingsFilename()));
        }

        public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection props)
        {
            // Create new collection of values
            SettingsPropertyValueCollection values = new SettingsPropertyValueCollection();

            // Iterate through the settings to be retrieved
            foreach (SettingsProperty setting in props)
            {
                SettingsPropertyValue value = new SettingsPropertyValue(setting);
                value.IsDirty = false;
                value.SerializedValue = GetValue(setting);
                values.Add(value);
            }
            return values;
        }

        private XmlDocument m_SettingsXML = null;

        private XmlDocument SettingsXML
        {
            get
            {
                // If we dont hold an xml document, try opening one.  
                // If it doesnt exist then create a new one ready.
                if (m_SettingsXML == null)
                {
                    m_SettingsXML = new XmlDocument();

                    try
                    {
                        m_SettingsXML.Load(Path.Combine(GetAppSettingsPath(), GetAppSettingsFilename()));
                    }
                    catch (Exception)
                    {
                        // Create new document
                        XmlDeclaration dec = m_SettingsXML.CreateXmlDeclaration("1.0", "utf-8", string.Empty);
                        m_SettingsXML.AppendChild(dec);

                        XmlNode nodeRoot;

                        nodeRoot = m_SettingsXML.CreateNode(XmlNodeType.Element, SettingsRootNode, "");
                        m_SettingsXML.AppendChild(nodeRoot);
                    }
                }

                return m_SettingsXML;
            }
        }

        private string GetValue(SettingsProperty setting)
        {
            string ret = "";

            try
            {
                if (IsRoaming(setting))
                    ret = SettingsXML.SelectSingleNode(SettingsRootNode + "/" + setting.Name).InnerText;
                else
                    ret = SettingsXML.SelectSingleNode(SettingsRootNode + "/" + Environment.MachineName + "/" + setting.Name).InnerText;
            }
            catch (Exception)
            {
                if (setting.DefaultValue != null)
                    ret = setting.DefaultValue.ToString();
                else
                    ret = "";
            }

            return ret;
        }

        private void SetValue(SettingsPropertyValue propVal)
        {
            XmlElement MachineNode;
            XmlElement SettingNode;

            // Determine if the setting is roaming.
            // If roaming then the value is stored as an element under the root
            // Otherwise it is stored under a machine name node 
            try
            {
                if (IsRoaming(propVal.Property))
                    SettingNode = (XmlElement)SettingsXML.SelectSingleNode(SettingsRootNode + "/" + propVal.Name);
                else
                    SettingNode = (XmlElement)SettingsXML.SelectSingleNode(SettingsRootNode + "/" + Environment.MachineName + "/" + propVal.Name);
            }
            catch (Exception)
            {
                SettingNode = null;
            }

            // Check to see if the node exists, if so then set its new value
            if (SettingNode != null)
                SettingNode.InnerText = propVal.SerializedValue.ToString();
            else if (IsRoaming(propVal.Property))
            {
                // Store the value as an element of the Settings Root Node
                SettingNode = SettingsXML.CreateElement(propVal.Name);
                SettingNode.InnerText = propVal.SerializedValue.ToString();
                SettingsXML.SelectSingleNode(SettingsRootNode).AppendChild(SettingNode);
            }
            else
            {
                // Its machine specific, store as an element of the machine name node,
                // creating a new machine name node if one doesnt exist.
                try
                {
                    MachineNode = (XmlElement)SettingsXML.SelectSingleNode(SettingsRootNode + "/" + Environment.MachineName);
                }
                catch (Exception)
                {
                    MachineNode = SettingsXML.CreateElement(Environment.MachineName);
                    SettingsXML.SelectSingleNode(SettingsRootNode).AppendChild(MachineNode);
                }

                if (MachineNode == null)
                {
                    MachineNode = SettingsXML.CreateElement(Environment.MachineName);
                    SettingsXML.SelectSingleNode(SettingsRootNode).AppendChild(MachineNode);
                }

                SettingNode = SettingsXML.CreateElement(propVal.Name);
                SettingNode.InnerText = propVal.SerializedValue.ToString();
                MachineNode.AppendChild(SettingNode);
            }
        }

        /// <summary>
        /// Determine if the setting is marked as Roaming
        /// </summary>
        /// <param name="prop"></param>
        /// <returns></returns>
        private bool IsRoaming(SettingsProperty prop)
        {
            if (SkipRoamingCheck) return true;
            foreach (DictionaryEntry d in prop.Attributes)
            {
                Attribute a = (Attribute)d.Value;
                if (a is SettingsManageabilityAttribute)
                    return true;
            }
            return false;
        }
    }

}

GetAppSettingsPath() 的返回值为 设置存储目录
GetAppSettingsFilename() 的返回值为 设置文件名
SkipRoamingCheck 是否跳过漫游属性检测,无特殊需求建议为 true

使用

使用上述代码的方法非常简单,只需:

  1. 把上述代码加入你的项目
  2. 如下图,双击打开 设置设计器
  3. 如下图,对于 每一个设置项,修改属性为下图: