Tuesday, 24 February 2015

Creating windows service using C# for windows mobile Threshold (Windows 10) Platform


Service implementation for Windows Threshold Mobile


Services are controlled by Service Control Manager as in the Desktop Version. But for Mobile Threshold need to be compiled with and liked with the libraries (Mincore.lib) as mentioned in an Essential components of a service:

We should use mincore library for creating and deploy service in Threshold platform. So that I’m creating wrapper class in c which is used to communicate from c# application

To Implement the below functionality in “Windows Service” wrapper project

            Step1: Create instance for “service controller manager “which is used control our windows service like create, start, stop, restart and delete.

SC_HANDLE OpenServiceControlManager()
{
       SC_HANDLE schSCManager;
       schSCManager = OpenSCManager(
              NULL,                    // local computer
              NULL,                    // ServicesActive database
              SC_MANAGER_ALL_ACCESS);  // full access rights

       if (NULL == schSCManager)
       {
              SvcLog(SVC_LOG_DEBUG, SVC_LOG, "OpenSCManager failed (%d)", GetLastError());
              return NULL;
       }

       return schSCManager;
}

Step 2: Create windows service to the target platform

SC_HANDLE SvcInstall(SC_HANDLE schSCManager, LPCWSTR szPath, LPCWSTR serviceName, LPCWSTR lpszServiceDisplayName)
{
       SC_HANDLE schService1;
       if (NULL == schSCManager)
       {
              SvcLog(SVC_LOG_DEBUG, SVC_LOG, "OpenSCManager failed (%d)", GetLastError());
              return NULL;
       }

       SvcLog(SVC_LOG_DEBUG, SVC_LOG, "Service Name [%s]", serviceName);
       SvcLog(SVC_LOG_DEBUG, SVC_LOG, "Service display Name [%s]", lpszServiceDisplayName);
       SvcLog(SVC_LOG_DEBUG, SVC_LOG, "path to service's binary  [%s]", szPath);
       schService1 = CreateServiceW(
              schSCManager,              // SCM database
              serviceName,               // name of service
              lpszServiceDisplayName,    // service name to display
              SERVICE_ALL_ACCESS,        // desired access
              SERVICE_WIN32_OWN_PROCESS, // service type
              SERVICE_AUTO_START,        // start type
              SERVICE_ERROR_NORMAL,      // error control type
              SVC_PATH,                  // path to service's binary              
              NULL,                      // no load ordering group
              NULL,                      // no tag identifier
              NULL,                      // no dependencies
              NULL,                      // LocalSystem account
              NULL);                     // no password

       if (schService1 == NULL)
       {
              SvcLog(SVC_LOG_DEBUG, SVC_LOG, "CreateService failed (%d)", GetLastError());
              return schService1;
       }
       else SvcLog(SVC_LOG_DEBUG, SVC_LOG, "Service installed successfully");

       CloseServiceHandle(schService1);
       return schService1;
}

Step 3: Fetch the service from SCM Database and start service

