The Life and Times of a Dev

Yes, we're really that weird
posts - 187 , comments - 328 , trackbacks - 106

My Links

News

Twitter












Tag Cloud

Archives

Post Categories

Play

Work

Reading Credit Card Data from a MagTek Card Swipe Device

Sometimes as developers we’re spoiled by third parties that do a lot of the heavy lifting for us.  However, sometimes we’re NOT spoiled and we have to get our hands dirty.

Today, I spent much of the day getting my hands dirty.  I’m working on a project that uses a MagTek credit card swiper and all MagTek provides you in terms of dlls is a c++ dll and an ActiveX dll.  What fun is that?  I wanted to avoid com interop (no, I don’t have a good reason) and write a C# class that handled talking with their C++ dlls directly.

This ended up being a good lesson in P/Invoke and how to deal with unsafe (I’m guessing strcat) code in a dll that I don’t control.

1207 lines of code (and comments) later, I have the final result completed.  I’m not going to post the entire post, since it would be WAY to long, but here are the key bits:

Here’s the dll imports you’ll need:

/// <summary>
///   Clears the data buffer
/// </summary>
[DllImport("MTUSCRA.dll")]
private static extern void MTUSCRAClearBuffer();

/// <summary>
///   Opens the MTUSCRA Device
/// </summary>
/// <returns> A uint that is an <see cref="ErrorValuesEnum" /> </returns>
[DllImport("MTUSCRA.dll")]
private static extern uint MTUSCRACloseDevice();

/// <summary>Gets the card data from the reader.</summary>
/// <param name="cardData">The card data structure for holding the card information. </param>
/// <returns>A uint that is an <see cref="ErrorValuesEnum"/> </returns>
[DllImport("MTUSCRA.dll")]
private static extern uint MTUSCRAGetCardData(ref MTMSRDATA cardData);

//// This has been removed because it requires unsafe code.
/////// <summary>Gets the card data delimited by the provided string.</summary>
/////// <param name="data">The string result that will be sent back. </param>
/////// <param name="delimiter">The delimiter for the string </param>
/////// <returns>A uint that is an <see cref="ErrorValuesEnum"/> </returns>
////[DllImport("MTUSCRA.dll")]
////private static extern unsafe uint MTUSCRAGetCardDataStr(byte* data, string delimiter);

/// <summary>Opens the MTUSCRA Device</summary>
/// <param name="deviceName">The name of the device to open </param>
/// <returns>A uint that is an <see cref="ErrorValuesEnum"/> </returns>
[DllImport("MTUSCRA.dll")]
private static extern uint MTUSCRAOpenDevice(string deviceName);

/// <summary>Opens the MTUSCRA Device</summary>
/// <param name="command">The command to send </param>
/// <param name="commandLength">The length of the command sent. </param>
/// <param name="result">The result of the command </param>
/// <param name="resultLength">The length of the result. </param>
/// <returns>A uint that is an <see cref="ErrorValuesEnum"/> </returns>
[DllImport("MTUSCRA.dll")]
private static extern uint MTUSCRASendCommand(string command, uint commandLength, ref string result, ref uint resultLength);

/// <summary>
/// Raised when the card state data changes.
/// </summary>
/// <param name="callBack">The call back for card data state changing.</param>
[DllImport("MTUSCRA.dll")]
private static extern void MTUSCRACardDataStateChangedNotify(CardDataStateChangedCallBack callBack);

/// <summary>
/// Raised when the device state changes
/// </summary>
/// <param name="callBack">The call back for card data state changing.</param>
[DllImport("MTUSCRA.dll")]
private static extern void MTUSCRADeviceStateChangedNotify(DeviceStateChangedCallBack callBack);

/// <summary>
/// Gets the current device state.
/// </summary>
/// <param name="deviceState">The device state</param>
[DllImport("MTUSCRA.dll")]
private static extern void MTUSCRAGetDeviceState(ref uint deviceState);

/// <summary>
/// Gets the current data state.
/// </summary>
/// <param name="dataState">The data state</param>
[DllImport("MTUSCRA.dll")]
private static extern void MTUSCRAGetCardDataState(ref uint dataState);

/// <summary>
/// Gets the cproduct id of the card reader.
/// </summary>
/// <param name="productId">The product id</param>
[DllImport("MTUSCRA.dll")]
private static extern void MTUSCRAGetPID(ref uint productId);

You’ll need a couple of delegates as well:

/// <summary>
///   A delegate for handling the card data state callback.
/// </summary>
/// <param name="dataState"> The data state </param>
private delegate void CardDataStateChangedCallBack(uint dataState);

/// <summary>
///   A delegate for handling the device state callback.
/// </summary>
/// <param name="deviceState"> The device state </param>
private delegate void DeviceStateChangedCallBack(uint deviceState);

