RSS Git Download  Clone
Raw Blame History
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Globalization;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.ServiceProcess;

using chc.servicemanagertray.Properties;
using System.Security.Principal;

namespace chc.servicemanagertray
{
    public partial class ServiceManagerForm : Form
    {
        #region Fields

        /// <summary>
        /// The datasource for the grid that provides the services.
        /// </summary>
        private ServiceDataSource ds;

        /// <summary>
        /// The name of the service currently selected to re-select on refresh and re-bind.
        /// </summary>
        private string instance_selected_service_name = null;

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes the designer components.
        /// Initializes the form.
        /// </summary>
        public ServiceManagerForm(String[] args)
        {
            InitializeComponent();
            InitializeForm();

            this.servicegrid.CellMouseEnter += Servicegrid_CellMouseEnter;

            if (args.Length == 3)
            {
                bool stopToFalseAndStartToTrue = Boolean.Parse(args[2]);
                var service = (from sw in ds.GetServices() where sw.ServiceController.ServiceName == args[1] select sw).FirstOrDefault();

                if (service != null)
                {
                    if (!stopToFalseAndStartToTrue)
                    {
                        service.Stop();
                    } else
                    {
                        service.Start();
                    }
                    SetStatusUpdateNotificationTimer(service, !stopToFalseAndStartToTrue ? ServiceControllerStatus.Stopped : ServiceControllerStatus.Running, null);
                }

            }
            searchFilter.TextChanged += SearchFilter_TextChanged;
            searchServiceInfo.TextChanged += searchServiceInfo_TextChanged;
        }

        private void SearchFilter_TextChanged(object sender, EventArgs e)
        {
            this.ds.Search = searchFilter.Text;
            searchServiceInfo.Text = searchFilter.Text;
            BindServiceData(true);
        }


        private void searchServiceInfo_TextChanged(object sender, EventArgs e)
        {
            this.ds.Search = searchServiceInfo.Text;
            searchFilter.Text = searchServiceInfo.Text;
            BindServiceData(true);
        }

        #endregion

        #region Methods

        /// <summary>
        /// Creates the datasource, the tray icon and binds the grid,
        /// </summary>
        private void InitializeForm()
        {
#if DEBUG
            WindowState = FormWindowState.Normal;
#endif
            this.ds = new ServiceDataSource();

            // grid binding
            InitializeGrid();

            BuildTrayMenu();

            System.Reflection.Assembly ass = System.Reflection.Assembly.GetExecutingAssembly();
            statusstrip_statuslabel.Text = string.Concat("v", ass.GetName().Version.ToString());
        }

        /// <summary>
        /// Initializes the grid programmatically (set alternating row style and so on..)
        /// </summary>
        private void InitializeGrid()
        {
            servicegrid.AlternatingRowsDefaultCellStyle.BackColor = servicegrid.DefaultCellStyle.BackColor.ChangeBrightness(-25);
            BindServiceData(true);
            this.servicegrid.Rows[0].Selected = true;
            this.servicegrid.Focus();
        }

        /// <summary>
        /// Builds the tray menu, adds the selected favorite services.
        /// </summary>
        private void BuildTrayMenu()
        {
            var favorites = (from sw in ds.GetServices() where sw.IsFavorite orderby sw.DisplayName descending select sw).ToList<ServiceWrapper>();

            while (this.trayicon_menu.Items.Count > 6)
            {
                this.trayicon_menu.Items.RemoveAt(2);
            }

            if (favorites.Count < 1)
            {
                return;
            }

            foreach (ServiceWrapper sw in favorites)
            {

                var item_service = new ToolStripMenuItem();
                item_service.Text = GetServiceMenuItemText(sw);
                item_service.Tag = sw;
                item_service.Checked = sw.Status == ServiceControllerStatus.Running;
                item_service.ToolTipText = Properties.Resources.NotifyIcon_Menu_FavoriteServicesLabel_Tooltip;
                item_service.Click += delegate(object sender, EventArgs e)
                {
                    var i = sender as ToolStripMenuItem;
                    var swi = i.Tag as ServiceWrapper;
                    if (item_service.Checked)
                    {
                        swi.Stop();
                        if (ServiceManagerForm.IsElevated)
                        {
                            SetStatusUpdateNotificationTimer(swi, ServiceControllerStatus.Stopped, item_service);
                        }
                    }
                    else
                    {
                        swi.Start();
                        if (ServiceManagerForm.IsElevated)
                        {
                            SetStatusUpdateNotificationTimer(swi, ServiceControllerStatus.Running, item_service);
                        }
                    }
                };
                this.trayicon_menu.Items.Insert(1, item_service);
            }
            this.trayicon_menu.Items.Insert(1, new ToolStripSeparator());
            var favorite_label = new ToolStripLabel(Properties.Resources.NotifyIcon_Menu_FavoriteServicesLabel_Text);
            favorite_label.Font = new Font(System.Drawing.SystemFonts.IconTitleFont, FontStyle.Bold);
            favorite_label.ForeColor = System.Drawing.SystemColors.InfoText;
            this.trayicon_menu.Items.Insert(2, favorite_label);

        }

        /// <summary>
        /// The service menu item string like [service name] - [service state]
        /// </summary>
        /// <param name="sw"></param>
        /// <returns></returns>
        private static string GetServiceMenuItemText(ServiceWrapper sw)
        {
            var msg = string.Format(Properties.Resources.NotifyIcon_Menu_Service, sw.DisplayName, sw.Status.ToString());
            return msg;
        }

        /// <summary>
        /// Starts a timer for the specified service
        /// and after the services reached the desired status it refreshes the grid.
        /// </summary>
        /// <param name="sw"></param>
        /// <param name="statusToWaitFor"></param>
        private void SetStatusUpdateNotificationTimer(ServiceWrapper sw, ServiceControllerStatus statusToWaitFor, ToolStripMenuItem item_service)
        {
            if (item_service != null)
            {
                item_service.Enabled = false;
            }
            var refresh = new Timer();
            refresh.Interval = 200;
            refresh.Tick += delegate(object sender2, EventArgs e2)
            {
                sw.ServiceController.Refresh();
                if (sw.ServiceController.Status == statusToWaitFor)
                {
                    if (item_service != null)
                    {
                        item_service.Checked = (sw.ServiceController.Status == ServiceControllerStatus.Running);
                        item_service.Text = GetServiceMenuItemText(sw);
                        item_service.Enabled = true;
                    }
                    ShowServiceState(sw);
                    BindServiceData(false);
                    BuildTrayMenu();
                    refresh.Stop();
                }
            };
            refresh.Start();
        }


        /// <summary>
        /// Displays the service state as a balloon.
        /// </summary>
        /// <param name="sw"></param>
        private void ShowServiceState(ServiceWrapper sw)
        {
            var msg = string.Format(CultureInfo.InvariantCulture, Properties.Resources.NotifyIcon_Baloon_Service_State, sw.DisplayName, sw.Status.ToString().ToLowerInvariant());
            trayicon.ShowBalloonTip(2000, Properties.Resources.NotifyIcon_Baloon_Header, msg, ToolTipIcon.Info);
        }

        /// <summary>
        /// Refreshes the services info and binds the data to the grid.
        /// </summary>
        /// <param name="refresh_services">If TRUE the list of services is refreshed as well.</param>
        private void BindServiceData(bool refresh_services)
        {
            string selected_service_name = this.instance_selected_service_name;

            if (selected_service_name == null)
            {
                selected_service_name = GetSelectedServiceName();
            }

            var list = ds.GetServicesSearched(refresh_services);
            DataGridViewColumn sorted_column = servicegrid.SortedColumn;
            if (sorted_column != null)
            {
                Properties.Settings.Default.SortColumnName = sorted_column.DataPropertyName;
                Properties.Settings.Default.SortOrder = servicegrid.SortOrder;
            }
            else
            {
                sorted_column = (from DataGridViewColumn c in servicegrid.Columns where c.DataPropertyName == Properties.Settings.Default.SortColumnName select c).Single<DataGridViewColumn>();
            }
            var sorting_list = new SortableBindingList<ServiceWrapper>(list);
            this.servicegrid.DataSource = sorting_list;
            if (sorted_column != null)
            {
                servicegrid.Sort(sorted_column, Properties.Settings.Default.SortOrder == SortOrder.Descending ? ListSortDirection.Descending : ListSortDirection.Ascending);
            }

            if (selected_service_name != null)
            {
                servicegrid.ClearSelection();
                var row = (from DataGridViewRow r in servicegrid.Rows where (r.DataBoundItem as ServiceWrapper).DisplayName == selected_service_name select r).SingleOrDefault<DataGridViewRow>();
                if (row != null)
                {
                    row.Selected = true;
                    servicegrid.FirstDisplayedScrollingRowIndex = row.Index;
                }
            }
            servicegrid.Update();
        }