int DoStartSvc(SC_HANDLE schSCManager, LPCWSTR serviceName, DWORD ServiceRights)
{
       SERVICE_STATUS_PROCESS ssStatus;
       DWORD dwOldCheckPoint;
       DWORD dwStartTickCount;
       DWORD dwWaitTime;
       DWORD dwBytesNeeded;
       SC_HANDLE schService;

       SvcLog(SVC_LOG_DEBUG, SVC_LOG, "Service Name [%s]", serviceName);
       schService = OpenServiceW(
              schSCManager,       // SCM database
              SVC_NAME,          // name of service
              SERVICE_ALL_ACCESS);            // need delete access

       if (schService == NULL)
       {
              SvcLog(SVC_LOG_DEBUG, SVC_LOG, "DoStartSvc :OpenService failed (%d)", GetLastError());
              return GetLastError();
       }

       // Check the status in case the service is not stopped.

       if (!QueryServiceStatusEx(
              schService,                     // handle to service
              SC_STATUS_PROCESS_INFO,         // information level
              (LPBYTE)&ssStatus,             // address of structure
              sizeof(SERVICE_STATUS_PROCESS), // size of structure
              &dwBytesNeeded))              // size needed if buffer is too small
       {
              SvcLog(SVC_LOG_DEBUG, SVC_LOG, "QueryServiceStatusEx failed (%d)", GetLastError());
              return GetLastError();
       }

       // Check if the service is already running. It would be possible
       // to stop the service here, but for simplicity this example just returns.

       if (ssStatus.dwCurrentState != SERVICE_STOPPED && ssStatus.dwCurrentState != SERVICE_STOP_PENDING)
       {
              SvcLog(SVC_LOG_DEBUG, SVC_LOG, "Cannot start the service because it is already running");
              return GetLastError();
       }

       // Save the tick count and initial checkpoint.

       dwStartTickCount = GetTickCount();
       dwOldCheckPoint = ssStatus.dwCheckPoint;

       // Wait for the service to stop before attempting to start it.

       while (ssStatus.dwCurrentState == SERVICE_STOP_PENDING)
       {
              // Do not wait longer than the wait hint. A good interval is
              // one-tenth of the wait hint but not less than 1 second 
              // and not more than 10 seconds.

              dwWaitTime = ssStatus.dwWaitHint / 10;
              SvcLog(SVC_LOG_DEBUG, SVC_LOG, "Current Service State Is SERVICE_STOP_PENDING");
              if (dwWaitTime < 1000)
                     dwWaitTime = 1000;
              else if (dwWaitTime > 10000)
                     dwWaitTime = 10000;

              Sleep(dwWaitTime);

              // Check the status until the service is no longer stop pending.

              if (!QueryServiceStatusEx(
                     schService,                     // handle to service
                     SC_STATUS_PROCESS_INFO,         // information level
                     (LPBYTE)&ssStatus,             // address of structure
                     sizeof(SERVICE_STATUS_PROCESS), // size of structure
                     &dwBytesNeeded))              // size needed if buffer is too small
              {
                     SvcLog(SVC_LOG_DEBUG, SVC_LOG, "QueryServiceStatusEx failed (%d)", GetLastError());
                     return GetLastError();
              }

              if (ssStatus.dwCheckPoint > dwOldCheckPoint)
              {
                     // Continue to wait and check.

                     dwStartTickCount = GetTickCount();
                     dwOldCheckPoint = ssStatus.dwCheckPoint;
              }
              else
              {
                     if (GetTickCount() - dwStartTickCount > ssStatus.dwWaitHint)
                     {
                           SvcLog(SVC_LOG_DEBUG, SVC_LOG, "Timeout waiting for service to stop");
                           return GetLastError();
                     }
              }
       }

       // Attempt to start the service.
       if (!StartService(
              schService,  // handle to service
              0,           // number of arguments
              NULL))      // no arguments
       {
              SvcLog(SVC_LOG_DEBUG, SVC_LOG, "StartService failed (%d)", GetLastError());
              return GetLastError();
       }
       else SvcLog(SVC_LOG_DEBUG, SVC_LOG, "Service start pending...");

       // Check the status until the service is no longer start pending.

       if (!QueryServiceStatusEx(
              schService,                     // handle to service
              SC_STATUS_PROCESS_INFO,         // info level
              (LPBYTE)&ssStatus,             // address of structure
              sizeof(SERVICE_STATUS_PROCESS), // size of structure
              &dwBytesNeeded))              // if buffer too small
       {
              SvcLog(SVC_LOG_DEBUG, SVC_LOG, "QueryServiceStatusEx failed (%d)", GetLastError());
              return GetLastError();
       }

       // Save the tick count and initial checkpoint.

       dwStartTickCount = GetTickCount();
       dwOldCheckPoint = ssStatus.dwCheckPoint;

       while (ssStatus.dwCurrentState == SERVICE_START_PENDING)
       {
              // Do not wait longer than the wait hint. A good interval is
              // one-tenth the wait hint, but no less than 1 second and no
              // more than 10 seconds.

              SvcLog(SVC_LOG_DEBUG, SVC_LOG, "Current Service State Is SERVICE_START_PENDING");
              dwWaitTime = ssStatus.dwWaitHint / 10;

              if (dwWaitTime < 1000)
                     dwWaitTime = 1000;
              else if (dwWaitTime > 10000)
                     dwWaitTime = 10000;

              Sleep(dwWaitTime);

              // Check the status again.
              if (!QueryServiceStatusEx(
                     schService,             // handle to service
                     SC_STATUS_PROCESS_INFO, // info level
                     (LPBYTE)&ssStatus,             // address of structure
                     sizeof(SERVICE_STATUS_PROCESS), // size of structure
                     &dwBytesNeeded))              // if buffer too small
              {
                     SvcLog(SVC_LOG_DEBUG, SVC_LOG, "QueryServiceStatusEx failed (%d)", GetLastError());
                     break;
              }

              if (ssStatus.dwCheckPoint > dwOldCheckPoint)
              {
                     // Continue to wait and check.

                     dwStartTickCount = GetTickCount();
                     dwOldCheckPoint = ssStatus.dwCheckPoint;
              }
              else
              {
                     if (GetTickCount() - dwStartTickCount > ssStatus.dwWaitHint)
                     {
                           // No progress made within the wait hint.
                           break;
                     }
              }
       }

       // Determine whether the service is running.
       if (ssStatus.dwCurrentState == SERVICE_RUNNING)
       {
              SvcLog(SVC_LOG_DEBUG, SVC_LOG, "Service started successfully.");
              SvcLog(SVC_LOG_DEBUG, SVC_LOG, "+++++++++++++++++++++++++++++++++++++++++++++++++++++");
       }
       else
       {
              SvcLog(SVC_LOG_DEBUG, SVC_LOG, "Service not started. ");
              SvcLog(SVC_LOG_DEBUG, SVC_LOG, "  Current State: %d", ssStatus.dwCurrentState);
              SvcLog(SVC_LOG_DEBUG, SVC_LOG, "  Exit Code: %d", ssStatus.dwWin32ExitCode);
              SvcLog(SVC_LOG_DEBUG, SVC_LOG, "  Check Point: %d", ssStatus.dwCheckPoint);
              SvcLog(SVC_LOG_DEBUG, SVC_LOG, "  Wait Hint: %d", ssStatus.dwWaitHint);
       }

       CloseServiceHandle(schService);
       //CloseServiceHandle(schSCManager);

       return 0;
}
Step 4: Start method will be call StartServiceCtrl_Dispatcher and Connects the main thread of a service process to the service control manager, which causes the thread to be the service control dispatcher thread for the calling process.

