# 制作工程文件

## 1.关联自定义的后缀名并添加图标，添加启动事件

这里的控制逻辑主要是从注册表中进行，即regedit.exe 中 ，打开 HKEY_CLASSES_ROOT  

添加自定义的后缀名项，并在默认值中添加自定义的备注名值

```
[HKEY_CLASSES_ROOT\.nlg]
@="NLG.Launcher.nlg"
```

添加刚才定义定义的备注名项，添加DefaultIcon ,默认值位需要添加的图标（注：icon 可以从exe ,0  中获取，或者dll 中获取，或注册表中获取）

添加shell (交互操作选项)，添加 open（操作，或者edit等），添加command 。

```
[HKEY_CLASSES_ROOT\NLG.Launcher.nlg]

[HKEY_CLASSES_ROOT\NLG.Launcher.nlg\DefaultIcon]
@="C:\\Users\\Xin\\OneDrive\\C#\\NLG\\NLG\\bin\\Debug\\NLG.exe ,0"

[HKEY_CLASSES_ROOT\NLG.Launcher.nlg\shell]

[HKEY_CLASSES_ROOT\NLG.Launcher.nlg\shell\open]

[HKEY_CLASSES_ROOT\NLG.Launcher.nlg\shell\open\command]
@="C:\\Program Files\\Notepad++\\notepad++.exe %1"
```

注册表修改完成之后，并不会自定更新，需要重启 explorer.exe （文件管理系统），或者重启系统也可以

在手动添加完成之后，需要考虑到的部分就是代码自动完成。

C# 部分的代码

```
        public static void SetIcon(string Extension,string ExtensionName,string icon,string command)
        {
            RegistryKey regKey = null;
            try
            {
                regKey = Registry.ClassesRoot.CreateSubKey(Extension);
                regKey?.SetValue("", ExtensionName);
                regKey = Registry.ClassesRoot.CreateSubKey(ExtensionName+"\\DefaultIcon");
                regKey?.SetValue("", icon);

                regKey = Registry.ClassesRoot.CreateSubKey(ExtensionName + "\\shell\\open\\command");

                regKey?.SetValue("", command);
            }
            catch(Exception ex)
            {
                
            }
            finally
            {
                regKey?.Close();        
```

重启文件管理系统

        public static void Explorer()
        {
            Process process = null;
            try
            {
                process = Process.GetProcessesByName("explorer")[0];
                process.Kill();
                //_ = Process.Start("explorer.exe",""); //会额外打开一个，自动重启
            }
            catch
            {
            }
            finally
            {
                process?.Close();
            }
        }

```
Reg.SetIcon(".nlg", "NLG.Launcher.nlg",  Environment.CurrentDirectory +"\\NLG.exe ,0",Environment.CurrentDirectory +"\\NLG.exe %1");
```

这样在打开特定文件后缀的时候就可以指定该文件作为固定的打开方式。

但是这种方式会有几个问题，因为操作的注册表是系统本身的，所以需要管理员权限，用户如果每次打开都需要一个管理员权限，会很影响使用体验 。

因为这个程序也就只执行一次就可以。所以可以把这个模块封装成一个单独的exe ,在需要运行的时候运行（比如在安装包安装完成之后，在主程序调用该功能的时候） 比如 register.exe 

在Advanced Installer 制作msi 安装包的时候也可以同时添加注册表，但是这个时候添加 的注册表是固定位置的，一次性的，不能多次进行，可以添加一些全局参数在里面，比如注册日期等。

# 2.工程文件的内容 

工程文件的内容是存放工程文件内容的地方，可以是完成的信息，也可以不是，只是一个入口。mp4 等特殊文件格式，属于公开的特有的工程文件，需要特别的解码的方式，也有sln 这种，纯文件式的，可以直接修改里面内容的，只是一个入口的工程文件。

这里我们采用sln vs的这种工程文件的形式。

里面的值可以有多种，INI、XML、JSON、YAML、TOML ,都可以。

vs 采用的ini 加密的方式  ，xml 的使用也很广泛C# 对xml 的支持要更为友好一些。性能和功能适中，但是会有些臃肿

ini C# 也可以支持，但是ini 的可扩展性差，性能不强，

json 的性能最好，也最简单，但是json 的开发是为了数据交互，比如接口，不是作为配置文件使用，不能添加注释，

首先需要新建一个配置文件类，在打开工程文件的时候，格式化到该类中去



    [Serializable]
    [XmlSerializerAssembly("EXCResources.XmlSerializers")]
     private  class Config{
     
     }
    

        private static void WriteConfigFile(string sFile)
        {
            XmlSerializer ser = new XmlSerializer(typeof(ConfigData), typeof(ConfigData).GetNestedTypes());
            FileStream fs = File.Create(sFile);
            ser.Serialize(fs, Config);
            fs.Close();
        }


        //更新数据
        private static void UpdateConfigFile(string sFile)
        {
            XDocument Doc = XDocument.Load(sFile);
    
            WriteConfigFile("temp.xml");
            XDocument Doc1 = XDocument.Load("temp.xml");
            foreach (var col in Doc.Element("ConfigData").Elements())
            {
                Doc.Element("ConfigData").Element(col.Name).SetValue(Doc1.Element("ConfigData").Element(col.Name).Value);
            }
    
            Doc.Save(sFile);
            File.Delete("temp.xml");
        }
    
        public static void ReadConfigFile(string sFile)
        {
            try
            {
                //此调用方法多次运行会产生内存泄漏,参见 https://stackoverflow.com/questions/1127431/xmlserializer-giving-filenotfoundexception-at-constructor
                using (var stream = File.OpenRead(sFile))
                {
                    XmlSerializer serializer = new XmlSerializer(typeof(ConfigData), typeof(ConfigData).GetNestedTypes());
                    Config = serializer.Deserialize(stream) as ConfigData;
                }
            }
            catch
            {
                MessageBox.Show("配置文件错误");
            }
        }





