static void Main(string[] args)
        {
            Helper.GetInputOptions(args);
            DisableUMCallbackFilter();
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            if (args.Length == 0)
            {
                MessageBox.Show("Bạn phải cung cấp tên profile vào đối số cho Launcher này!", "Lỗi", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            CurrentVersion = Application.ProductVersion;
            AppDomain.CurrentDomain.AssemblyResolve += ResolveEventHandler;
            Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);
            AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(Unhandled);
            RootDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            if (Settings.InputOptions?.LogPath == null)
            {
                log = StreamWriter.Null; // use a blackhole as log file
            }
            else
            {
                log = new StreamWriter(File.Open(Path.Combine(RootDirectory, Settings.InputOptions.LogPath), FileMode.Create, FileAccess.Write, FileShare.Read), Encoding.UTF8);
            }
            PackageDirectory = Path.Combine(RootDirectory, "Pkg");
            ProfileDirectory = Path.Combine(RootDirectory, "Prfl");
            DateTime now = DateTime.Now;

            log.Log(now.ToString("F", new CultureInfo("en-US")));
            log.Log("Dotnet Runtime Patcher by Meigyoku Thmn");
            log.Log($"Version {CurrentVersion}");
            var DebugBuild = Settings.InputOptions.Debug;
            var pd         = new ProgressDialog(IntPtr.Zero);

            pd.Title   = "Đang tải dữ liệu";
            pd.Maximum = 100;
            pd.Value   = 0;
            pd.Line1   = "Thiết đặt CSScript";
            pd.Line2   = "Xin vui lòng chờ trong giây lát...";
            pd.Line3   = " ";
            pd.ShowDialog(ProgressDialog.PROGDLG.Modal, ProgressDialog.PROGDLG.NoMinimize);
            Thread.Sleep(5000);

            var options = new Options(RootDirectory, "Options.jsonc");

            options.Save();
            log.Log("Set up CSScript.");
            CSScript.GlobalSettings.UseAlternativeCompiler = CodeDom_Roslyn.LocateRoslynCSSProvider();
            CSScript.GlobalSettings.RoslynDir   = CodeDom_Roslyn.LocateRoslynCompilers();
            CSScript.EvaluatorConfig.DebugBuild = DebugBuild;


            log.Log($"Read {Path.Combine(ProfileDirectory, args[0] + ".jsonc")}");
            var exeCfg     = JObject.Parse(File.ReadAllText(Path.Combine(ProfileDirectory, args[0] + ".jsonc")));
            var targetPath = (string)exeCfg["targetPath"];

            if (targetPath == null)
            {
                log.Log($"Target path doesn't exist in profile!");
                MessageBox.Show("Đường dẫn đến 'file thực thi' không tồn tại trong thiết lập!"); return;
            }
            TargetDirectory = Path.GetDirectoryName(targetPath);
            var package = (string)exeCfg["package"];

            if (package == null)
            {
                log.Log($"Package name in profile is missing!");
                MessageBox.Show("Không hề có thiết lập gói!"); return;
            }
            log.Log($"Read {Path.Combine(PackageDirectory, package, "versions.jsonc")}");
            var versionsCfg = JObject.Parse(File.ReadAllText(Path.Combine(PackageDirectory, package, "versions.jsonc")));
            var targetInfo  = GetChecksumAndSize(targetPath);
            var version     = versionsCfg[targetInfo.Hash];

            if (version == null || (uint)version["size"] != targetInfo.Size)
            {
                log.Log("Unable to find suitable patch for target executable file.");
                MessageBox.Show("Không tìm thấy bản patch phù hợp, có thể phần mềm của bạn đang là phiên bản khác rồi!"); return;
            }
            TargetVersion = (string)version["ver"];
            if (TargetVersion == null)
            {
                log.Log("TargetVersion is null");
            }
            var patchName = (string)version["name"];

            if (patchName == null)
            {
                log.Log("patchName is null");
            }
            TargetIcon     = Icon.ExtractAssociatedIcon(targetPath);
            TargetAssembly = Assembly.LoadFrom(targetPath);
            var referenceAssemblies = TargetAssembly.GetReferencedAssemblies();

            ReferenceAssemblies = referenceAssemblies.Aggregate(
                new SortedDictionary <string, Assembly>(),
                (acc, e) => {
                acc.Add(e.Name, Assembly.Load(e));
                return(acc);
            }
                );
            var tmp            = package.Split('/');
            var id             = tmp[0];
            var packageName    = tmp[1];
            var mainScriptPath = Path.Combine(PackageDirectory, package, patchName, "Main.cs");

#if DEBUG
            // for debugging purpose
            // mainScriptPath = @"C:\Touhou-Dotnet-Patches\lang-vi\thfdf\Main.cs";
#endif
            log.Log("Begin loading patching script...");
            log.Log($"DebugMode = {DebugBuild}");

            var mutex   = new Mutex(false, ConfigurationManager.AppSettings["SharedLock"], out bool createdNew);
            var updater = options.UpdateOnStart && createdNew ? new Updater(targetPath, id, packageName, patchName, RootDirectory, PackageDirectory, options) : null;
            if (!createdNew)
            {
                log.Log("An instance of Configurator or Updater is already running!");
            }
            if (updater != null)
            {
                log.Log("Run Updater...");
            }
            var updatingTask = updater?.RunAsync();

            pd.Value = 10;
            pd.Line1 = "Biên dịch tệp script";

            log.Log($"Load {mainScriptPath}");
            CSScriptHack.InjectObjectForPrecompilers(new Hashtable()
            {
                { "Version", TargetVersion },
            });
            var package_dirs = new ScriptParser(mainScriptPath, null).ResolvePackages()
                               .Select(Path.GetDirectoryName)
                               .ToList();
            package_dirs.ForEach(CSScript.GlobalSettings.AddSearchDir);
            var refAsms = ReferenceAssemblies.Select(asm => asm.Value.Location).ToArray();
            refAsms = new string[0];
            var script = new AsmHelper(CSScript.LoadFile(
                                           mainScriptPath, null, DebugBuild, refAsms));
            Directory.SetCurrentDirectory(TargetDirectory);

            pd.Value = 20;
            pd.CloseDialog();
            log.Log("Call DotnetPatching.Config.OnInit");
            dynamic status = script.GetStaticMethod("DotnetPatching.Config.OnInit")();
            if (status == false)
            {
                goto EnableUpdateButtonStep;
            }
            pd         = new ProgressDialog(IntPtr.Zero);
            pd.Title   = "Đang tải dữ liệu";
            pd.Maximum = 100;
            pd.Value   = 0;
            pd.Line1   = "Thiết đặt Harmony";
            pd.Line2   = "Xin vui lòng chờ trong giây lát...";
            pd.Line3   = " ";
            pd.ShowDialog(ProgressDialog.PROGDLG.Modal, ProgressDialog.PROGDLG.NoMinimize);
            pd.Value = 30;
            log.Log("Call DotnetPatching.Detours.OnSetup");
            var OnSetup    = script.GetStaticMethod("DotnetPatching.Detours.OnSetup");
            var detourList = (List <PatchTuple>)OnSetup();
            log.Log("Call DotnetPatching.Transpilers.OnSetup");
            OnSetup = script.GetStaticMethod("DotnetPatching.Transpilers.OnSetup");
            var transpilerList = (List <TranspilerTuple>)OnSetup();
            var total          = detourList.Count + transpilerList.Count;
            log.Log("Begin setting up Detour Functions...");
            pd.Line2 = "Setting up Detour Functions";
            SetupHook(detourList, (count, message) => {
                pd.Line3 = message;
                pd.Value = (uint)(30 + 70 * count / total);
            });
            log.Log("Begin setting up Transpilers to modify functions...");
            SetupTranspiler(transpilerList, (count, message) => {
                pd.Line3 = message;
                pd.Value = (uint)(30 + 70 * count / total);
            });
            log.Log("Launch the target executable...");
            pd.Value = 100;
            pd.CloseDialog();
            TargetAssembly.EntryPoint.Invoke(null, new object[] { new string[] { } });
EnableUpdateButtonStep:
            log.Log("Enable updating.");

            if (updatingTask != null)
            {
                updater.EnableUpdateButton();
                log.Log("Wait for updater to complete.");
                updatingTask.Wait();
                updater.Close();
            }
            mutex.Dispose();

            log.Log("Dotnet Runtime Patcher main thread ends.");
            log.Close();
        }