int StartServiceCtrl_Dispatcher(SERVICE_TABLE_ENTRYW* DispatchTable1)//, LPHANDLER_FUNCTION SvcCtrlHandler)
{
       SvcLog(SVC_LOG_DEBUG, SVC_LOG, "No param will continue running service");

       if (!StartServiceCtrlDispatcherW(DispatchTable1))
       {
              SvcLog(SVC_LOG_DEBUG, SVC_LOG, TEXT("StartServiceCtrlDispatcher"));
              return 1;
       }

       return 0;
}

bool RegisterService_CtrlHandlerW(LPCWSTR lpServiceName, LPHANDLER_FUNCTION SvcCtrl_Handler)
{
       SvcLog(SVC_LOG_DEBUG, SVC_LOG, "Calling C++ Wrapper Class RegisterServiceCtrlHandlerW methods");
       gSvcStatusHandle = RegisterServiceCtrlHandlerW(
              SVC_NAME,
              SvcCtrlHandler);
       SvcLog(SVC_LOG_DEBUG, SVC_LOG, "Service Name [%s]", lpServiceName);
       if (!gSvcStatusHandle)
       {
              SvcLog(SVC_LOG_DEBUG, SVC_LOG, "RegisterServiceCtrlHandler");
              return false;
       }

       // These SERVICE_STATUS members remain as set here

       gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
       gSvcStatus.dwServiceSpecificExitCode = 0;

       // Report initial status to the SCM

       ReportSvcStatus(SERVICE_START_PENDING, NO_ERROR, 3000);
       SvcLog(SVC_LOG_DEBUG, SVC_LOG, "SERVICE_START_PENDING");
      
       return true;

}
Step 5: Set the service status like stopped, running
bool SetSvcStatus()// SERVICE_STATUS_HANDLE hServiceStatus, SERVICE_STATUS status)
{
       SvcLog(SVC_LOG_DEBUG, SVC_LOG, "Calling SvcInitService");
       ghSvcStopEvent = CreateEvent(
              NULL,    // default security attributes
              TRUE,    // manual reset event
              FALSE,   // not signaled
              NULL);   // no name

       if (ghSvcStopEvent == NULL)
       {
              ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0);
              SvcLog(SVC_LOG_DEBUG, SVC_LOG, "SERVICE_STOPPED");
              return false;
       }

       // Report running status when initialization is complete.
       ReportSvcStatus(SERVICE_RUNNING, NO_ERROR, 0);

       HANDLE waitEvents[1] = {
              ghSvcStopEvent
       };
       while (1)
       {
              DWORD eventRxIndex = WSAWaitForMultipleEvents(1, waitEvents, FALSE, INFINITE, FALSE);
              if ((0 + WAIT_OBJECT_0) == eventRxIndex){
                     SvcLog(SVC_LOG_DEBUG, SVC_LOG, "Get 0 Event for controlling service");
                     /*Accept event received*/
                     //SvcCtrlHandler(eventRxIndex);
                     ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0);
                     SvcLog(SVC_LOG_DEBUG, SVC_LOG, "SERVICE_STOPPED");    
              }
              return true;
       }

       SvcLog(SVC_LOG_DEBUG, SVC_LOG, "Successfully SvcInitService");
       return true;
}

Service implementation in c# application

Step1: Create console application and add ServiceInstaller helper class and implement the following functionality for communicate Service wrapper class

using System;
using System.Runtime.InteropServices;

