다음을 통해 공유


다중 스레드 서비스 개체 만들기(.NET용 POS v1.14 SDK 설명서)

이전 섹션에서는 다음을 포함하여 프로젝트를 시작하기 위한 샘플 및 가이드를 제공했습니다.

  • 간단한 템플릿 만들기
  • 서비스 객체 클래스를 구현하여 PosExplorer를 통해 포인트 오브 서비스 샘플 애플리케이션에서 컴파일하고 볼 수 있도록 합니다.
  • 스레드 도우미 클래스 구현

이 샘플에서는 이러한 모든 단계를 결합하여 다중 스레드 MSR 서비스 개체 클래스를 만듭니다. 이 샘플은 실제로 하드웨어에서 읽지 않습니다. 단순히 시스템을 통해 테스트 데이터를 푸시합니다. 그러나 서비스 개체와 관련된 코드를 추가하는 방법을 보여 줍니다.

서비스 개체에 대해 이 코드를 사용자 지정하려면

  1. PosAssembly 조직의 이름을 포함할 수 있도록 AssemblyInfo.cs 특성을 수정합니다.

  2. 네임스페이스의 이름이 조직 및 서비스 개체에 적합한지 확인합니다.

  3. ServiceObject 만들고 있는 서비스 개체의 형식, 이름, 설명 및 버전 번호를 포함하도록 특성을 수정합니다.

  4. 이 서비스 개체를 HardwareId 플러그 앤 플레이 디바이스 또는 다양한 디바이스와 연결하는 특성을 추가합니다.

  5. 서비스 개체 판독기 스레드 소개에 제공된 ThreadHelper 클래스를 포함합니다. 코드를 소스 파일에 붙여넣거나 프로젝트에서 별도의 소스 파일로 컴파일하여 이 작업을 수행할 수 있습니다. ThreadHelper 클래스가 액세스 가능한 네임스페이스에 있는지 확인합니다.

  6. 서비스 개체에서 사용하는 기본 클래스 및 지원하려는 기능에 따라 필요한 멤버를 구현합니다. 이 샘플은 기능이 거의 없는 작동하는 MSR 서비스 개체입니다.

요구 사항

이 샘플을 컴파일하려면 프로젝트에 올바른 참조 및 전역 특성이 있어야 합니다. .NET 서비스 개체에 대한 작업 POS를 아직 만들지 않은 경우 서비스 개체 샘플: 시작 섹션을 검토합니다.

또한 이전 섹션인 서비스 개체 판독기 스레드 소개의 코드를 프로젝트에 포함해야 합니다.

입증합니다

대부분의 서비스 개체는 하드웨어를 모니터링하고 다양한 들어오는 데이터 이벤트를 애플리케이션에 알리기 위해 두 번째 스레드를 사용해야 합니다. 이 샘플에서는 다중 스레드 서비스 개체를 만드는 한 가지 방법을 보여줍니다. 서비스 개체 판독기 스레드 소개에서 설명한 ServiceObjectThreadHelper 클래스를 사용하여 이 작업을 수행합니다.

도우미 클래스를 사용하려면 애플리케이션이 ServiceObjectThreadHelper 인터페이스를 구현하는 새 클래스를 정의해야 합니다. 이 인터페이스에는 다음 세 가지 메서드가 포함됩니다.

  • ServiceObjectThreadOpen 이 메서드는 스레드 초기화 중에 호출되며 하드웨어별 리소스를 초기화하는 데 사용해야 합니다.
  • ServiceObjectThreadClose 이 메서드는 스레드가 종료될 때 호출되며 하드웨어별 리소스를 해제하는 데 사용해야 합니다.
  • ServiceObjectThreadProcedure 이 메서드는 스레드가 성공적으로 시작되고 하드웨어 이벤트에서 대기하는 루프를 반복해야 하며 적절한 ManualEvent 가 트리거될 때까지 종료되지 않아야 합니다.

이 코드는 서비스 개체 샘플 만들기 항목에 제시된 샘플을 기반으로 하며 다음 기능을 추가합니다.

  • ServiceObjectThreadHelper에서 파생된 클래스를 만듭니다.
  • MsrThreadingObject 클래스의 인스턴스를 만듭니다. 이 클래스의 생성자는 서비스 개체에 대한 참조인 단일 인수를 사용합니다.
  • 서비스 개체에서 MsrThreadingObject 개체의 메서드를 호출하여 스레드 도우미를 적절하게 시작하고 중지합니다.

예시

using System;
using System.Threading;
using Microsoft.PointOfService;
using Microsoft.PointOfService.BaseServiceObjects;
using System.Text;

