Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
?
Solved

C# Keep Serial Port Open After OnStart in Windows Service

Posted on 2016-09-25
2
Medium Priority
?
382 Views
Last Modified: 2016-09-25
I do not understand how to keep the Serial Port open for monitoring and recording of serial port data received after the OnStart of my Windows Service.  What am I missing or not understanding?  I thought that once I called the Open method of my Serial Port class it would stay open and just monitor.  It appears that after the OnStart the program ends even though it states running in Services window.  Below I have posted the class of my service.  Below that, I have posted my Serial Port class for completeness.

I know I have the correct port and settings because I can transmit successfully from the Windows 10 hyperterminal to the Windows Server 2012 R2 hyperterminal instance.  Of course, I close the server hyperterminal before I start my service since there are not conflicts.  Please help.  Thanks.

SERVICE PARTIAL CLASS
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;



namespace APPSecurityDoor
{
    public partial class APPSecurityDoorServ : ServiceBase
    {
        [DllImport("advapi32.dll", SetLastError = true)]
        private static extern bool SetServiceStatus(IntPtr handle, ref ServiceStatus serviceStatus);
        private SerialPortActions serialPortActions = new SerialPortActions();


        public APPSecurityDoorServ()
        {
            InitializeComponent();
            eventLog1 = new System.Diagnostics.EventLog();
            if (!System.Diagnostics.EventLog.SourceExists("APPSecurityDoorSource"))
            {
                System.Diagnostics.EventLog.CreateEventSource("APPSecurityDoorSource", "APPSecurityDoorLog");
            }
            eventLog1.Source = "APPSecurityDoorSource";
            eventLog1.Log = "APPSecurityDoorLog";
            
        }

        protected override void OnStart(string[] args)
        {
            eventLog1.WriteEntry("In OnStart");

            // Update the service state to Start Pending.
            ServiceStatus serviceStatus = new ServiceStatus();
            serviceStatus.dwCurrentState = ServiceState.SERVICE_START_PENDING;
            serviceStatus.dwWaitHint = 100000;
            SetServiceStatus(this.ServiceHandle, ref serviceStatus);

            try
            {
                
                serialPortActions.Open();
            }
            catch (Exception e)
            {
                eventLog1.WriteEntry("Service start fail. " + e, EventLogEntryType.Error, 11);
            }
            eventLog1.WriteEntry("Service start Success.", EventLogEntryType.Information, 10);

            // Update the service state to Running.
            serviceStatus.dwCurrentState = ServiceState.SERVICE_RUNNING;
            SetServiceStatus(this.ServiceHandle, ref serviceStatus);
        }

        protected override void OnStop()
        {
            eventLog1.WriteEntry("In onStop.");

            // Update the service state to Start Pending.
            ServiceStatus serviceStatus = new ServiceStatus();
            serviceStatus.dwCurrentState = ServiceState.SERVICE_STOP_PENDING;
            serviceStatus.dwWaitHint = 100000;
            SetServiceStatus(this.ServiceHandle, ref serviceStatus);

            serialPortActions.Close();

            // Update the service state to Running.
            serviceStatus.dwCurrentState = ServiceState.SERVICE_STOPPED;
            SetServiceStatus(this.ServiceHandle, ref serviceStatus);
        }
        protected override void OnContinue()
        {
            eventLog1.WriteEntry("In OnContinue.");
        }
        protected override void OnPause()
        {
            eventLog1.WriteEntry("In OnPause.");
        }
        protected override void OnShutdown()
        {
            eventLog1.WriteEntry("In OnShutdown.");
        }

        public enum ServiceState
        {
            SERVICE_STOPPED = 0x00000001,
            SERVICE_START_PENDING = 0x00000002,
            SERVICE_STOP_PENDING = 0x00000003,
            SERVICE_RUNNING = 0x00000004,
            SERVICE_CONTINUE_PENDING = 0x00000005,
            SERVICE_PAUSE_PENDING = 0x00000006,
            SERVICE_PAUSED = 0x00000007,
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct ServiceStatus
        {
            public long dwServiceType;
            public ServiceState dwCurrentState;
            public long dwControlsAccepted;
            public long dwWin32ExitCode;
            public long dwServiceSpecificExitCode;
            public long dwCheckPoint;
            public long dwWaitHint;
        };
    }
}

Open in new window


SERIAL PORT CLASS:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Ports;

namespace APPSecurityDoor
{
    /// <summary> 
    /// Interfaces with a serial port. There should only be one instance 
    /// of this class for each serial port to be used. 
    /// </summary>
    class SerialPortActions
    {
        private SerialPort _serialPort = new SerialPort();
        private int _baudRate = 4800;
        private int _dataBits = 8;
        private Handshake _handshake = Handshake.None;
        private Parity _parity = Parity.None;
        private string _portName = "COM2";
        private StopBits _stopBits = StopBits.One;

        private DBActions dbActions = new DBActions();
        private EventLog eventLog2 = new EventLog();