namespace TeleClient
{   
    /// <summary>
    ///
    /// </summary>
    [Flags]
    public enum ServiceRights
    {
        /// <summary>
        ///
        /// </summary>
        QueryConfig = 0x1,
        /// <summary>
        ///
        /// </summary>
        ChangeConfig = 0x2,
        /// <summary>
        ///
        /// </summary>
        QueryStatus = 0x4,
        /// <summary>
        ///
        /// </summary>
        EnumerateDependants = 0x8,
        /// <summary>
        ///
        /// </summary>
        Start = 0x10,
        /// <summary>
        ///
        /// </summary>
        Stop = 0x20,
        /// <summary>
        ///
        /// </summary>
        PauseContinue = 0x40,
        /// <summary>
        ///
        /// </summary>
        Interrogate = 0x80,
        /// <summary>
        ///
        /// </summary>
        UserDefinedControl = 0x100,
        /// <summary>
        ///
        /// </summary>
        Delete = 0x00010000,
        /// <summary>
        ///
        /// </summary>
        StandardRightsRequired = 0xF0000,
        /// <summary>
        ///
        /// </summary>
        AllAccess = (StandardRightsRequired | QueryConfig | ChangeConfig |
        QueryStatus | EnumerateDependants | Start | Stop | PauseContinue |
        Interrogate | UserDefinedControl)
    }

    /// <summary>
    ///
    /// </summary>
    public enum ServiceBootFlag
    {
        /// <summary>
        ///
        /// </summary>
        Start = 0x00000000,
        /// <summary>
        ///
        /// </summary>
        SystemStart = 0x00000001,
        /// <summary>
        ///
        /// </summary>
        AutoStart = 0x00000002,
        /// <summary>
        ///
        /// </summary>
        DemandStart = 0x00000003,
        /// <summary>
        ///
        /// </summary>
        Disabled = 0x00000004
    }

    /// <summary>
    ///
    /// </summary>
    public enum ServiceState
    {
        /// <summary>
        ///
        /// </summary>
        Unknown = -1, // The state cannot be (has not been) retrieved.
        /// <summary>
        ///
        /// </summary>
        NotFound = 0, // The service is not known on the host server.
        /// <summary>
        ///
        /// </summary>
        Stop = 1, // The service is NET stopped.
        /// <summary>
        ///
        /// </summary>
        Run = 2, // The service is NET started.
        /// <summary>
        ///
        /// </summary>
        Stopping = 3,
        /// <summary>
        ///
        /// </summary>
        Starting = 4,
    }

    /// <summary>
    ///
    /// </summary>
    public enum ServiceControl
    {
        /// <summary>
        ///
        /// </summary>
        Stop = 0x00000001,
        /// <summary>
        ///
        /// </summary>
        Pause = 0x00000002,
        /// <summary>
        ///
        /// </summary>
        Continue = 0x00000003,
        /// <summary>
        ///
        /// </summary>
        Interrogate = 0x00000004,
        /// <summary>
        ///
        /// </summary>
        Shutdown = 0x00000005,
        /// <summary>
        ///
        /// </summary>
        ParamChange = 0x00000006,
        /// <summary>
        ///
        /// </summary>
        NetBindAdd = 0x00000007,
        /// <summary>
        ///
        /// </summary>
        NetBindRemove = 0x00000008,
        /// <summary>
        ///
        /// </summary>
        NetBindEnable = 0x00000009,
        /// <summary>
        ///
        /// </summary>
        NetBindDisable = 0x0000000A
    }

    /// <summary>
    ///
    /// </summary>
    public enum ServiceError
    {
        /// <summary>
        ///
        /// </summary>
        Ignore = 0x00000000,
        /// <summary>
        ///
        /// </summary>
        Normal = 0x00000001,
        /// <summary>
        ///
        /// </summary>
        Severe = 0x00000002,
        /// <summary>
        ///
        /// </summary>
        Critical = 0x00000003
    }

    /// <summary>
    /// Installs and provides functionality for handling windows services
    /// </summary>
    public class ServiceInstaller
    {     
        [StructLayout(LayoutKind.Sequential)]
        private class SERVICE_STATUS
        {
            public int dwServiceType = 0;
            public ServiceState dwCurrentState = 0;
            public int dwControlsAccepted = 0;
            public int dwWin32ExitCode = 0;
            public int dwServiceSpecificExitCode = 0;
            public int dwCheckPoint = 0;
            public int dwWaitHint = 0;
        }
          

        [DllImport(@"ServiceWrapper.dll", EntryPoint = "OpenServiceControlManager")]
        private static extern IntPtr OpenSCManager();      

        [DllImport("ServiceWrapper.dll", EntryPoint = "OpenWindowsService", CharSet = CharSet.Ansi)]
        private static extern IntPtr OpenService(IntPtr hSCManager,[MarshalAs(UnmanagedType.LPStr)] string lpServiceName, ServiceRights dwDesiredAccess);