namespace Samples.ServiceObjects.Advanced.MSR
{
    public class MsrThreadingObject :
            ServiceObjectThreadHelper, IDisposable
    {
        // This is a helper class which will depend on
        // being able to call back into the actual Service
        // Object to pass along data. However, you cannot
        // keep a strong reference to the Service Object,
        // since that will prevent proper disposal, which
        // may create a state in which all hardware resources
        // are not properly released by the SO. Therefore,
        // create a weak reference. From this reference,
        // you can get a temporary strong reference, which
        // you act on and then release.
        WeakReference ServiceObjectReference;

        // The name of the Service Object.
        string ObjectName;

        public MsrThreadingObject(AdvancedSampleMsr so)
        {
            ObjectName = GetType().Name;
            ServiceObjectReference = new WeakReference(so);
        }

        ~MsrThreadingObject()
        {
            Dispose(true);
        }

        private bool IsDisposed = false;
        protected virtual void Dispose(bool disposing)
        {
            if (!IsDisposed)
            {
                IsDisposed = true;
                base.Dispose(disposing);
            }
        }

        public void Dispose()
        {
            Dispose(false);
        }

        #region Methods of ServiceObjectThreadHelper

        // This will be called during initialization.
        public override void ServiceObjectThreadOpen()
        {
            Logger.Info(ObjectName, "Msr Thread Open");
        }

        // This method will be called during shutdown.
        public override void ServiceObjectThreadClose()
        {
            Logger.Info(ObjectName, "Msr Thread Open");
        }

        public override void ServiceObjectThreadProcedure(
                            AutoResetEvent ThreadStopEvent)
        {
            // Convert a C# string into a sample byte array.
            UTF8Encoding encoder = new UTF8Encoding();

            // Convert sample data to a byte array.
            byte[] MsrData = encoder.GetBytes(
                        "This is MSR test data");

            Logger.Info(ObjectName, "Msr Thread Procedure Entered");

            while (true)
            {
                // When this method is called by the
                // ServiceObjectThreadHelper, it is obligated to
                // exit when the event ThreadStopEvent has been
                // set.

                // Additionally, this method will also wait for
                // hardware events or for a time-out. That should
                // be done here.

                // This example waits for the event to be set
                // or times out after several seconds.

                if (ThreadStopEvent.WaitOne(2000, false))
                {
                    break;
                }

                Logger.Info(ObjectName, "Reader Thread cycling");

                // Try to get a strong reference to the Service
                // Object using the weak reference saved when
                // this helper object was created.
                AdvancedSampleMsr msr =
                    ServiceObjectReference.Target
                    as AdvancedSampleMsr;

                // If this fails, that means the Service
                // Object has already been disposed of. Exit the
                // thread.
                if (msr == null)
                {
                    break;
                }

                // Using the strong reference, you can now make
                // calls back into the Service Object.
                msr.OnCardSwipe(MsrData);
                msr = null;
            }
            #endregion Methods of ServiceObjectThreadHelper
        }

        // Implementation of the Service Object class. This class
        // implements all the methods needed for an MSR Service
        // Object.
        //
        // A Service Object which supports a Plug and Play device
        // should also have a HardwareId attribute here.

        [HardwareId(
                @"HID\Vid_05e0&Pid_038a",
                @"HID\Vid_05e0&Pid_038a")]

        [ServiceObject(
                DeviceType.Msr,
                "AdvancedSampleMsr",
                "Advanced Sample Msr Service Object",
                1,
                9)]
        public class AdvancedSampleMsr : MsrBase
        {
            // String returned for various health checks.
            private string MyHealthText;
            private const string PollingStatistic =
                            "Polling Interval";

            // Create a class with interface methods called from the
            // threading object.
            MsrThreadingObject ReadThread;
            public AdvancedSampleMsr()
            {
                // DevicePath must be set before Open() is called.
                // In the case of Plug and Play hardware, the POS
                // for .NET Base class will set this value.
                DevicePath = "Sample Msr";

                Properties.CapIso = true;
                Properties.CapTransmitSentinels = true;

                Properties.DeviceDescription =
                            "Advanced Sample Msr";

                // Initialize the string to be returned from
                // CheckHealthText().
                MyHealthText = "";
            }

            ~AdvancedSampleMsr()
            {
                // Code added from previous sections to terminate
                // the read thread started by the thread-helper
                // object.
                ReadThread.CloseThread();

                Dispose(false);
            }

            protected override void Dispose(bool disposing)
            {
                try
                {
                    if (disposing)
                    {
                        if (ReadThread != null)
                        {
                            ReadThread.Dispose();
                            ReadThread = null;
                        }
                    }
                }
                finally
                {
                    // Must call base class Dispose.
                    base.Dispose(disposing);
                }
            }

            #region Internal Members
            // This is a private method called from the task
            // interface when a data event occurs in the reader
            // thread.
            internal void OnCardSwipe(byte[] CardData)
            {
                // Simple sample data.
                UTF8Encoding utf8 = new UTF8Encoding();
                byte[] track1Data = utf8.GetBytes(
                                "this is test track 1");
                byte[] track2Data = utf8.GetBytes(
                                "this is test track 2");

                // Call GoodRead(), UnreadableCard, or FailedRead
                // from here.
                GoodRead(
                        track1Data,
                        track2Data,
                        null,
                        null,
                        Microsoft.PointOfService.BaseServiceObjects.CardType.Iso);
            }
            #endregion Internal Members

            #region PosCommon overrides
            //  PosCommon.Open.
            public override void Open()
            {
                // Call base class Open.
                base.Open();

                // Initialize statistic values.

                // Set values for common statistics.
                SetStatisticValue(StatisticManufacturerName,
                                "Microsoft Corporation");
                SetStatisticValue(
                            StatisticManufactureDate, "2004-10-23");
                SetStatisticValue(
                            StatisticModelName, "Msr Simulator");
                SetStatisticValue(
                            StatisticMechanicalRevision, "1.0");
                SetStatisticValue(
                            StatisticInterface, "USB");

                // Create a new manufacturer statistic.
                CreateStatistic(
                            PollingStatistic,
                            false,
                            "milliseconds");

                // Set handlers for statistics stored in hardware.
                // Create a class with interface methods called
                // from the threading object.
                ReadThread = new MsrThreadingObject(this);
            }

            // PosCommon.CheckHealthText.
            public override string CheckHealthText
            {
                get
                {
                    // MsrBasic.VerifyState(mustBeClaimed,
                    // mustBeEnabled).
                    VerifyState(false, false);
                    return MyHealthText;
                }
            }

            //  PosCommon.CheckHealth.
            public override string CheckHealth(
                            HealthCheckLevel
                            level)
            {
                // Verify that device is open, claimed, and enabled.
                VerifyState(true, true);

                // Your code here checks the health of the device and
                // returns a descriptive string.

                // Cache result in the CheckHealthText property.
                MyHealthText = "Ok";
                return MyHealthText;
            }

            //  PosCommon.DirectIO.
            public override DirectIOData DirectIO(
                                int command,
                                int data,
                                object obj)
            {
                return new DirectIOData(data, obj);
            }

            public override bool DeviceEnabled
            {
                get
                {
                    return base.DeviceEnabled;
                }
                set
                {
                    if (value != base.DeviceEnabled)
                    {
                        base.DeviceEnabled = value;

                        if (value == false)
                        {
                            // Stop the reader thread when the
                            // device is disabled.
                            ReadThread.CloseThread();
                        }
                        else
                        {
                            try
                            {
                                // Enabling the device, start the
                                // reader thread.
                                ReadThread.OpenThread();
                            }
                            catch (Exception e)
                            {
                                base.DeviceEnabled = false;

                                if (e is PosControlException)
                                    throw;

                                throw new PosControlException(
                                        "Unable to Enable Device",
                                        ErrorCode.Failure, e);
                            }
                        }
                    }
                }
            }
            #endregion PosCommon overrides.

            #region MsrBasic Overrides

            // MsrBasic.MsrFieldData
            // Once the track data is retrieved, this method is
            // called when the application accesses various data
            // properties in the MsrBasic class. For example,
            // FirstName and AccountNumber.
            protected override MsrFieldData ParseMsrFieldData(
                                    byte[] track1Data,
                                    byte[] track2Data,
                                    byte[] track3Data,
                                    byte[] track4Data,
                                    CardType cardType)
            {
                // MsrFieldData contains the data elements that
                // MsrBasic will return as properties to the
                // application, as they are requested.
                MsrFieldData data = new MsrFieldData();

                // Parse the raw track data and store in fields to
                // be used by the app.
                data.FirstName = "FirstName";
                data.Surname = "LastName";
                data.Title = "Mr.";
                data.AccountNumber = "123412341234";

                return data;
            }

            // MsrBasic.MsrTrackData.
            protected override MsrTrackData ParseMsrTrackData(
                                    byte[] track1Data,
                                    byte[] track2Data,
                                    byte[] track3Data,
                                    byte[] track4Data,
                                    CardType cardType)
            {
                MsrTrackData data = new MsrTrackData();

                // Modify the track data as appropriate for your SO.
                // Remove the sentinel characters from the track data,
                // for example.
                data.Track1Data = (byte[])track1Data.Clone();
                data.Track2Data = (byte[])track2Data.Clone();

                return data;
            }
            #endregion MsrBasic overrides
        }
    }
}

또한 참조하십시오

업무

기타 리소스