Capture Helper

Capture Helper is the easiest and recommended way for adding the barcode scanning capabilities to a C# application.

Capture Helper Initialization

To use Capture Helper, first create an instance of Capture Helper and register for the events your application requires and open Capture Helper. If opening Capture Helper returns an error such as SktErrors.ESKT_UNABLEOPENDEVICE (-27), it might be because the Socket Mobile Companion software is not installed or not running.

Here is a typical Capture Helper initialization:

public Form1()
{
    InitializeComponent();

    // initialize CaptureHelper
    capture = new CaptureHelper()
    {
        // make the events running in UI Thread context
        // Note this MUST be done on the UI thread.  If not,
        // UI updates from CaptureHelper will not occur
        // Setting this is optional.
        ContextForEvents = SynchronizationContext.Current;
    };

    // register for the Capture Helper events
    capture.DeviceArrival += CaptureDeviceArrival;
    capture.DeviceRemoval += CaptureDeviceRemoval;
    capture.DeviceOwnershipChange += CaptureDeviceOwnershipChange;
    capture.DecodedData += CaptureDecodedData;
    capture.Errors += CaptureErrors;
    capture.DevicePowerState += DevicePowerState;
    capture.Terminate += Terminate;

    ...
}

Note

The line capture.ContextForEvents = SynchronizationContext.Current; allows your application to handle the Capture Helper events directly in the User Interface (UI) Thread context so the UI can be directly updated. Setting ContextForEvents is optional, if none of the event handlers updates the UI then this line can be removed. CaptureHelper.ContextForEvents can ONLY be set on the UI thread. CaptureHelper.ContextForEvents is a public member, so it can be set at any time.

In the OnFormOpening override method of the form object proceed to open the communication between this application and Socket Mobile Companion software as shown below:

protected async override void OnFormOpening(FormOpeningEventArgs e)
{
    base.OnFormOpening(e);
    string appId = "windows:com.mycompany.myapp";
    string developerId = "520CE559-D74D-4447-9E65-0E35512A0344";
    string appKey = "MC3CFQD76T2AE/Jus4JJ6nxZJyub3WBxXgIVAKglTx239tKjR+LNspa46Y9io2w5";

    long result = await capture.OpenAsync(appId, developerId, appKey);

    if (!SktErrors.SKTSUCCESS(result))
    {
        labelCaptureVersion.Text = "Unable to connect to Socket Mobile Companion";
        DialogResult dialogResult = MessageBox.Show(
            "Unable to open Capture, is Socket Mobile Companion Service running?",
            "Error",
            MessageBoxButtons.OK,
            MessageBoxIcon.Warning);
    }
}

From that moment on, if a Socket Cordless Scanner connects to the host, the application CaptureDeviceArrival handler is invoked, and when the user then scans a barcode the CaptureDecodedData is invoked with the decoded data.

Minimal implementation

Assuming the only thing that matters to the application is to receive the decoded data, a minimal implementation could be as simple as:

public Form1()
{
    InitializeComponent();
    // initialize CaptureHelper
    capture = new CaptureHelper();
    capture.ContextForEvents = WindowsFormsSynchronizationContext.Current;
    capture.DecodedData += CaptureDecodedData;

    string appId = "windows:com.mycompany.myapp";
    string developerId = "520CE559-D74D-4447-9E65-0E35512A0344";
    string appKey = "MC3CFQD76T2AE/Jus4JJ6nxZJyub3WBxXgIVAKglTx239tKjR+LNspa46Y9io2w5";

    long result = await capture.OpenAsync(appId, developerId, appKey);

    if (!SktErrors.SKTSUCCESS(result)) {
        labelCaptureVersion.Text = "Unable to connect to Socket Mobile Companion";
    }
}

async void CaptureDecodedData(object sender, CaptureHelper.DecodedDataArgs e)
{
    textBoxDecodedData.Text = e.DecodedData.DataToUTF8String;
}

Of course this sample won’t help the user if for some reason the scanner is not connected to the host, or if there is an error occurring while using Capture. For these reasons we highly recommend to track the device presence, to handle the error event and to collect the Capture version.

Note

The line capture.ContextForEvents = WindowsFormsSynchronizationContext.Current; allows the application to handle the Capture Helper events directly in the UI Thread context so the UI can be directly updated. If none of the event handlers updates the UI then this line can be removed.

Device connection awareness

This is a great way to confirm if the scanner is correctly connected to the application or even to drive the UI when the scanner connects or scans. Capture Helper automatically opens the device as soon as it receives its connection notification. Once the device is open, Capture Helper fires the device arrival event with a CaptureHelperDevice instance to represent this particular device. That CaptureHelperDevice instance is used at each event related to the device, and can be used to retrieve or configure the device settings.

For an application to be aware of Device connections, there are 2 events that can be monitored: DeviceArrival and DeviceRemoval. Here is sample code on how to register for these events along with the DecodedData event. The devices are added into a ListBox in this particular case:

public Form1()
{
  InitializeComponent();
  // initialize CaptureHelper
  capture = new CaptureHelper();

  capture.ContextForEvents = WindowsFormsSynchronizationContext.Current;
  capture.DeviceArrival += CaptureDeviceArrival;
  capture.DeviceRemoval += CaptureDeviceRemoval;
  capture.DecodedData += CaptureDecodedData;

  labelStatus.Text = "no scanner connected";

  string appId = "windows:com.mycompany.myapp";
  string developerId = "520CE559-D74D-4447-9E65-0E35512A0344";
  string appKey = "MC3CFQD76T2AE/Jus4JJ6nxZJyub3WBxXgIVAKglTx239tKjR+LNspa46Y9io2w5";

  long result = await capture.OpenAsync(appId, developerId, appKey);

  if (!SktErrors.SKTSUCCESS(result)) {
      labelCaptureVersion.Text = "Unable to connect to Socket Mobile Companion (" + result + ")";
  }

}