        [DllImport("ServiceWrapper.dll", EntryPoint = "SvcInstall")]
        private static extern IntPtr CreateService(IntPtr hSCManager, string
        lpServiceName, string lpDisplayName, ServiceRights dwDesiredAccess, int
        dwServiceType, ServiceBootFlag dwStartType, ServiceError dwErrorControl,
        string lpBinaryPathName, string lpLoadOrderGroup, IntPtr lpdwTagId, string
        lpDependencies, string lp, string lpPassword);

        [DllImport("ServiceWrapper.dll", EntryPoint = "SvcInstall")]
        private static extern IntPtr CreateService(IntPtr hSCManager, [MarshalAs(UnmanagedType.LPStr)] string
        szPath, [MarshalAs(UnmanagedType.LPStr)] string lpServiceName, [MarshalAs(UnmanagedType.LPStr)] string lpDisplayName);

        [DllImport("ServiceWrapper.dll", EntryPoint = "CloseServiceHandler")]
        private static extern int CloseServiceHandle(IntPtr hSCObject);

        [DllImport("ServiceWrapper.dll", EntryPoint = "QueryServiceStatus")]
        private static extern int QueryServiceStatus(IntPtr hService,
        SERVICE_STATUS lpServiceStatus);

        [DllImport("ServiceWrapper.dll", SetLastError = true)]
        private static extern int DeleteService(IntPtr schSCManager,[MarshalAs(UnmanagedType.LPStr)] string serviceName);

        [DllImport("ServiceWrapper.dll")]
        private static extern int ControlService(IntPtr hService, ServiceControl
        dwControl, SERVICE_STATUS lpServiceStatus);

        [DllImport("ServiceWrapper.dll", EntryPoint = "DoStartSvc")]
        private static extern int StartService(IntPtr hSCManager, [MarshalAs(UnmanagedType.LPStr)] string lpServiceName);     

        [DllImport("ServiceWrapper.dll", EntryPoint = "ReportServiceStatus")]
        private static extern int ReportServiceStatus([MarshalAs(UnmanagedType.LPStr)] string ServiceName);

        /// <summary>
        ///
        /// </summary>
        public ServiceInstaller()
        {
        }

        /// <summary>
        /// Takes a service name and tries to stop and then uninstall the windows serviceError
        /// </summary>
        /// <param name="ServiceName">The windows service name to uninstall</param>
        public static void Uninstall(string ServiceName)
        {
            IntPtr scman = OpenServiceControlManager();
            try
            {
                IntPtr service = OpenService(scman, ServiceName, ServiceRights.StandardRightsRequired | ServiceRights.Stop |
                ServiceRights.QueryStatus);
                if (service == IntPtr.Zero)
                {
                    throw new ApplicationException("Service not installed.");
                }
                try
                {
                    StopService(service);
                    int ret = DeleteService(service, ServiceName);
                    if (ret == 0)
                    {
                        int error = Marshal.GetLastWin32Error();
                        throw new ApplicationException("Could not delete service " + error);
                    }
                }
                catch (Exception ex)
                {
                    Console.Write(ex.Message);
                }
                finally
                {
                    CloseServiceHandle(service);
                }
            }
            catch (Exception ex)
            {
                Console.Write(ex.Message);
            }
            finally
            {
                CloseServiceHandle(scman);
            }
        }

        /// <summary>
        /// Accepts a service name and returns true if the service with that service name exists
        /// </summary>
        /// <param name="ServiceName">The service name that we will check for existence</param>
        /// <returns>True if that service exists false otherwise</returns>
        public static bool ServiceIsInstalled(string ServiceName)
        {
            IntPtr scman = OpenServiceControlManager();
            try
            {
                IntPtr service = OpenService(scman, ServiceName, ServiceRights.QueryStatus);
                if (service == IntPtr.Zero) return false;
                CloseServiceHandle(service);
                return true;
            }
            finally
            {
                CloseServiceHandle(scman);
            }
        }

        /// <summary>
        /// Takes a service name, a service display name and the path to the service executable and installs / starts the windows service.
        /// </summary>
        /// <param name="ServiceName">The service name that this service will have</param>
        /// <param name="DisplayName">The display name that this service will have</param>
        /// <param name="FileName">The path to the executable of the service</param>
        public static void Install(string ServiceName, string DisplayName, string FileName)
        {
            Logger.Log.Info("Try to open SC Manager");
            IntPtr scman = OpenServiceControlManager();
            try
            {              
                Logger.Log.Info("Create Tele service ");
                IntPtr service = CreateService(scman, FileName, ServiceName, DisplayName);             
                if (service == IntPtr.Zero)
                {
                    throw new ApplicationException("Failed to install service.");
                }              
            }
            catch
            {
                throw;
            }
            finally
            {
                CloseServiceHandle(scman);
            }
        }