And then you’ll want to wire those up like so:

 

this.CardDataStateChanged = new CardDataStateChangedCallBack(this.OnCardDataStateChanged);
this.DeviceStateChanged = new DeviceStateChangedCallBack(this.OnDeviceStateChanged);

MTUSCRACardDataStateChangedNotify(this.CardDataStateChanged);
MTUSCRADeviceStateChangedNotify(this.DeviceStateChanged);

And finally, you’ll want the Struct that you’ll need to use to get the card data:

[StructLayout(LayoutKind.Sequential)]
public struct MTMSRDATA
{
    /// <summary>The default data size for tracks.</summary>
    private const int DEF_MSR_DATA_LEN = 256;

    /// <summary>The card data.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN * 3)]
    public string m_szCardData;

    /// <summary>masked card data.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN * 3)]
    public string m_szCardDataMasked;

    /// <summary>Track 1 Data.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN)]
    public string m_szTrack1Data;

    /// <summary>Track 2 data.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN)]
    public string m_szTrack2Data;

    /// <summary>Track 3 data.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN)]
    public string m_szTrack3Data;

    /// <summary>Masked track 1 data.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN)]
    public string m_szTrack1DataMasked;

    /// <summary>masked track 2 data.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN)]
    public string m_szTrack2DataMasked;

    /// <summary>masked track 3 data.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN)]
    public string m_szTrack3DataMasked;

    /// <summary>MagnePrint data.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN)]
    public string m_szMagnePrintData;

    /// <summary>Card encode type.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN)]
    public string m_szCardEncodeType;

    /// <summary>MagnePrint Status.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN)]
    public string m_szMagnePrintStatus;

    /// <summary>DUKPT Session ID.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN)]
    public string m_szDUKPTSessionID;

    /// <summary>Device Serial Number.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN)]
    public string m_szDeviceSerialNumber;

    /// <summary>DUKPT Key Serial Number.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN)]
    public string m_szDUKPTKSN;

    /// <summary>First Name from Track 1.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN)]
    public string m_szFirstName;

    /// <summary>Last Name from Track 1.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN)]
    public string m_szLastName;

    /// <summary>PAN from Track 2.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN)]
    public string m_szPAN;

    /// <summary>The Expiration Month.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN)]
    public string m_szMonth;

    /// <summary>The Expiration Year.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN)]
    public string m_szYear;

    /// <summary>Reader product ID.</summary>
    public uint m_dwReaderID;

    /// <summary>MagnePrint length.</summary>
    public uint m_dwMagnePrintLength;

    /// <summary>MagnePrint Status.</summary>
    public uint m_dwMagnePrintStatus;

    /// <summary>Track 1 data length.</summary>
    public uint m_dwTrack1Length;

    /// <summary>Track 2 length.</summary>
    public uint m_dwTrack2Length;

    /// <summary>Track 3 length.</summary>
    public uint m_dwTrack3Length;

    /// <summary>Track 1 length masked.</summary>
    public uint m_dwTrack1LengthMasked;

    /// <summary>Track 2 length masked.</summary>
    public uint m_dwTrack2LengthMasked;

    /// <summary>Track 3 length masked.</summary>
    public uint m_dwTrack3LengthMasked;

    /// <summary>Card encode type.</summary>
    public uint m_dwCardEncodeType;

    /// <summary>Track 1 decode status.</summary>
    public uint m_dwTrack1DcdStatus;

    /// <summary>Track 2 decode status.</summary>
    public uint m_dwTrack2DcdStatus;

    /// <summary>The m_dw track 3 dcd status.</summary>
    public uint m_dwTrack3DcdStatus;

    /// <summary>Card swipe status.</summary>
    public uint m_dwCardSwipeStatus;
}

Hopefully, this will help you get started and will save you some time.  I know it would have saved me quite a bit!

Good luck!

Technorati Tags: ,,

Print | posted on Wednesday, July 11, 2012 5:25 PM |

Feedback

Gravatar

# re: Reading Credit Card Data from a MagTek Card Swipe Device

Thank you very much for this code, you saved me a ton of time. We have been getting killed by the ActiveX control that keeps doing this
http://stackoverflow.com/questions/2878525/getting-reportavoncomrelease-exception-when-using-3rd-party-com
to us.
4/11/2013 10:45 AM | Darrel Miller
Gravatar

# re: Reading Credit Card Data from a MagTek Card Swipe Device

Hi,

Can you please share the source code of this article? i really need this badly and it would be great if you can help me by sharing the source code.

Thanks,

Mrunal
4/25/2013 6:44 AM | Mrunal
Post A Comment
Title:
Name:
Email:
Website:
Comment:
Verification:
 
 

Powered by: