private void IsReadyToStart_ThreadFunc()
        {
            bool found = false;

            if (bEventLog)
            {
                this.eventLog.WriteEntry("We missed the message about successfully logged-on.", EventLogEntryType.Information);
            }
            while (!found && !bReadyToStart)
            {
                Thread.Sleep(1000);
                foreach (MyProcess s in MyProcess.GetProcessList())
                {
                    if (s.ProcessName.Equals("explorer"))
                    {
                        found         = true;
                        bReadyToStart = true;
                        break;
                    }
                }
                if (!found)
                {
                    if (bEventLog)
                    {
                        this.eventLog.WriteEntry("Failed to find 'explorer.exe', Maybe trying to upgrade?", EventLogEntryType.FailureAudit);
                    }
                }
            }
            if (bEventLog)
            {
                this.eventLog.WriteEntry("Now, Ready to Go!", EventLogEntryType.SuccessAudit);
            }
            return;
        }
        void ConsoleUpdater()
        {
            List <ManualResetEvent> doneUninstallEvents = new List <ManualResetEvent>();
            List <ManualResetEvent> doneInstallEvents   = new List <ManualResetEvent>();
            List <Package>          toBeUninstall       = new List <Package>();
            List <Package>          toBeInstall         = new List <Package>();

            #region EventLog Init
            {
                try
                {
                    if (!System.Diagnostics.EventLog.SourceExists(EventLogSetting[0]))
                    {
                        System.Diagnostics.EventLog.CreateEventSource(EventLogSetting[0], EventLogSetting[1]);
                    }

                    eventLog.Source = EventLogSetting[0];
                    eventLog.Log    = EventLogSetting[1];
                    bEventLog       = true;
                }
                catch
                {
                    bEventLog = false;
                }
            }
            #endregion
            #region 0. Get Path
            String Path = String.Empty;
            try
            {
                foreach (ManagementObject mo in (new ManagementClass("Win32_Service")).GetInstances())
                {
                    if (mo.GetPropertyValue("Name").ToString() == "CNUService")
                    {
                        Path = System.IO.Path.GetDirectoryName(mo.GetPropertyValue("PathName").ToString().Trim('"'));
                        break;
                    }
                }
                if (Path == String.Empty)
                {
                    Path = AppDomain.CurrentDomain.BaseDirectory;
                }
            }
            catch (Exception ex)
            {
                EventLog("Failed to get $SrvPath \n" + ex.ToString(), EventLogEntryType.Error);
            }
            Package.UpdatePath = Path;
            #endregion
            #region 0. 다른 업데이터가 떠있으면 자살.
            List <MyProcess> currentRunning = MyProcess.GetProcessList();
            {
                List <MyProcess> foundUpdater = currentRunning.FindAll(
                    delegate(MyProcess runner)
                {
                    if (("CNUUpdater").Equals(runner.ProcessName))
                    {
                        return(true);
                    }
                    return(false);
                }
                    );
                if (foundUpdater.Count > 1)
                {
                    EventLog("0. 업데이트가 2개 이상 켜져있습니다. 자살합니다ㅠ.", EventLogEntryType.Error);
                    return;
                }
            }
            #endregion

            #region "1. 컴퓨터에 깔린 패키지 리스트를 불러옵니다. (못불러오면 그냥Die!)"
            EventLog("1. 컴퓨터에 깔린 패키지 리스트를 불러옵니다.", EventLogEntryType.SuccessAudit);
            List <Package> localPackage;
            try
            {
                #region #UNITTEST

                /*
                 * localPackage = new List<Package>();
                 * Package t1 = new Package();
                 * t1.Name = "Uninstall";  // Uninstall
                 * t1.Version = "1.0.0";
                 * //t1.ProductCode = "{27FA8657-6D2C-4917-990E-CE46C94D31B6}";
                 * localPackage.Add(t1);
                 * Package t2 = new Package();
                 * t2.Name = "Uninstall+Install";  // Uninstall(->Install)
                 * t2.Version = "2.0.0";
                 * localPackage.Add(t2);
                 * Package t3 = new Package();
                 * t3.Name = "SameVersion";  // nope
                 * t3.Version = "3.0.0";
                 * localPackage.Add(t3);
                 */
                #endregion
                String packages = System.IO.Path.Combine(Path, "Packages.xml");
                EventLog(packages);
                localPackage = Package.ReadXML(packages);
            }
            catch (Exception ex)
            {
                EventLog("1. 컴퓨터에 깔린 패키지 리스트가 없습니다. " + ex.ToString(), EventLogEntryType.Error);
                return;
            }
            #endregion

            #region "2. 서버에 있는 최신 패키지 리스트를 불러옵니다. (못불러오면 그냥Die!)"
            EventLog("2. 서버에 있는 최신 패키지 리스트를 불러옵니다. ", EventLogEntryType.SuccessAudit);
            List <Package> remotePackage;
            try
            {
                #region #UNITTEST

                /*
                 * remotePackage = new List<Package>();
                 * Package t1 = new Package();
                 * t1.Name = "Install";  // Install
                 * t1.Version = "1.0.0";
                 * remotePackage.Add(t1);
                 * Package t2 = new Package();
                 * t2.Name = "Uninstall+Install";  // Uninstall(->Install)
                 * t2.Version = "3.0.0";
                 * remotePackage.Add(t2);
                 * Package t3 = new Package();
                 * t3.Name = "SameVersion";
                 * t3.Version = "3.0.0";
                 * remotePackage.Add(t3);
                 */
                #endregion
                EventLog(Package.UpdateServer);
                WebClient newClient = new WebClient();
                newClient.DownloadFile(Package.UpdateServer + "Latest.xml", System.IO.Path.Combine(Path, "Latest.xml"));
                remotePackage = Package.ReadXML(System.IO.Path.Combine(Path, "Latest.xml"));
            }
            catch (Exception ex)
            {
                EventLog("2. 서버에 있는 최신 패키지 리스트가 없습니다. \n" + ex.ToString(), EventLogEntryType.Error);
                return;
            }
            #endregion

            #region "3. 컴터에 깔려있는데, 서버엔 없어!! => UNINSTALL목록에 넣습니다."
            EventLog("3. 이미 깔려있는 패키지들을 불러옵니다.");
            foreach (Package lcl_one in localPackage)
            {
                #region "패키지가 실행중인지 확인."
                MyProcess foundRunning;
                if (
                    (
                        foundRunning = currentRunning.Find(
                            delegate(MyProcess runner)
                {
                    if ((runner.ProcessName).Equals(System.IO.Path.GetFileNameWithoutExtension(lcl_one.Name)))
                    {
                        return(true);
                    }
                    return(false);
                }
                            )
                    ) != null
                    )
                {
                    lcl_one.CurrentPID = foundRunning.Id;
                    EventLog("3. 현재 <" + lcl_one.Name + "> 패키지가 사용중(#" + lcl_one.CurrentPID + ")에 있습니다.", EventLogEntryType.Warning);
                }
                #endregion
                #region "삭제할 패키지가 있는지 확인."
                if (remotePackage.Find(
                        delegate(Package rmt_one)
                {
                    if ((rmt_one.Name).Equals(lcl_one.Name))
                    {
                        return(true);
                    }
                    return(false);
                }
                        ) == null
                    )
                {
                    toBeUninstall.Add(lcl_one);

                    ManualResetEvent evt = new ManualResetEvent(false);
                    doneUninstallEvents.Add(evt);
                    lcl_one.SetEventHandlers(evt, null);

                    lcl_one.Error += new FailingEventHandler(GetError);

                    EventLog("3. 최신 목록에는 <" + lcl_one.Name + "> 패키지가 없으므로, 삭제할 예정입니다.", EventLogEntryType.Information);
                }
                #endregion
            }
            #endregion

            #region "4. 서버에만 있을경우 => INSTALL목록에 넣습니다. (업데이트도 INSTALL로).)"
            EventLog("4. 서버의 최신 패키지 리스트들을 불러옵니다.");
            foreach (Package latest_rmt_one in remotePackage)
            {
                Package found_lcl_one;
                if ((found_lcl_one = localPackage.Find(
                         delegate(Package lcl_one)
                {
                    if ((lcl_one.Name).Equals(latest_rmt_one.Name))
                    {
                        return(true);
                    }
                    return(false);
                }
                         )) != null
                    )
                {
                    #region "이미 패키지가 깔려있을경우, 업데이트 해야하는지 확인."
                    if (Package.IsNeedToUpdateByComparePackages(found_lcl_one, latest_rmt_one))
                    {
                        toBeInstall.Add(latest_rmt_one);

                        ManualResetEvent evt2 = new ManualResetEvent(false);
                        doneInstallEvents.Add(evt2);
                        latest_rmt_one.SetEventHandlers(null, evt2);

                        latest_rmt_one.Error += new FailingEventHandler(GetError);

                        EventLog("4. 최신의 <" + latest_rmt_one.Name + "> 패키지로 업데이트할 예정입니다.", EventLogEntryType.Information);
                    }
                    else
                    {
                        EventLog("4. 이미 최신의 <" + latest_rmt_one.Name + "> 패키지를 사용합니다.", EventLogEntryType.Information);
                    }
                    #endregion
                }
                else
                {
                    #region "패키지가 안깔려있으니 설치해야함."
                    toBeInstall.Add(latest_rmt_one);
                    ManualResetEvent evt = new ManualResetEvent(false);
                    doneInstallEvents.Add(evt);
                    latest_rmt_one.SetEventHandlers(null, evt);
                    latest_rmt_one.Error += new FailingEventHandler(GetError);
                    EventLog("4. 새로운 <" + latest_rmt_one.Name + "> 패키지를 설치할 예정입니다.", EventLogEntryType.Information);
                    #endregion
                }
            }
            #endregion

            #region "5. 업데이트 해야하면 => CNUService를 끄고 계속 진행합니다. (아니면 그냥Die!)"
            ServiceController cnuService = null;
            if (toBeInstall.Count > 0 || toBeUninstall.Count > 0)
            {
                try
                {
                    cnuService = new ServiceController("CNUService");
                    cnuService.Stop();
                }
                catch (Exception ex)
                {
                    EventLog("5. 업데이트 해야하면 => CNUService가없어?!!!!뭐야? \n" + ex.ToString(), EventLogEntryType.Error);
                }
            }
            else
            {
                EventLog("5. 업데이트 할게없어요ㅋㅋ, 잘자요.", EventLogEntryType.SuccessAudit);
                System.IO.File.Delete(System.IO.Path.Combine(Path, "Latest.xml"));
                return;
            }
            #endregion

            #region "6. 업데이트를 위한 THREAD를 생성합니다. (UNINSTALL->INSTALL순서로 진행됩니다.)"
            foreach (Package to_uninstall in toBeUninstall)
            {
                ThreadPool.QueueUserWorkItem(to_uninstall.UpdateCallback, null);
            }
            foreach (Package to_install in toBeInstall)
            {
                ThreadPool.QueueUserWorkItem(to_install.UpdateCallback, null);
            }
            EventLog("6. 업데이트를 위한 THREAD를 생성합니다. (UNINSTALL->INSTALL순서로 진행됩니다.)", EventLogEntryType.Information);
            #endregion

            #region "7. UNINSTALL들이 다 됬는지 기달립니다. (INSTALL이 진행중일수도 있습니다)"
            EventLog("7. " + toBeUninstall.Count + "건의 UNINSTALL이 모두 끝나기를 기다릴게요.");
            // WaitHandle.WaitAll(doneUninstallEvents.ToArray());  // 으악! 이게 안됨!ㅠㅠ
            foreach (WaitHandle one in doneUninstallEvents)
            {
                WaitHandle.WaitAny(new WaitHandle[] { one });
            }


            EventLog("7. UNINSTALL이 모두 끝났습니다.", EventLogEntryType.SuccessAudit);
            #endregion

            #region "8. INSTALL들이 다 됬는지 기달립니다."
            EventLog("8. " + toBeInstall.Count + "건의 INSTALL이 모두 끝나기를 기다릴게요.");
            try
            {
                //WaitHandle.WaitAll(doneInstallEvents.ToArray());
                foreach (WaitHandle one in doneInstallEvents)
                {
                    WaitHandle.WaitAny(new WaitHandle[] { one });
                }
            }
            catch (Exception ex)
            {
                EventLog(ex.ToString());
            }
            EventLog("8. INSTALL이 모두 끝났습니다.", EventLogEntryType.SuccessAudit);
            #endregion

            #region "9. Post Updater의 업데이트가 있을경우, 먼저 적용합니다."
            try
            {
                EventLog("9. Post Updater의 업데이트가 있을경우, 먼저 적용합니다.");
                String postupdater = "CNUPostUpdater2.exe";
                foreach (Package IfPost in toBeInstall)
                {
                    if ((IfPost.Name).Equals(postupdater))
                    {
                        EventLog("9. Post Updater의 업데이트가 있습니다.");
                        String dest = System.IO.Path.Combine(Path, postupdater);
                        System.IO.File.Delete(dest);
                        System.IO.File.Move(System.IO.Path.Combine(Path, "Updates", postupdater), dest);
                        break;
                    }
                }
            }
            catch (Exception ex)
            {
                EventLog("9. Post Updater의 업데이트 도중 문제가 생겼습니다. \n" + ex.ToString(), EventLogEntryType.Error);
            }
            #endregion

            #region "10. Post Update로 역활을 넘깁니다."
            EventLog("10. Post Update로 역활을 넘깁니다.", EventLogEntryType.Information);
            try
            {
                // http://stackoverflow.com/questions/3891623/c-sharp-granting-log-on-as-service-permission-to-a-windows-user
                RunAs.by.AdminSliently(System.IO.Path.Combine(Path, "CNUPostUpdater2.exe"));
            }
            catch (Exception ex)
            {
                EventLog(ex.ToString(), EventLogEntryType.Error);
            }
            #endregion
        }
        //Go
        #region "서비스가 할 동작들."
        private void MainService_ThreadFunc()
        {
            if (bEventLog)
            {
                this.eventLog.WriteEntry("Ready !!!!!  @ MainService_ThreadFunc()");
            }
            while (!bReadyToStart)
            {
                Thread.Sleep(2000);
            }
            if (bEventLog)
            {
                this.eventLog.WriteEntry("Set !!!!!  @ MainService_ThreadFunc()");
            }

            Boolean OnceOnly = false;

            while (!_ServiceShutdownRequestEvent.WaitOne(0))
            {
                if (bEventLog)
                {
                    this.eventLog.WriteEntry("Go !!!!!   @ MainService_ThreadFunc()");
                }
                Thread.Sleep(60 * 1000);
                try
                {
                    #region "1. 로컬 패키지 리스트를 받아옵니다."
                    {
                        List <Package> localPackage = Package.ReadXML(System.IO.Path.Combine(this.GetPath(), "Packages.xml"));
                        // "2. 패키지 리스트에서 실행해야할 파일을 뽑아냅니다."
                        List <MyProcess> currentRunProcess = MyProcess.GetProcessList();

                        foreach (Package i in localPackage)
                        {
                            MyProcess foundRunning;
                            if (
                                (
                                    foundRunning = currentRunProcess.Find(
                                        delegate(MyProcess runner)
                            {
                                if ((runner.ProcessName).Equals(System.IO.Path.GetFileNameWithoutExtension(i.Name)))
                                {
                                    return(true);
                                }
                                return(false);
                            }
                                        )
                                ) == null
                                )
                            {
                                if (i.toRun)
                                {
                                    // "3. 조건에 해당하면 돌립시다."
                                    if ((i.RunOnce == false) || ((i.RunOnce == true) && (OnceOnly == false)))
                                    {
                                        uint   pid = uint.MaxValue;
                                        String url = System.IO.Path.Combine(this.GetPath(), i.Name);
                                        if (i.RunAs != null && i.RunAs.Equals("Administrator"))
                                        {
                                            pid = RunAs.by.AdminSliently(this.GetPath() + "\\" + i.Name);
                                            //Thread s = new Thread(Administrator_ThreadFunc);
                                            //s.Start((object)url);
                                        }
                                        else
                                        {
                                            pid = RunAs.by.User(url);
                                        }
                                        if (bEventLog)
                                        {
                                            this.eventLog.WriteEntry(i.Name + " : Running at #" + pid.ToString() + "\n" + url, EventLogEntryType.SuccessAudit);
                                        }
                                    }
                                }
                            }
                            else
                            {
                                if (bEventLog)
                                {
                                    this.eventLog.WriteEntry(i.Name + " : Already Running at #" + foundRunning.Id.ToString(), EventLogEntryType.Information);
                                }
                            }
                        }
                    }
                    OnceOnly = true;
                    #endregion
                }
                catch (Exception ex)
                {
                    if (bEventLog)
                    {
                        this.eventLog.WriteEntry("MainService_ThreadFunc() : ERROR!\n" + ex.ToString(), EventLogEntryType.Error);
                    }
                }
            }
        }