        /// <summary>
        /// Takes a service name and starts it
        /// </summary>
        /// <param name="serviceName">The service name</param>
        public static void StartService(string serviceName)
        {
            IntPtr scman = OpenServiceControlManager();
            try
            {
                IntPtr hService = OpenService(scman, serviceName, ServiceRights.QueryStatus |
                ServiceRights.Start);
                Logger.Log.Info("Successfully opened SCManager");
                if (hService == IntPtr.Zero)
                {
                    throw new ApplicationException("Could not open service.");
                }
                try
                {
                    StartService(hService, serviceName);
                }
                catch (Exception ex)
                {
                    Console.Write(ex.Message);
                }
                finally
                {
                    CloseServiceHandle(hService);
                }
            }
            catch (Exception ex)
            {
                Console.Write(ex.Message);
            }
            finally
            {
                CloseServiceHandle(scman);
            }
        }     

        /// <summary>
        /// Stops the provided windows service
        /// </summary>
        /// <param name="Name">The service name that will be stopped</param>
        public static void StopService(string Name)
        {
            IntPtr scman = OpenServiceControlManager();
            try
            {
                IntPtr hService = OpenService(scman, Name, ServiceRights.QueryStatus | ServiceRights.Stop);
                Console.Write("Successfullt opened SCManager");
                if (hService == IntPtr.Zero)
                {
                    throw new ApplicationException("Could not open service.");
                }
                try
                {
                    StopService(hService);
                }
                catch (Exception ex)
                {
                    Console.Write(ex.Message);
                }

                finally
                {
                    CloseServiceHandle(hService);
                }
            }
            catch (Exception ex)
            {
                Console.Write(ex.Message);
            }
            finally
            {
                CloseServiceHandle(scman);
            }
        }

        /// <summary>
        /// Stars the provided windows service
        /// </summary>
        /// <param name="hService">The handle to the windows service</param>
        private static void StartService(IntPtr hService, string serviceName, int? state = null)
        {
            SERVICE_STATUS status = new SERVICE_STATUS();
            StartService(hService, serviceName);
            Console.Write("~: Service started Successfully");
            WaitForServiceStatus(hService, ServiceState.Starting, ServiceState.Run);
        }      

        /// <summary>
        /// Stops the provided windows service
        /// </summary>
        /// <param name="hService">The handle to the windows service</param>
        public static void ReportSvcStatus(string ServiceName)
        {
            ReportServiceStatus(ServiceName);
            Logger.Log.Info("Service successfully started");
        }

        /// <summary>
        /// Stops the provided windows service
        /// </summary>
        /// <param name="hService">The handle to the windows service</param>
        private static void StopService(IntPtr hService)
        {
            SERVICE_STATUS status = new SERVICE_STATUS();
            ControlService(hService, ServiceControl.Stop, status);
            Console.Write("Service stoped Successfully");
            WaitForServiceStatus(hService, ServiceState.Stopping, ServiceState.Stop);
        }

        /// <summary>
        /// Takes a service name and returns the <code>ServiceState</code> of the corresponding service
        /// </summary>
        /// <param name="ServiceName">The service name that we will check for his <code>ServiceState</code></param>
        /// <returns>The ServiceState of the service we wanted to check</returns>
        public static ServiceState GetServiceStatus(string ServiceName)
        {
            IntPtr scman = OpenServiceControlManager();
            try
            {
                IntPtr hService = OpenService(scman, ServiceName,
                ServiceRights.QueryStatus);
                if (hService == IntPtr.Zero)
                {
                    return ServiceState.NotFound;
                }
                try
                {
                    return GetServiceStatus(hService);
                }
                finally
                {
                    CloseServiceHandle(scman);
                }
            }
            finally
            {
                CloseServiceHandle(scman);
            }
        }

        /// <summary>
        /// Gets the service state by using the handle of the provided windows service
        /// </summary>
        /// <param name="hService">The handle to the service</param>
        /// <returns>The <code>ServiceState</code> of the service</returns>
        private static ServiceState GetServiceStatus(IntPtr hService)
        {
            SERVICE_STATUS ssStatus = new SERVICE_STATUS();
            Logger.Log.Info("make query for service status.");
            if (QueryServiceStatus(hService, ssStatus) == 0)
            {
                Logger.Log.Info("Failed to query service status.");
                throw new ApplicationException("Failed to query service status.");
            }
            return ssStatus.dwCurrentState;
        }