void CaptureDeviceRemoval(object sender, CaptureHelper.DeviceArgs e)
{
    RemoveDeviceFromListBox(listBoxDevices, e.CaptureDevice);
}

void CaptureDeviceArrival(object sender, CaptureHelper.DeviceArgs e)
{
    AddDeviceIntoListBox(listBoxDevices, e.CaptureDevice);
    labelStatus.Text = e.CaptureDevice.GetDeviceInfo().Name;
}

async void CaptureDecodedData(object sender, CaptureHelper.DecodedDataArgs e)
{
    textBoxDecodedData.Text = e.DecodedData.DataToUTF8String;
}

Note

The line capture.ContextForEvents = WindowsFormsSynchronizationContext.Current; allows the application to handle the Capture Helper events directly in the UI Thread context the UI can be directly updated. If none of the event handlers updates the UI then this line can be removed.

Adding features to Capture Helper

Capture Helper is implemented as partial class. If your application needs a feature that is not implemented in Capture Helper, that feature can be added by creating a CaptureHelper partial class, copy-pasting a similar feature from the provided CaptureHelper, and modifying it to match your application needs.

Capture Helper with Debug Traces

If the application is compiled in Debug mode it is possible to activate the traces from Capture Helper. The application should pass a Capture Debug Console object that implements the unique method void PrintLine(string message). Here is sample code showing the details of this feature by first creating a DebugConsole class (or whatever other name you pick) derived from CaptureHelperDebug as shown here:

#if DEBUG
    class DebugConsole : CaptureHelperDebug
    {

        public void PrintLine(string message)
        {
            Debug.WriteLine(message);
        }
    }
#endif

Then after creating the Capture Helper instance this DebugConsole instance is passed to the Capture Helper instance as shown here:

public Form1()
{
    InitializeComponent();
    // initialize CaptureHelper
    capture = new CaptureHelper();
#if DEBUG
    capture.DebugConsole = new DebugConsole();
#endif
    capture.ContextForEvents = WindowsFormsSynchronizationContext.Current;
    capture.DeviceArrival += CaptureDeviceArrival;
    capture.DeviceRemoval += CaptureDeviceRemoval;
    capture.DeviceOwnershipChange += CaptureDeviceOwnershipChange;
    capture.DecodedData += CaptureDecodedData;
    capture.Errors += CaptureErrors;
    capture.DevicePowerState += DevicePowerState;
    capture.Terminate += Terminate;
    ...

SetLocalAcknowledgmentAsync

CaptureHelperDevice exposes two overloads of SetLocalAcknowledgmentAsync that target different device generations. Both set the ICaptureProperty.PropId.kLocalAcknowledgmentDevice property.

Signature

Target devices

Behaviour

SetLocalAcknowledgmentAsync(byte timeoutSeconds)

Bluetooth Low Energy devices with Echo protocol

Passes the value directly as the property byte. A value of 0 means the device acknowledges decoded data as soon as it is decoded. Any other value sets a timeout in seconds; the trigger remains locked until the host acknowledges or the timeout elapses.

SetLocalAcknowledgmentAsync(bool enable) (deprecated)

Classic Bluetooth scanners

Converts the boolean to the corresponding ICaptureProperty.Values.DeviceDataAcknowledgment constant: kOn (1) when true, kOff (0) when false.

Use GetLocalAcknowledgmentAsync() to read back the current setting. It returns a LocalAcknowledgmentResult with an Enabled boolean that is true when the device byte equals DeviceDataAcknowledgment.kOn.

Note

The bool overload is marked [Obsolete] and is kept for backward compatibility with classic Bluetooth scanners. Use the byte overload for Bluetooth Low Energy devices with Echo protocol.

SetDecodeActionAsync / GetDecodeActionAsync

CaptureHelperDevice exposes two generations of decode action methods, targeting different device types.

Set

Signature

Target devices

Behaviour

SetDecodeActionAsync(byte mask, byte led, byte beep, byte rumble)

Bluetooth Low Energy devices with ECHO protocol

Packs the four values into a single byte and sends it to the device. mask selects which decode result the action applies to (DecodeLocalActionSelectionMask.kGood or kBad). led, beep and rumble use the DataConfirmationLed, DataConfirmationBeep and DataConfirmationRumble constants respectively.

SetDecodeActionAsync(bool beep, bool flash, bool rumble) (deprecated)

Classic Bluetooth scanners

Enables or disables beep, LED flash and rumble independently using boolean flags.

Get

Signature

Target devices

Behaviour

GetGoodDecodeActionAsync()

Bluetooth Low Energy devices with ECHO protocol

Returns a GoodDecodeActionResult with three byte fields covering LED, beep and rumble for a good decode, using the DataConfirmationLed, DataConfirmationBeep and DataConfirmationRumble constants.

GetDecodeActionAsync() (deprecated)

Classic Bluetooth scanners

Returns a DecodeActionResult with three boolean fields (Beep, Flash, Rumble).

Note

The deprecated overloads are marked [Obsolete] and are kept for backward compatibility with classic Bluetooth scanners. Use the ECHO protocol variants for Bluetooth Low Energy devices.