static void Main(string[] args)
        {
            try
            {
                mmTimerPeriod = new MMTimerPeriod();

                System.Diagnostics.Process currentProcess = System.Diagnostics.Process.GetCurrentProcess();

                appName = System.IO.Path.GetFileNameWithoutExtension(currentProcess.MainModule.ModuleName);

                Logging.AddLogMessageHandlerToDefaultDistributionGroup(new Logging.Handlers.QueueLogMessageHandler(Logging.CreateConsoleLogMessageHandler(logGate: Logging.LogGate.Info, data: false, nvs: false)));

                IConfig config = Config.Instance;

                config.AddStandardProviders(ref args);

                List <Logging.ILogMessageHandler> lmhList = new List <Logging.ILogMessageHandler>();

                bool useOutputDebugStringLMH = config.GetConfigKeyAccessOnce("Logging.LMH.UseOutputDebugString").GetValue <bool>(false);
                bool useDiagnosticTraceLMH   = config.GetConfigKeyAccessOnce("Logging.LMH.UseDiagnosticTrace").GetValue <bool>(false);

                if (useOutputDebugStringLMH)
                {
                    lmhList.Add(Logging.CreateWin32DebugLogMessageHandler(appName, logGate: Logging.LogGate.Info));
                }

                if (useDiagnosticTraceLMH)
                {
                    lmhList.Add(Logging.CreateDiagnosticTraceLogMessageHandler(logGate: Logging.LogGate.Info));
                }

                if (!lmhList.IsEmpty())
                {
                    Logging.AddLogMessageHandlerToDefaultDistributionGroup(new Logging.Handlers.QueueLogMessageHandler("LMH.Queue", lmhList.ToArray()));
                }

                Logging.StartLoggingIfNeeded();

                Logging.Logger appLogger = new Logging.Logger("AppMain");

                DictionaryConfigKeyProvider localProvider = new DictionaryConfigKeyProvider("localCKP")
                {
                    { "PerfSuite.MDRFFiles.DirPath", @".\Data" },
                };

                if (config.SearchForKeys(new Utils.StringMatching.MatchRuleSet(Utils.StringMatching.MatchType.Exact, "PerfSuite.Ping.PingTargetArray")).IsNullOrEmpty())
                {
                    localProvider.Add("PerfSuite.Ping.PingTargetArray", "localhost"); // "localhost,8.8.8.8,8.8.4.4"
                }
                config.AddProvider(localProvider);

                OutputDebugStringCapturePart odsCapturePart;
                PerformanceSuitePart         perfSuite;

                List <IActivePartBase> partsList = new List <IActivePartBase>();

                using (Win32.Hooks.ConsoleCtrlHandlerHook consoleCtrlHandlerHook = new Win32.Hooks.ConsoleCtrlHandlerHook("cch", (sender, ctrlType) => CtrlHandlerDelegate(sender, ctrlType, partsList)))
                {
                    bool isDebuggerAttached = System.Diagnostics.Debugger.IsAttached;
                    bool enableOutputDebugStringCapturePart = config.GetConfigKeyAccessOnce("Logging.EnableOutputDebugStringCapturePart").GetValue <bool>(!isDebuggerAttached);
                    if (enableOutputDebugStringCapturePart && !useOutputDebugStringLMH && !useDiagnosticTraceLMH)
                    {
                        partsList.Add(odsCapturePart = new OutputDebugStringCapturePart("ODS", generateMesgType: Logging.MesgType.Info));
                    }

                    var perfSuiteConfig = new PerformanceSuitePartConfig().Setup();
                    partsList.Add(perfSuite = new PerformanceSuitePart(perfSuiteConfig));

                    MDRFLogMessageHandlerAdapterConfig mdrfLMHConfig = new MDRFLogMessageHandlerAdapterConfig()
                    {
                        OnlyRecordMessagesIfFileIsAlreadyActive = true
                    }.Setup();
                    MDRFLogMessageHandlerAdapter mdrfLMH = new MDRFLogMessageHandlerAdapter("LMH.MDRF", Logging.LogGate.All, perfSuite.MDRFWriter, mdrfLMHConfig);
                    Logging.AddLogMessageHandlerToDefaultDistributionGroup(new Logging.Handlers.QueueLogMessageHandler(mdrfLMH));

                    IClientFacet[] goOnlineActionArray = partsList.Select(part => part.CreateGoOnlineAction(true).StartInline()).ToArray();
                    goOnlineActionArray.DoForEach((a) => a.WaitUntilComplete());

                    for (; ;)
                    {
                        System.Threading.Thread.Sleep(100);
                    }
                }
            }
            catch (System.Exception ex)
            {
                Logging.ShutdownLogging();

                Console.WriteLine("{0}: failed with exception: {1}".CheckedFormat(appName, ex.ToString(ExceptionFormat.Full)));

                Environment.Exit(4);
            }
        }
        private static Win32.Hooks.ConsoleCtrlHandlerHook.ClientProvidedDelegateResult CtrlHandlerDelegate(Win32.Hooks.ConsoleCtrlHandlerHook sender, Win32.Hooks.CtrlType ctrlType, List <IActivePartBase> partsList)
        {
            IClientFacet [] goOfflineActionArray = partsList.Select(part => part.CreateGoOfflineAction().StartInline()).ToArray();

            QpcTimer waitTimeLimitTimer = new QpcTimer()
            {
                TriggerIntervalInSec = 0.5
            }.Start();

            goOfflineActionArray.WaitUntilSetComplete(() => waitTimeLimitTimer.IsTriggered);

            sender.ExitCode = (goOfflineActionArray.Any(a => a.ActionState.Failed) ? 1 : 0);

            partsList.TakeAndDisposeOfGivenObjects();

            return(Win32.Hooks.ConsoleCtrlHandlerHook.ClientProvidedDelegateResult.Exit);
        }