        /// <summary>
        /// Returns true when the service status has been changes from wait status to desired status
        /// ,this method waits around 10 seconds for this operation.
        /// </summary>
        /// <param name="hService">The handle to the service</param>
        /// <param name="WaitStatus">The current state of the service</param>
        /// <param name="DesiredStatus">The desired state of the service</param>
        /// <returns>bool if the service has successfully changed states within the allowed timeline</returns>
        private static bool WaitForServiceStatus(IntPtr hService, ServiceState
        WaitStatus, ServiceState DesiredStatus)
        {
            SERVICE_STATUS ssStatus = new SERVICE_STATUS();
            int dwOldCheckPoint;
            int dwStartTickCount;
            Logger.Log.Info("make query for service status and WaitForServiceStatus.");
            QueryServiceStatus(hService, ssStatus);
            if (ssStatus.dwCurrentState == DesiredStatus) return true;
            dwStartTickCount = Environment.TickCount;
            dwOldCheckPoint = ssStatus.dwCheckPoint;

            while (ssStatus.dwCurrentState == WaitStatus)
            {
                // Do not wait longer than the wait hint. A good interval is
                // one tenth the wait hint, but no less than 1 second and no
                // more than 10 seconds.

                int dwWaitTime = ssStatus.dwWaitHint / 10;

                if (dwWaitTime < 1000) dwWaitTime = 1000;
                else if (dwWaitTime > 10000) dwWaitTime = 10000;

                System.Threading.Thread.Sleep(dwWaitTime);

                // Check the status again.
                Logger.Log.Info("QueryServiceStatus(hService, ssStatus) == 0");
                if (QueryServiceStatus(hService, ssStatus) == 0) break;

                if (ssStatus.dwCheckPoint > dwOldCheckPoint)
                {
                    // The service is making progress.
                    dwStartTickCount = Environment.TickCount;
                    dwOldCheckPoint = ssStatus.dwCheckPoint;
                }
                else
                {
                    if (Environment.TickCount - dwStartTickCount > ssStatus.dwWaitHint)
                    {
                        // No progress made within the wait hint
                        break;
                    }
                }
            }
            return (ssStatus.dwCurrentState == DesiredStatus);
        }

        /// <summary>
        /// Opens the service manager
        /// </summary>
        /// <param name="Rights">The service manager rights</param>
        /// <returns>the handle to the service manager</returns>
        private static IntPtr OpenServiceControlManager()
        {
            IntPtr scman = OpenSCManager();
            if (scman == IntPtr.Zero)
            {
                Console.Write("Could not connect to service control manager.");
                throw new ApplicationException("Could not connect to service control manager.");
            }
            return scman;
        }
    }
}

Step 2: Implement install,start,stop and uninstall functionality in program main method

using System;
using System.IO;
using System.Threading.Tasks;
using TeleClient.General;
using System.Threading;
using Windows.Networking.Connectivity;
using System.Linq;
using System.Xml.Linq;
using System.Xml;
using Windows.Networking.Sockets;
using Windows.Networking;
using System.Runtime.InteropServices;
using System.Security.Principal;
using Windows.Networking.NetworkOperators;
using Windows.Storage;
using Windows.Networking.BackgroundTransfer;
using System.Security.Permissions;
using Windows.Devices.Geolocation;
using System.Security.AccessControl;
using TeleClient.General.Enum;
using TelemtryClient;
using Microsoft.Win32;
using System.Text;

namespace TeleClient
{
    class Program
    {

        static string serviceName = "TeleClient";
        static AutoResetEvent evnt = new AutoResetEvent(false);
        [MTAThread]
        static void Main(string[] args)
        {
            try
            {               
                Logger.Log.Info("Application starting...");
                if (args.Length > 0)
                {
                    if (args[0] == "install")
                    {
                        Logger.Log.Info("Install service.... ");
                        //Installs and starts the service
                        ServiceInstaller.Install(serviceName, "TeleClient", @"C:\\test\\ServiceTools\\TeleClient.exe");
                        Logger.Log.Info("try to start service service");
                        StartService(args, serviceName);
                    }
                    else if (args[0] == "start")
                    {
                        Logger.Log.Info("Start service");
                        StartService(args, serviceName);
                    }
                    else if (args[0] == "stop")
                    {
                        Logger.Log.Info("Start service");
                        ServiceInstaller.StopService(serviceName);
                    }
                    else if (args[0] == "uninstall")
                    {
                        Logger.Log.Info("Start service");
                        ServiceInstaller.StopService(serviceName);
                        ServiceInstaller.Uninstall(serviceName);
                    }
                }
                else
                {
                    Logger.Log.Info("Calling service class by API");
                    ServiceBase[] ServicesToRun;
                    ServicesToRun = new ServiceBase[]
                        {
                            new ClientService()
                        };
                    ServiceBase.Run(ServicesToRun);
                }
               
                Logger.Log.Info("~: Initialized service1 constructor");
            }
            catch (Exception ex)
            {
                Logger.Log.Info("Error On main : " + ex.Message);
                Logger.Log.Info(ex.StackTrace);
                if (ex.InnerException != null)
                {
                    Logger.Log.Info("Inner Exception");
                    Logger.Log.Info(ex.InnerException.Message);
                    Logger.Log.Info(ex.InnerException.StackTrace);
                }
            }
        }


