前のセクションでは、次のようなプロジェクトを開始するためのサンプルとガイドを提供しました。
- 単純なテンプレートの作成。
- PosExplorerを介して Point Of Service サンプル アプリケーションによってコンパイルおよび表示できるサービス オブジェクト クラスの実装。
- スレッド ヘルパー クラスの実装。
このサンプルでは、これらすべての手順を組み合わせて、動作するマルチスレッド MSR サービス オブジェクト クラスを作成します。 このサンプルは、実際にはどのハードウェアからも読み取りません。 システムを介してテスト データをプッシュするだけです。 ただし、サービス オブジェクトに固有のコードを追加する方法を示します。
サービス オブジェクトのこのコードをカスタマイズするには
組織の名前が含まれるように、AssemblyInfo.csの
PosAssembly属性を変更します。名前空間の名前が組織とサービス オブジェクトに適していることを確認します。
ServiceObject属性を変更して、作成するサービス オブジェクトの種類、名前、説明、バージョン番号を含めます。HardwareId属性を追加して、このサービス オブジェクトをプラグ アンド プレイ デバイスまたはデバイスの範囲に関連付けます。サービス オブジェクト リーダー スレッドの概要に示されている ThreadHelper クラスを含めます。 これを行うには、コードをソース ファイルに貼り付けるか、プロジェクト内の別のソース ファイルとしてコンパイルします。 ThreadHelper クラスがアクセス可能な名前空間にあることを確認します。
サービス オブジェクトで使用される 基本 クラスとサポートする機能に応じて、必要なメンバーを実装します。 このサンプルは、限定的な機能を持つ動作中の MSR サービスオブジェクトです。
Requirements
このサンプルをコンパイルするには、プロジェクトに正しい参照とグローバル属性が必要です。 .NET サービス オブジェクト用の動作する POS をまだ作成していない場合は、「 サービス オブジェクトのサンプル: 作業の開始 」セクションを確認してください。
さらに、前のセクション「 サービス オブジェクト リーダー スレッドの概要」のコードをプロジェクトに含める必要もあります。
対象
ほとんどのサービス オブジェクトでは、2 番目のスレッドを使用してハードウェアを監視し、さまざまな受信データ イベントをアプリケーションに通知する必要があります。 このサンプルでは、マルチスレッド サービス オブジェクトを作成する 1 つの方法を示します。 これを行うには、「サービス オブジェクト リーダー スレッドの概要」で説明されている ServiceObjectThreadHelper クラスに依存します。
ヘルパー クラスを使用するには、アプリケーションで ServiceObjectThreadHelper インターフェイスを実装する新しいクラスを定義する必要があります。 このインターフェイスには、次の 3 つのメソッドが含まれています。
- ServiceObjectThreadOpen このメソッドはスレッドの初期化中に呼び出され、ハードウェア固有のリソースを初期化するために使用する必要があります。
- ServiceObjectThreadClose このメソッドは、スレッドが終了したときに呼び出され、ハードウェア固有のリソースを解放するために使用する必要があります。
- ServiceObjectThreadProcedure このメソッドは、スレッドが正常に開始されると呼び出され、ハードウェア イベントの待機をループする必要があり、適切な ManualEvent がトリガーされるまで終了しないでください。
このコードは、「サービス オブジェクト サンプルの作成」で説明されている サンプルに 基づいており、次の機能を追加します。
- ServiceObjectThreadHelper から派生したクラスを作成します。
- MsrThreadingObject クラスのインスタンスを作成します。 このクラスのコンストラクターは、サービス オブジェクトへの参照である 1 つの引数を受け取ります。
- 必要に応じて、サービス オブジェクトから MsrThreadingObject オブジェクトのメソッドを呼び出して、スレッド ヘルパーを開始および停止します。
Example
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
}
}
}
こちらもご覧ください
タスク
その他のリソース
.NET