        /// <summary> 
        /// Holds data received until we get a terminAPPr. 
        /// </summary> 
        private string tString = string.Empty;
        /// <summary> 
        /// End of transmition byte in this case EOT (ASCII 4). 
        /// </summary> 
        private byte _terminAPPr = 0x4;

        public int BaudRate { get { return _baudRate; } set { _baudRate = value; } }
        public int DataBits { get { return _dataBits; } set { _dataBits = value; } }
        public Handshake Handshake { get { return _handshake; } set { _handshake = value; } }
        public Parity Parity { get { return _parity; } set { _parity = value; } }
        public string PortName { get { return _portName; } set { _portName = value; } }
        public bool Open()
        {
            eventLog2.Source = "APPSecurityDoorSource";
            eventLog2.Log = "APPSecurityDoorLog";
            try
            {
                _serialPort.BaudRate = _baudRate;
                _serialPort.DataBits = _dataBits;
                _serialPort.Handshake = _handshake;
                _serialPort.Parity = _parity;
                _serialPort.PortName = _portName;
                _serialPort.StopBits = _stopBits;
                _serialPort.DataReceived += new SerialDataReceivedEventHandler(_serialPort_DataReceived);
            }
            catch (Exception e)
            {
                eventLog2.WriteEntry("Fail open serial port. " + e, EventLogEntryType.Error, 201);
                return false;
            }
            eventLog2.WriteEntry("Success open serial port.", EventLogEntryType.Information, 200);
            return true;
        }

        public bool Close()
        {
            eventLog2.Source = "APPSecurityDoorSource";
            eventLog2.Log = "APPSecurityDoorLog";
            try
            {
                _serialPort.Close();
            }
            catch (Exception e)
            {
                eventLog2.WriteEntry("Fail close serial port. " + e, EventLogEntryType.Error, 211);
                return false;
            }
            eventLog2.WriteEntry("Success close serial port.", EventLogEntryType.Information, 210);
            return true;
        }

        void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            eventLog2.Source = "APPSecurityDoorSource";
            eventLog2.Log = "APPSecurityDoorLog";

            //Initialize a buffer to hold the received data 
            byte[] buffer = new byte[_serialPort.ReadBufferSize];

            //There is no accurate method for checking how many bytes are read 
            //unless you check the return from the Read method 
            int bytesRead = _serialPort.Read(buffer, 0, buffer.Length);

            //For the example assume the data we are received is ASCII data. 
            tString += Encoding.ASCII.GetString(buffer, 0, bytesRead);

            eventLog2.WriteEntry("Value: " + tString, EventLogEntryType.Information, 1);

            //Check if string contains the terminAPPr  
            if (tString.IndexOf((char)_terminAPPr) > -1)
            {
                //If tString does contain terminAPPr we cannot assume that it is the last character received 
                string workingString = tString.Substring(0, tString.IndexOf((char)_terminAPPr));
                //Remove the data up to the terminAPPr from tString 
                tString = tString.Substring(tString.IndexOf((char)_terminAPPr));
                
                //Do something with workingString 
                //////Console.WriteLine(workingString);

                eventLog2.WriteEntry("Write to " + workingString, EventLogEntryType.Information, 1000);
                dbActions.Insert(workingString);

            }
        }
    }
}

Open in new window

0
Comment
Question by:Nathan Vanderwyst
2 Comments
 
LVL 36

Accepted Solution

by:
ste5an earned 2000 total points
ID: 41814811
First of all: SerialPort implements IDisposable. Thus your class SerialPortActions must also implement the IDisposable interface. So don't use the immediate instanciation of it

 private SerialPort _serialPort = new SerialPort();

Open in new window


Then drop the EventLog.CreateEventSource call from your service. Cause this means that your service must run with administrative priveleges, which is not necessary. Create the event source in the installer. And use as fallback in your service the application log, when you don't find your log source.

The core of your problem is how a service application works. After the OnStart() the services goes to on Execute(), when this method is left, then the service ends its operations.

Thus you need to place your serial port operations into separate worker thread. Which you can start in the OnStart. Then wait in the execute method (ehe execute method is the synchronous hook for worker code). See Creating a C# Service.
0
 

Author Closing Comment

by:Nathan Vanderwyst
ID: 41815296
Thank you.
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Recently, I read that Microsoft has analysed statistics for their security intelligence report. It revealed: still, the clear majority of windows users do their daily work as administrator. An administrative account is a burden, security-wise. My ar…
Each password manager has its own problems in dealing with certain websites and their login methods. In Part 1, I review the Top 5 Password Managers that I've found to be the best. In Part 2 we'll look at which ones co-exist together and why it'…
As developers, we are not limited to the functions provided by the VBA language. In addition, we can call the functions that are part of the Windows operating system. These functions are part of the Windows API (Application Programming Interface). U…
The viewer will learn how to successfully create a multiboot device using the SARDU utility on Windows 7. Start the SARDU utility: Change the image directory to wherever you store your ISOs, this will prevent you from having 2 copies of an ISO wit…
Suggested Courses

580 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question