        static void StartService(string[] args, string serviceName)
        {
            Logger.Log.Info("~: Service is installed.  Attempting to start service.");
            ServiceController sc = new ServiceController();
            sc.ServiceName = serviceName;
            Logger.Log.Info("~: Check service Status.  Attempting to start service.");
            Logger.Log.Info(string.Format("Starting {0}: ", sc.ServiceName));
            try
            {
                sc.Start(args);
                sc.WaitForStatus(ServiceControllerStatus.Running);
                Logger.Log.Info("~: Service started sccuessfully");
            }
            catch (Exception ex)
            {
                Logger.Log.Info(ex.Message);
            }
        }
    }

    public partial class ClientService : ServiceBase
    {
        public ClientService ()
        {

            Logger.Log.Info("~: Client Constructor Initialized ");
            this.ServiceName = "MyServiceName";
            this.CanShutdown = true;
            this.CanStop = true;
        }

        protected override void OnStart(string[] args)
        {
            InitializeEventUploadTimer()
            Logger.Log.Info("~: Completed InitializeDirectory");
            base.OnStart(args);
        }

        #region InitializeComponent
        private void InitializeDirectory()
        {
            Logger.Log.Info("~: #######################################################################");
            Logger.Log.Info("~: ######");
            Logger.Log.Info("~: ######   STARTING: " + System.DateTime.Now.ToLongTimeString());
            Logger.Log.Info("~: ######");
            Logger.Log.Info("~: #######################################################################" + System.Environment.NewLine);

        }


        private void InitializeEventUploadTimer()
        {
            Logger.Log.Info("~: Initializing EventUploadTimer");

            int Interval;
            int.TryParse(Utility.GetAppSettings(FilePaths.ConfigFilePath, "EventElapsedTiming"), out Interval);
            Interval = Interval * 60 * 1000;
            bool set = true;
            Task.Factory.StartNew(async () =>
              {
                  while (set)
                  {
                      Logger.Log.Info(string.Format("Task delay : {0}", DateTime.Now.ToString()));
                      await Task.Delay(Interval);
                      Logger.Log.Info(string.Format("Timer Elapsed : {0}", DateTime.Now.ToString()));
                  }
              });
           

            Logger.Log.Info(string.Format("process completed : {0}", DateTime.Now.ToString()));

        }

       
        #endregion

        protected override void OnStop()
        {
            ServiceInstaller.StopService(ServiceName);
        }
    }

}

1.Installing and running Service on Windows Threshold Mobile

                                                              i.      Copy files from your desktop to device
putd <Source File Path on Dev Machine> <Destination path on Threshold Mobile Machine>
e.g. putd C:\TestSolution\Release\WindowsService.exe  C:\test\
                                                           ii.      Install windows service in your Threshold Mobile device.
cmd-device <path to service exe> '"install"'
e.g. cmd-device C:\test\WindowsService.exe '"install"'
The exe must follow appropriate code flow for handling “install” parameter
                                                         iii.      Uninstall windows service in your Threshold Mobile device.
cmd-device <path to service exe> '"uninstall"'
e.g. cmd-device C:\test\WindowsService.exe '"uninstall"'
The exe must follow appropriate code flow for handling “uninstall” parameter
                                                         iv.      Start the windows service in your Threshold Mobile device.
cmd-device <path to service exe> '"start"'
e.g. cmd-device C:\test\WindowsService.exe '"start"'
The exe must follow appropriate code flow for handling “start” parameter
                                                            v.      To list available window service using this command:
cmd-device net start
                                                         vi.      To get service status use this command
cmd-device sc query [ServiceName]
                                                       vii.      To start the service use this command:
cmd-device sc start [ServiceName]
                                                    viii.      To stop the service use this command:
cmd-device sc stop [ServiceName]
                                                          ix.      To delete the service use this command:
cmd-device sc delete [ServiceName]

2.      List of APIs available with mincore.lib

a.       The list of API’s supported by mincore.lib is available in document “MincoreLibApis.txt” available here.

b.      Alternatively you can get this by running following command on Visual Studio Developer Command Line Prompt.
dumpbin /exports c:\Program Files (x86)\Windows Kits\8.2\Lib\winv6.4\um\x86\mincore.lib

 Download full source code here

 






No comments:

Post a Comment