        /// <summary>
        /// Gets the name of the selected service.
        /// </summary>
        /// <returns></returns>
        private string GetSelectedServiceName()
        {
            string selected_service_name = null;
            if (servicegrid.SelectedRows.Count > 0)
            {
                selected_service_name = (servicegrid.SelectedRows[0].DataBoundItem as ServiceWrapper).DisplayName;
            }
            return selected_service_name;
        }

        /// <summary>
        /// If the window is minimized it will hidden in the tray.
        /// </summary>
        private void SetTaskbarState()
        {
            if (FormWindowState.Minimized == this.WindowState)
            {
                this.ShowInTaskbar = false;

                if (!Properties.Settings.Default.TrayBalloonShown)
                {
                    this.trayicon.ShowBalloonTip(5000, Properties.Resources.NotifyIcon_Baloon_Header, Properties.Resources.NotifyIcon_Baloon_Hide, ToolTipIcon.Info);
                    Properties.Settings.Default.TrayBalloonShown = true;
                }
            }
            else
            {
                this.ShowInTaskbar = true;
            }
        }

        public static bool IsElevated
        {
            get
            {
                WindowsPrincipal pricipal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
                bool hasAdministrativeRight = pricipal.IsInRole(WindowsBuiltInRole.Administrator);
                return hasAdministrativeRight;
            }
        }

        public static void RequestElevatation(String serviceName, bool falseIsToStopAndTrueIsToStart)
        {

            ProcessStartInfo processInfo = new ProcessStartInfo();
            processInfo.Verb = "runas";
            processInfo.FileName = Application.ExecutablePath;
            processInfo.Arguments = serviceName + " " + falseIsToStopAndTrueIsToStart.ToString();
            try
            {
                Process.Start(processInfo);
            }
            catch (Win32Exception)
            {
                return;
            }
            Application.Exit();
        }

        #endregion

        #region Commands
        /// <summary>
        /// Displays the form.
        /// </summary>
        private void ShowForm()
        {
            this.WindowState = FormWindowState.Normal;
        }

        /// <summary>
        /// Saves the settings and quits.
        /// </summary>
        public void QuitForm()
        {
            SaveSettings();
            Application.Exit();
        }

        /// <summary>
        /// Saves the grid sort settings into the program settings.
        /// </summary>
        private void SaveGridSortState()
        {
            if (servicegrid.SortedColumn != null)
            {
                Properties.Settings.Default.SortColumnName = servicegrid.SortedColumn.DataPropertyName;
                Properties.Settings.Default.SortOrder = servicegrid.SortOrder;
            }
        }

        /// <summary>
        /// Saves settings.
        /// Save grid sort state.
        /// </summary>
        private void SaveSettings()
        {
            SaveGridSortState();
            Properties.Settings.Default.Save();
        }


        /// <summary>
        /// Minimizes the form.
        /// </summary>
        private void MinimizeForm()
        {
            WindowState = FormWindowState.Minimized;
        }

        /// <summary>
        /// Shows or hides the main form based on the visibility (toggle).
        /// </summary>
        private void ToggleFormDisplay()
        {
            if (WindowState != FormWindowState.Minimized)
            {
                MinimizeForm();
            }
            else
            {
                ShowForm();
            }

        }


        private void RefreshGrid()
        {
            BindServiceData(true);
        }

        #endregion

        #region Events

        /// <summary>
        /// When the form is resized, the taskbar state is set.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ServiceManagerForm_Resize(object sender, EventArgs e)
        {
            SetTaskbarState();
        }


        /// <summary>
        /// When the form is closed, it is minimized instead so that it is hidden in the tray.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ServiceManagerForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (e.CloseReason != CloseReason.ApplicationExitCall)
            {
                e.Cancel = true;
                WindowState = FormWindowState.Minimized;
            }
        }

        #endregion

        #region Tray Icon Menu Events

        /// <summary>
        /// On left mouse click, show the service manager on the tray icon.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void trayicon_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                ToggleFormDisplay();
            }
        }

        /// <summary>
        /// Show the service manager on the tray menu item click.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void trayicon_menu_servicemanager_Click(object sender, EventArgs e)
        {
            ToggleFormDisplay();
        }

        /// <summary>
        /// When exit is clicked the quit method is called.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void trayicon_menu_exit_Click(object sender, EventArgs e)
        {
            QuitForm();
        }

        #endregion

        #region Main menu events


        /// <summary>
        /// About menu.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void mainmenu_help_about_Click(object sender, EventArgs e)
        {
            MessageBox.Show(global::chc.servicemanagertray.Properties.Resources.About_Text, global::chc.servicemanagertray.Properties.Resources.About_Title, MessageBoxButtons.OK, MessageBoxIcon.Information);
        }


        /// <summary>
        /// Options menu
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void mainmenu_tools_option_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Not implemented at the moment.", global::chc.servicemanagertray.Properties.Resources.About_Title, MessageBoxButtons.OK, MessageBoxIcon.Warning);
        }

        #endregion

        #region Grid Events

        private void Servicegrid_CellMouseEnter(object sender, DataGridViewCellEventArgs e)
        {
            if (e.ColumnIndex < 0 || e.RowIndex < 0)
            {
                return;
            }
            var dataGridView = (sender as DataGridView);
            //Check the condition as per the requirement casting the cell value to the appropriate type
            servicegrid.Cursor = Cursors.Default;
            switch (e.ColumnIndex)
            {
                case 2:
                case 3:
                case 4:
                    servicegrid.Cursor = Cursors.Hand;
                    break;

                default:
                    servicegrid.Cursor = Cursors.Default;
                    break;
            }
        }

        /// <summary>
        /// Renders the info panel contents on the left.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void servicegrid_CurrentCellChanged(object sender, EventArgs e)
        {
            if (servicegrid.CurrentRow != null)
            {
                ServiceWrapper sw = servicegrid.CurrentRow.DataBoundItem as ServiceWrapper;
                infopanel_name.Text = sw.ServiceController.DisplayName;
                infopanel_description.Text = sw.Description;

            }
        }


        /// <summary>
        /// Selects the service row on right click also.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void servicegrid_MouseDown(object sender, MouseEventArgs e)
        {
            // Sets is so the right-mousedown will select a cell
            DataGridView.HitTestInfo hti = servicegrid.HitTest(e.X, e.Y);

            if (hti.RowIndex == -1)
            {
                return;
            }

            // Clear all the previously selected rows
            servicegrid.ClearSelection();

            // Set as selected
            servicegrid.Rows[hti.RowIndex].Selected = true;
        }


        /// <summary>
        /// Updates the ui to make a service favorita or start/stop on the gui.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void servicegrid_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            if (e.RowIndex < 0)
            {
                return;
            }
            var row = servicegrid.Rows[e.RowIndex];
            var sw = row.DataBoundItem as ServiceWrapper;

            switch (row.Cells[e.ColumnIndex].OwningColumn.DataPropertyName)
            {
                case "IsFavorite":
                    sw.IsFavorite = !sw.IsFavorite;
                    this.BuildTrayMenu();
                    SaveSettings();
                    break;

                case "Status":
                case "IsRunning":
                    ToolStripMenuItem menu_item = null;
                    bool new_state = !sw.IsRunning;
                    sw.IsRunning = new_state;

                    if (IsElevated)
                    {
                        SetStatusUpdateNotificationTimer(sw, new_state ? ServiceControllerStatus.Running : ServiceControllerStatus.Stopped, menu_item);

                        // find corresponding tray menu item
                        foreach (ToolStripItem item in trayicon_menu.Items)
                        {
                            menu_item = item as ToolStripMenuItem;
                            if (menu_item != null && menu_item.Tag == sw)
                            {
                                break;
                            }
                            menu_item = null;
                        }
                        break;
                    }
                    break;
            }
        }
        #endregion

        #region Generic Command Events

        /// <summary>
        /// Generic refresh command.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void generic_refreshbutton_Click(object sender, EventArgs e)
        {
            RefreshGrid();
        }


        /// <summary>
        /// Generic exit command.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void generic_exit_Click(object sender, EventArgs e)
        {
            QuitForm();
        }
        #endregion


        #region Tool Strip Events

        /// <summary>
        /// Starts the windows service manager.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void toolstrip_winservicemanager_Click(object sender, EventArgs e)
        {
            Process.Start("services.msc");
        }

        /// <summary>
        /// Starts the windows task manager.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void toolstrip_taskmanager_Click(object sender, EventArgs e)
        {
            Process.Start("taskmgr.exe");

        }


        #endregion

    }
}