over 5 years ago

最近遇上一個開發需求,是3M的護照掃描機,如果是做成Application 大概一天內就能夠搞定

但是客人堅持要在Web上作業,所以就我所知道的技術範圍也只有ActiveX Object 但是這個應用也只有IE

所以告知客人這樣只能用IE,沒想到客人竟然欣然接受

好吧,以客為尊,所以整理和蒐集一下相關的資訊,首先必須說明一下,我參考了朱大的文章,開發了ActiveX 段的程式

建議先參考朱大的精美說明 小朱® 的技術隨手寫

首先我把3M所提供的SDK中的範例找出來使用,但沒想到竟然是.NET Framework 2.0,且直接開啟專案還有錯誤引用的問題

所以修正一下之後,讓應用程式的部分可以直接運作,而且由於我使用Visual Studio 2013 開發,一直有.Net Framework版本的錯誤訊息,所以幾經考慮之後,選擇使用visual Stuio 2010來開發

首先我試著讓程式能夠運作

i.找到下載的檔案找尋目錄
C:\Program Files (x86)\3M\3M Swipe Reader\1.0.12\SDK\Samples\DotNET\SwipeReaderMessages.NET
底下有一個可以使用的專案檔,選擇開啟這個專案檔(我建議是將這個檔案搬移至你要開發的目錄位置)

ii.開啟專案後,會發現三角的驚嘆號,錯誤引用(沒發生請跳過,試著執行專案)
刪掉MMMReaderDotNet20.dll的參考,重新參考檔案,並且找到剛剛下載的檔案,把/Bin 與 /Config (C:\Program Files (x86)\3M\3M Swipe Reader\1.0.12\Bin)資料夾搬移至與目前開發專案的資料夾同層目錄,以利程式運作


iii.試著執行應用程式,查看是否可以運作並取得資料

注意: 你需要先安裝的Driver ,可以在剛剛下載的檔案中(C:\Program Files (x86)\3M\3M Swipe Reader\1.0.12\Drivers)中找到,否則會出現找不到COM的錯誤訊息

第一階段我的程式與架構

Main.cs
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Text;

namespace SwipeReaderMessages.NET
{
    /// <summary>
    /// Summary description for Form1.
    /// </summary>
    public class MainForm : System.Windows.Forms.Form
    {
        
        enum RowType
        {
            Data,
            Event,
            Error,
            Command,
            CommandResponse
        }
    
        private MMM.Readers.Modules.Swipe.SwipeSettings swipeSettings;
        
        // Helper control to get around .NET 2.0 threadsafe control problem
        private Control _threadHelperControl;
    
        private System.Windows.Forms.ListView listViewMessages;
        private System.Windows.Forms.ColumnHeader columnMessageId;
        private System.Windows.Forms.ColumnHeader columnMessageName;
        private System.Windows.Forms.ColumnHeader columnSize;
        private System.Windows.Forms.ColumnHeader columnData;
        private System.Windows.Forms.Button buttonClearList;
        private System.Windows.Forms.Label labelHardwareProto;
        private System.Windows.Forms.Timer timerInit;
        private System.ComponentModel.IContainer components;

        public MainForm()
        {
            //
            // Required for Windows Form Designer support
            //
            InitializeComponent();

            // Initialize helper control to get around .NET 2.0 threadsafe control problem
            _threadHelperControl = new Control();
            _threadHelperControl.CreateControl();
            
            //
            // TODO: Add any constructor code after InitializeComponent call
            //
        }       

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing )
        {
            if( disposing )
            {
                if (components != null) 
                {
                    components.Dispose();
                }
            }
            base.Dispose( disposing );
        }

        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.listViewMessages = new System.Windows.Forms.ListView();
            this.columnMessageId = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
            this.columnMessageName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
            this.columnSize = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
            this.columnData = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
            this.buttonClearList = new System.Windows.Forms.Button();
            this.labelHardwareProto = new System.Windows.Forms.Label();
            this.timerInit = new System.Windows.Forms.Timer(this.components);
            this.SuspendLayout();
            // 
            // listViewMessages
            // 
            this.listViewMessages.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
            | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
            this.listViewMessages.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
            this.columnMessageId,
            this.columnMessageName,
            this.columnSize,
            this.columnData});
            this.listViewMessages.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.listViewMessages.FullRowSelect = true;
            this.listViewMessages.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable;
            this.listViewMessages.Location = new System.Drawing.Point(8, 9);
            this.listViewMessages.MultiSelect = false;
            this.listViewMessages.Name = "listViewMessages";
            this.listViewMessages.Size = new System.Drawing.Size(728, 440);
            this.listViewMessages.TabIndex = 0;
            this.listViewMessages.UseCompatibleStateImageBehavior = false;
            this.listViewMessages.View = System.Windows.Forms.View.Details;
            // 
            // columnMessageId
            // 
            this.columnMessageId.Text = "ID";
            // 
            // columnMessageName
            // 
            this.columnMessageName.Text = "Name";
            this.columnMessageName.Width = 160;
            // 
            // columnSize
            // 
            this.columnSize.Text = "Size";
            this.columnSize.Width = 80;
            // 
            // columnData
            // 
            this.columnData.Text = "Data";
            this.columnData.Width = 400;
            // 
            // buttonClearList
            // 
            this.buttonClearList.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
            this.buttonClearList.Location = new System.Drawing.Point(664, 468);
            this.buttonClearList.Name = "buttonClearList";
            this.buttonClearList.Size = new System.Drawing.Size(75, 26);
            this.buttonClearList.TabIndex = 1;
            this.buttonClearList.Text = "Clear List";
            this.buttonClearList.Click += new System.EventHandler(this.buttonClearList_Click);
            // 
            // labelHardwareProto
            // 
            this.labelHardwareProto.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
            this.labelHardwareProto.Location = new System.Drawing.Point(8, 468);
            this.labelHardwareProto.Name = "labelHardwareProto";
            this.labelHardwareProto.Size = new System.Drawing.Size(648, 26);
            this.labelHardwareProto.TabIndex = 2;
            // 
            // timerInit
            // 
            this.timerInit.Interval = 1;
            this.timerInit.Tick += new System.EventHandler(this.timerInit_Tick);
            // 
            // MainForm
            // 
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 15);
            this.ClientSize = new System.Drawing.Size(744, 502);
            this.Controls.Add(this.labelHardwareProto);
            this.Controls.Add(this.buttonClearList);
            this.Controls.Add(this.listViewMessages);
            this.Name = "MainForm";
            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
            this.Text = "Swipe Reader Messages .NET";
            this.Closed += new System.EventHandler(this.MainForm_Closed);
            this.Load += new System.EventHandler(this.MainForm_Load);
            this.ResumeLayout(false);

        }
        #endregion

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main() 
        {
            Application.Run(new MainForm());
        }
        
        /// Insert a new row into the list view.
        private void InsertRow(
            int aMessageID,
            string aMessageName,
            int aSize,
            string aData,
            RowType aType
        )
        {
            string lIDStr = string.Empty;
            
            switch (aType)
            {
                case RowType.Data:
                {
                    lIDStr = "D: " + aMessageID.ToString();
                    break;
                }
                case RowType.Event:
                {
                    lIDStr = "Ev: " + aMessageID.ToString();
                    break;
                }
                case RowType.Error:
                {
                    lIDStr = "Err: " + aMessageID.ToString();
                    break;
                }
                case RowType.Command:
                {
                    lIDStr = "Command";
                    break;
                }
                case RowType.CommandResponse:
                {
                    lIDStr = "Response";
                    break;
                }
            }
            
            listViewMessages.BeginUpdate();
            
            ListViewItem item = listViewMessages.Items.Add(lIDStr);
            item.SubItems.Add(aMessageName);
            item.SubItems.Add(aSize.ToString());
            item.SubItems.Add(aData);
            
            listViewMessages.EndUpdate();
            
            item.EnsureVisible();
        }
        
        // Thread helper callback to make sure data is received on the correct thread.
        private void ProcessDataThreadHelper(
            MMM.Readers.Modules.Swipe.SwipeItem aDataItem,
            object aData
        )
        {
            if (_threadHelperControl.InvokeRequired)
            {
                _threadHelperControl.Invoke(
                    new MMM.Readers.Modules.Swipe.DataDelegate(ProcessData), 
                    new object[] { aDataItem, aData }
                );
            }
            else
            {
                ProcessData(aDataItem, aData);
            }
        }
        
        // Thread helper callback to make sure data is received on the correct thread.
        private void ProcessEventThreadHelper(MMM.Readers.FullPage.EventCode aEventCode)
        {
            if (_threadHelperControl.InvokeRequired)
            {
                _threadHelperControl.Invoke(
                    new MMM.Readers.FullPage.EventDelegate(ProcessEvent), 
                    new object[] { aEventCode }
                );
            }
            else
            {
                ProcessEvent(aEventCode);
            }
        }
        
        // Thread helper callback to make sure data is received on the correct thread.
        private void ProcessErrorThreadHelper(
            MMM.Readers.ErrorCode aErrorCode, 
            string aErrorMessage
        )
        {
            if (_threadHelperControl.InvokeRequired)
            {
                _threadHelperControl.Invoke(
                    new MMM.Readers.ErrorDelegate(ProcessError), 
                    new object[] { aErrorCode, aErrorMessage }
                );
            }
            else
            {
                ProcessError(aErrorCode, aErrorMessage);
            }
        }

        private void ShowQALineData(
            int aMessageID, 
            int line, 
            MMM.Readers.Modules.Swipe.RTEQALineData qaLineData
        )
        {
            if (Convert.ToBoolean(qaLineData.HasData))
            {
                string lineStr = string.Format("LINE {0} - ", line);

                InsertRow(aMessageID, lineStr + "QA_CHAR_COUNT", 0, qaLineData.CharCount.ToString(), RowType.Data);
                InsertRow(aMessageID, lineStr + "QA_LOWER_LINE_BOUNDARY", 0, qaLineData.LowerLineBoundary.ToString(), RowType.Data);
                InsertRow(aMessageID, lineStr + "QA_UPPER_LINE_BOUNDARY", 0, qaLineData.UpperLineBoundary.ToString(), RowType.Data);
                InsertRow(aMessageID, lineStr + "QA_RECOGNISED_COUNT", 0, qaLineData.RecognisedCount.ToString(), RowType.Data);
                InsertRow(aMessageID, lineStr + "QA_AVERAGE_STROKE_WIDTH", 0, qaLineData.AverageStrokeWidth.ToString(), RowType.Data);
                InsertRow(aMessageID, lineStr + "QA_THINNEST_STROKE_WIDTH", 0, qaLineData.ThinnestStrokeWidth.ToString(), RowType.Data);
                InsertRow(aMessageID, lineStr + "QA_THICKEST_STROKE_WIDTH", 0, qaLineData.ThickestStrokeWidth.ToString(), RowType.Data);
                InsertRow(aMessageID, lineStr + "QA_NON_CONTINUOUS_COUNT", 0, qaLineData.NonContinuousCount.ToString(), RowType.Data);
            }
        }
        
        private void ProcessData(MMM.Readers.Modules.Swipe.SwipeItem aDataItem, object aData)
        {
            string dataStr = string.Empty;
            
            if (aData is int || aData is bool || aData is float || aData is string)
            {
                dataStr = aData.ToString();
                InsertRow((int)aDataItem, aDataItem.ToString(), 0, dataStr, RowType.Data);
            }
            else if (aData is MMM.Readers.CodelineData)
            {
                MMM.Readers.CodelineData codeline = (MMM.Readers.CodelineData)aData;
                InsertRow((int)aDataItem, aDataItem.ToString(), codeline.Data.Length, codeline.Data, RowType.Data);
                InsertRow((int)aDataItem, "OCR_LINE_1", codeline.Line1.Length, codeline.Line1, RowType.Data);
                InsertRow((int)aDataItem, "OCR_LINE_2", codeline.Line2.Length, codeline.Line2, RowType.Data);
                InsertRow((int)aDataItem, "OCR_LINE_3", codeline.Line3.Length, codeline.Line3, RowType.Data);
                InsertRow((int)aDataItem, "OCR_DOC_ID", codeline.DocId.Length, codeline.DocId, RowType.Data);
                InsertRow((int)aDataItem, "OCR_DOC_TYPE", codeline.DocType.Length, codeline.DocType, RowType.Data);
                InsertRow((int)aDataItem, "OCR_SURNAME", codeline.Surname.Length, codeline.Surname, RowType.Data);
                InsertRow((int)aDataItem, "OCR_FORENAME", codeline.Forename.Length, codeline.Forename, RowType.Data);
                InsertRow((int)aDataItem, "OCR_SECOND_NAME", codeline.SecondName.Length, codeline.SecondName, RowType.Data);
                InsertRow((int)aDataItem, "OCR_FORENAMES", codeline.Forenames.Length, codeline.Forenames, RowType.Data);

                if (codeline.DateOfBirth.Day == -1 &&
                    codeline.DateOfBirth.Month == -1 &&
                    codeline.DateOfBirth.Year == -1)
                {
                    InsertRow((int)aDataItem, "OCR_DATE_OF_BIRTH", 0, "", RowType.Data);
                }
                else
                {
                    string lD, lM, lY;

                    if (codeline.DateOfBirth.Day == -1)
                        lD = "??-";
                    else
                        lD = string.Format("{0:00}-", codeline.DateOfBirth.Day);

                    if (codeline.DateOfBirth.Month == -1)
                        lM = "??-";
                    else
                        lM = string.Format("{0:00}-", codeline.DateOfBirth.Month);

                    if (codeline.DateOfBirth.Year == -1)
                        lY = "??";
                    else
                        lY = string.Format("{0:00}", codeline.DateOfBirth.Year);


                    InsertRow((int)aDataItem, "OCR_DATE_OF_BIRTH", 0, (lD+lM+lY), RowType.Data);

                }


                if (codeline.ExpiryDate.Day == -1 &&
                    codeline.ExpiryDate.Month == -1 &&
                    codeline.ExpiryDate.Year == -1)
                {
                    InsertRow((int)aDataItem, "OCR_EXPIRY_DATE", 0, "", RowType.Data);
                }
                else
                {
                    string lD, lM, lY;

                    if (codeline.ExpiryDate.Day == -1)
                        lD = "??-";
                    else
                        lD = string.Format("{0:00}-", codeline.ExpiryDate.Day);

                    if (codeline.ExpiryDate.Month == -1)
                        lM = "??-";
                    else
                        lM = string.Format("{0:00}-", codeline.ExpiryDate.Month);

                    if (codeline.ExpiryDate.Year == -1)
                        lY = "??";
                    else
                        lY = string.Format("{0:00}", codeline.ExpiryDate.Year);


                    InsertRow((int)aDataItem, "OCR_EXPIRY_DATE", 0, (lD+lM+lY), RowType.Data);

                }  
                
                InsertRow((int)aDataItem, "OCR_ISSUING_STATE", codeline.IssuingState.Length, codeline.IssuingState, RowType.Data);
                InsertRow((int)aDataItem, "OCR_NATIONALITY", codeline.Nationality.Length, codeline.Nationality, RowType.Data);
                InsertRow((int)aDataItem, "OCR_DOC_NUMBER", codeline.DocNumber.Length, codeline.DocNumber, RowType.Data);
                InsertRow((int)aDataItem, "OCR_SEX", codeline.Sex.Length, codeline.Sex, RowType.Data);
                InsertRow((int)aDataItem, "OCR_SHORT_SEX", 1, Convert.ToChar(codeline.ShortSex).ToString(), RowType.Data);
#if !DOTNET_11
                InsertRow((int)aDataItem, "OCR_OPTIONALDATA1", codeline.OptionalData1.Length, codeline.OptionalData1, RowType.Data);
                InsertRow((int)aDataItem, "OCR_OPTIONALDATA2", codeline.OptionalData2.Length, codeline.OptionalData2, RowType.Data);
#endif
            }
            else if (aData is MMM.Readers.Modules.Swipe.MsrData)
            {
                MMM.Readers.Modules.Swipe.MsrData msrData = (MMM.Readers.Modules.Swipe.MsrData)aData;
                InsertRow((int)aDataItem, "MSR_TRACK_1", msrData.Track1.Length, msrData.Track1, RowType.Data);
                InsertRow((int)aDataItem, "MSR_TRACK_2", msrData.Track2.Length, msrData.Track2, RowType.Data);
                InsertRow((int)aDataItem, "MSR_TRACK_3", msrData.Track3.Length, msrData.Track3, RowType.Data);
            }
            else if (aData is MMM.Readers.Modules.Swipe.SwipeBarcodePDF417Data)
            {
                MMM.Readers.Modules.Swipe.SwipeBarcodePDF417Data swipeBarcodeData = (MMM.Readers.Modules.Swipe.SwipeBarcodePDF417Data)aData;
                InsertRow((int)aDataItem, "BARCODE PDF417", swipeBarcodeData.DataField.Length, swipeBarcodeData.DataField, RowType.Data);
            }
            else if (aData is MMM.Readers.Modules.Swipe.SwipeBarcodeCode128Data)
            {
                MMM.Readers.Modules.Swipe.SwipeBarcodeCode128Data swipeBarcodeData = (MMM.Readers.Modules.Swipe.SwipeBarcodeCode128Data)aData;
                InsertRow((int)aDataItem, "BARCODE CODE 128", swipeBarcodeData.DataField.Length, swipeBarcodeData.DataField, RowType.Data);
            }
            else if (aData is MMM.Readers.Modules.Swipe.SwipeBarcodeCode39Data)
            {
                MMM.Readers.Modules.Swipe.SwipeBarcodeCode39Data swipeBarcodeData = (MMM.Readers.Modules.Swipe.SwipeBarcodeCode39Data)aData;
                InsertRow((int)aDataItem, "BARCODE CODE 39", swipeBarcodeData.DataField.Length, swipeBarcodeData.DataField, RowType.Data);
            }
            else if (aData is MMM.Readers.AAMVAData)
            {
                MMM.Readers.AAMVAData AAMVAData = (MMM.Readers.AAMVAData)aData;
                InsertRow((int)aDataItem, "AAMVA_FULLNAME", AAMVAData.Parsed.FullName.Length, AAMVAData.Parsed.FullName, RowType.Data);
                InsertRow((int)aDataItem, "AAMVA_FORENAME", AAMVAData.Parsed.Forename.Length, AAMVAData.Parsed.Forename, RowType.Data);
                InsertRow((int)aDataItem, "AAMVA_SURNAME", AAMVAData.Parsed.Surname.Length, AAMVAData.Parsed.Surname, RowType.Data);
                InsertRow((int)aDataItem, "AAMVA_LICENCE_NUMBER", AAMVAData.Parsed.LicenceNumber.Length, AAMVAData.Parsed.LicenceNumber, RowType.Data);
                InsertRow((int)aDataItem, "AAMVA_ADDRESS_STREET", AAMVAData.Parsed.AddressStreet.Length, AAMVAData.Parsed.AddressStreet, RowType.Data);
                InsertRow((int)aDataItem, "AAMVA_ADDRESS_CITY", AAMVAData.Parsed.AddressCity.Length, AAMVAData.Parsed.AddressCity, RowType.Data);
                InsertRow((int)aDataItem, "AAMVA_ADDRESS_POSTALCODE", AAMVAData.Parsed.AddressPostalCode.Length, AAMVAData.Parsed.AddressPostalCode, RowType.Data);
                InsertRow((int)aDataItem, "AAMVA_ADDRESS_STATE", AAMVAData.Parsed.AddressState.Length, AAMVAData.Parsed.AddressState, RowType.Data);
                InsertRow((int)aDataItem, "AAMVA_ADDRESS_COUNTRY", AAMVAData.Parsed.AddressCountry.Length, AAMVAData.Parsed.AddressCountry, RowType.Data);
            }
            else if (aData is MMM.Readers.Modules.Swipe.AtbData)
            {
                MMM.Readers.Modules.Swipe.AtbData atbData = (MMM.Readers.Modules.Swipe.AtbData)aData;
                InsertRow((int)aDataItem, "ATB_TRACK_1_BLOCK_1", atbData.Track1.Block1.Length, atbData.Track1.Block1, RowType.Data);
                InsertRow((int)aDataItem, "ATB_TRACK_1_BLOCK_2", atbData.Track1.Block2.Length, atbData.Track1.Block2, RowType.Data);
                InsertRow((int)aDataItem, "ATB_TRACK_1_BLOCK_3", atbData.Track1.Block3.Length, atbData.Track1.Block3, RowType.Data);
                InsertRow((int)aDataItem, "ATB_TRACK_2_BLOCK_1", atbData.Track2.Block1.Length, atbData.Track2.Block1, RowType.Data);
                InsertRow((int)aDataItem, "ATB_TRACK_2_BLOCK_2", atbData.Track2.Block2.Length, atbData.Track2.Block2, RowType.Data);
                InsertRow((int)aDataItem, "ATB_TRACK_2_BLOCK_3", atbData.Track2.Block3.Length, atbData.Track2.Block3, RowType.Data);
                InsertRow((int)aDataItem, "ATB_TRACK_3_BLOCK_1", atbData.Track3.Block1.Length, atbData.Track3.Block1, RowType.Data);
                InsertRow((int)aDataItem, "ATB_TRACK_3_BLOCK_2", atbData.Track3.Block2.Length, atbData.Track3.Block2, RowType.Data);
                InsertRow((int)aDataItem, "ATB_TRACK_3_BLOCK_3", atbData.Track3.Block3.Length, atbData.Track3.Block3, RowType.Data);
                InsertRow((int)aDataItem, "ATB_TRACK_4_BLOCK_1", atbData.Track4.Block1.Length, atbData.Track4.Block1, RowType.Data);
                InsertRow((int)aDataItem, "ATB_TRACK_4_BLOCK_2", atbData.Track4.Block2.Length, atbData.Track4.Block2, RowType.Data);
                InsertRow((int)aDataItem, "ATB_TRACK_4_BLOCK_3", atbData.Track4.Block3.Length, atbData.Track4.Block3, RowType.Data);
            }
            else if (aData is MMM.Readers.Modules.Swipe.RTEQAData)
            {
                MMM.Readers.Modules.Swipe.RTEQAData qaData = (MMM.Readers.Modules.Swipe.RTEQAData)aData;
                InsertRow((int)aDataItem, "QA_CODELINE_COUNT", 0, qaData.CodelineCount.ToString(), RowType.Data);
                InsertRow((int)aDataItem, "QA_COLUMN_COUNT", 0, qaData.ColumnCount.ToString(), RowType.Data);
                InsertRow((int)aDataItem, "QA_CLEAR_AREA_PRESENT", 0, Convert.ToBoolean(qaData.ClearAreaPresent).ToString(), RowType.Data);
                InsertRow((int)aDataItem, "QA_SPOT_COUNT", 0, qaData.SpotCount.ToString(), RowType.Data);
                ShowQALineData((int)aDataItem, 1, qaData.Line1);
                ShowQALineData((int)aDataItem, 2, qaData.Line2);
                ShowQALineData((int)aDataItem, 3, qaData.Line3);
            }
            else if (aData is MMM.Readers.Modules.Swipe.RTESwipeData)
            {
                MMM.Readers.Modules.Swipe.RTESwipeData rteData = (MMM.Readers.Modules.Swipe.RTESwipeData)aData;
                InsertRow((int)aDataItem, "RTE_DEVICE_TYPE", 0, rteData.DeviceType.ToString(), RowType.Data);
                InsertRow((int)aDataItem, "RTE_MESSAGE_TYPE", 0, rteData.MessageType.ToString(), RowType.Data);
                InsertRow((int)aDataItem, "RTE_BCC", 0, rteData.BCC.ToString(), RowType.Data);
                InsertRow((int)aDataItem, "RTE_OCR_FLAG_BYTE", 0, rteData.OCRFlagByte.ToString(), RowType.Data);
            }
            else if (aData is MMM.Readers.Modules.Swipe.MuseSwipeData)
            {
                MMM.Readers.Modules.Swipe.MuseSwipeData museData = (MMM.Readers.Modules.Swipe.MuseSwipeData)aData;
                InsertRow((int)aDataItem, "MUSE_DEVICE_TYPE", 0, museData.DeviceType.ToString(), RowType.Data);
                InsertRow((int)aDataItem, "MUSE_CRC_HIGH", 0, museData.CrcHigh.ToString(), RowType.Data);
                InsertRow((int)aDataItem, "MUSE_CRC_LOW", 0, museData.CrcLow.ToString(), RowType.Data);
            }
            else if (aData is MMM.Readers.Modules.Swipe.CuteSwipeData)
            {
                MMM.Readers.Modules.Swipe.CuteSwipeData cuteData = (MMM.Readers.Modules.Swipe.CuteSwipeData)aData;
                InsertRow((int)aDataItem, "CUTE_DEVICE_TYPE", 0, cuteData.DeviceType.ToString(), RowType.Data);
            }
            else if (aData is MMM.Readers.Modules.Swipe.MagtekMsrSwipeData)
            {
                MMM.Readers.Modules.Swipe.MagtekMsrSwipeData magtekData = (MMM.Readers.Modules.Swipe.MagtekMsrSwipeData)aData;
                InsertRow((int)aDataItem, "MAGTEK_MSR_CARD_TYPE", 0, magtekData.CardEncodeType.ToString(), RowType.Data);
            }
            else if (aData is byte)
            {
                byte dataValue = (byte)aData;
                dataStr = dataValue.ToString("X2");
                InsertRow((int)aDataItem, aDataItem.ToString(), 0, dataStr, RowType.Data);
            }
            else if (aData is byte[])
            {
                byte[] dataArray = aData as byte[];
                if (aDataItem == MMM.Readers.Modules.Swipe.SwipeItem.WHOLE_DATA)
                {
                    dataStr = ConvertSwipeDataByteArray(dataArray);
                }
                else
                {
                    foreach (byte byteVal in dataArray)
                    {
                        dataStr = string.Concat(dataStr, byteVal.ToString("X2"), " ");
                    }
                }
                InsertRow((int)aDataItem, aDataItem.ToString(), 0, dataStr, RowType.Data);
            }           
        }
        
        private void ProcessEvent(MMM.Readers.FullPage.EventCode aEventCode)
        {
            InsertRow((int)aEventCode, aEventCode.ToString(), 0, string.Empty, RowType.Event);
        }
        
        private void ProcessError(MMM.Readers.ErrorCode aErrorCode, string aErrorMessage)
        {
            InsertRow((int)aErrorCode, aErrorCode.ToString(), 0, aErrorMessage, RowType.Error);
        }
        
        private void InitialiseSwipeAPI()
        {
            MMM.Readers.ErrorCode lErrorCode = MMM.Readers.ErrorCode.NO_ERROR_OCCURRED;
            
            // Initialise logging and error handling first. The error handler callback
            // will receive all error messages generated by the 3M Page Reader SDK
            MMM.Readers.Modules.Reader.SetErrorHandler(
                new MMM.Readers.ErrorDelegate(ProcessErrorThreadHelper),
                IntPtr.Zero 
            );
            lErrorCode = MMM.Readers.Modules.Reader.InitialiseLogging(
                true,
                3,
                -1,
                "SwipeReader.Net.log"
            );
            
            if (lErrorCode == MMM.Readers.ErrorCode.NO_ERROR_OCCURRED)
            {
                // Next load the settings for the Swipe Reader from the ini files. You can 
                // also modify and save settings back to the ini files using 
                // MMM.Readers.Modules.Reader.SaveSwipeSettings()
                lErrorCode = MMM.Readers.Modules.Reader.LoadSwipeSettings(
                    ref swipeSettings
                );
            }
            
            if (lErrorCode == MMM.Readers.ErrorCode.NO_ERROR_OCCURRED)
            {
                // Initialise the Swipe Reader. Data and events will be sent back in a 
                // non-blocking fashion through the callbacks provided
                //
                // Thread helper delegates are used to avoid thread-safety issues, 
                // particularly with .NET framework 2.0
                lErrorCode = MMM.Readers.Modules.Swipe.Initialise(
                    swipeSettings,
                    new MMM.Readers.Modules.Swipe.DataDelegate(ProcessDataThreadHelper),
                    new MMM.Readers.FullPage.EventDelegate(ProcessEventThreadHelper)
                );
            }
            
            if (lErrorCode != MMM.Readers.ErrorCode.NO_ERROR_OCCURRED)
            {
                InsertRow(
                    (int)lErrorCode, 
                    lErrorCode.ToString(), 
                    0, 
                    "Failed to initialise Swipe Reader API", 
                    RowType.Error
                );
            }
            else
            {
                // Display the hardware device and protocol in use
                string lProtocolName = new string(swipeSettings.Protocol.ProtocolName);
                
                if (lProtocolName.StartsWith("RTE"))
                {
                    // For RTE_INTERRUPT and RTE_POLLED modes, the Swipe Reader API can 
                    // automatically send Enable Device commands once finished reading so
                    // that you do not have to
                    if (
                        !lProtocolName.Equals("RTE_NATIVE") && 
                        swipeSettings.Protocol.RTE.AutoSendEnableDevice > 0
                    )
                    {
                        lProtocolName = string.Concat(
                            lProtocolName, 
                            ", Auto Send Enable Command"
                        );
                    }
                    
                    if (swipeSettings.Protocol.RTE.UseBCC > 0)
                    {
                        lProtocolName = string.Concat(
                            lProtocolName, 
                            ", with BCC"
                        );
                    }
                    else
                    {
                        lProtocolName = string.Concat(
                            lProtocolName, 
                            ", no BCC"
                        );
                    }
                }
                
                labelHardwareProto.Text = string.Format(
                    "{0}, Hardware: {1}", 
                    lProtocolName, 
                    swipeSettings.Hardware.DeviceType.ToString()
                );
            }
        }
        
        private string ConvertSwipeDataByteArray(byte[] array)
        {
            StringBuilder builder = new StringBuilder();
            
            foreach (byte val in array)
            {
                switch (val)
                {
                    case 0 : builder.Append("{NUL}"); break;
                    case MMM.Readers.Modules.Swipe.ByteConstants.SOH : builder.Append("{SOH}"); break;
                    case MMM.Readers.Modules.Swipe.ByteConstants.STX : builder.Append("{STX}"); break;
                    case MMM.Readers.Modules.Swipe.ByteConstants.ETX : builder.Append("{ETX}"); break;
                    case MMM.Readers.Modules.Swipe.ByteConstants.LF : builder.Append("{LF}"); break;
                    case MMM.Readers.Modules.Swipe.ByteConstants.CR : builder.Append("{CR}"); break;
                    case MMM.Readers.Modules.Swipe.ByteConstants.ACK : builder.Append("{ACK}"); break;
                    case MMM.Readers.Modules.Swipe.ByteConstants.NACK : builder.Append("{NACK"); break;                 
                    case MMM.Readers.Modules.Swipe.CuteProtocolByteConstants.SOD1 : builder.Append("{SOD1}"); break;
                    case MMM.Readers.Modules.Swipe.CuteProtocolByteConstants.EOD1 : builder.Append("{EOD1}"); break;
                    case MMM.Readers.Modules.Swipe.CuteProtocolByteConstants.SOD2 : builder.Append("{SOD2}"); break;
                    case MMM.Readers.Modules.Swipe.CuteProtocolByteConstants.EOD2 : builder.Append("{EOD2}"); break;
                    default : builder.Append(Convert.ToChar(val)); break;
                }
            }
            
            return builder.ToString();
        }

        private void MainForm_Load(object sender, System.EventArgs e)
        {
            // Use a timer to initialise the Swipe Reader API, this allows the dialog
            // to be drawn to the screen so the user can see something happening
            timerInit.Enabled = true;
        }

        private void MainForm_Closed(object sender, System.EventArgs e)
        {
            MMM.Readers.Modules.Swipe.Shutdown();
            MMM.Readers.Modules.Reader.ShutdownLogging();
        }

        private void timerInit_Tick(object sender, System.EventArgs e)
        {
            timerInit.Enabled = false;
            InitialiseSwipeAPI();
        }

        private void buttonClearList_Click(object sender, System.EventArgs e)
        {
            listViewMessages.Items.Clear();
        }
        
    }
}

接著我需要把程式調整為可以呼叫使用的類別庫

i.新增專案->選擇C#->選擇Windows->選擇類別庫->定義名稱

ii.新增一個cs檔,並將將原本專案中的程式碼複製改寫

MyActiveX.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace MyActiveX
{

    [Guid("C90E96C1-8534-4243-9530-960D9AF982CB")]
    [ComVisible(true)]
    public class MyActiveX : IObjectSafety
    {
        public string ProtocolStr { get; set; }
        public string resultStr { get; set; }
        public string ErrorStr { get; set; }
        enum RowType
        {
            Data,
            Event,
            Error,
            Command,
            CommandResponse
        }

        public void Close()
        {
            try
            {
                MMM.Readers.Modules.Swipe.Shutdown();
                MMM.Readers.Modules.Reader.ShutdownLogging();
            }
            catch
            {
            }
        }
        public void Start()
        {
            try
            {
                _threadHelperControl = new Control();
                _threadHelperControl.CreateControl();
                //實體化
                InitialiseSwipeAPI();
                //讀取資料
                //string rtnStr = resultStr;
                //resultStr = ""; //清空 表示之前的資料已經顯示過了
                //讀取結束
                //MMM.Readers.Modules.Swipe.Shutdown();
                //MMM.Readers.Modules.Reader.ShutdownLogging();
                //return rtnStr;
            }
            catch (Exception ex)
            {
                //return ex.Message;
                ErrorStr = ex.Message;
            } 
        }
        private MMM.Readers.Modules.Swipe.SwipeSettings swipeSettings;
        private Control _threadHelperControl;
        
        /// Insert a new row into the list view.
        private void InsertRow(
            int aMessageID,
            string aMessageName,
            int aSize,
            string aData,
            RowType aType
        )
        {
            string lIDStr = string.Empty;

            switch (aType)
            {
                case RowType.Data:
                    {
                        lIDStr = "D: " + aMessageID.ToString();
                        break;
                    }
                case RowType.Event:
                    {
                        lIDStr = "Ev: " + aMessageID.ToString();
                        break;
                    }
                case RowType.Error:
                    {
                        lIDStr = "Err: " + aMessageID.ToString();
                        break;
                    }
                case RowType.Command:
                    {
                        lIDStr = "Command";
                        break;
                    }
                case RowType.CommandResponse:
                    {
                        lIDStr = "Response";
                        break;
                    }
            }

            //listViewMessages.BeginUpdate();

            //ListViewItem item = listViewMessages.Items.Add(lIDStr);
            //item.SubItems.Add(aMessageName);
            //item.SubItems.Add(aSize.ToString());
            //item.SubItems.Add(aData);

            //listViewMessages.EndUpdate();

            //item.EnsureVisible();
            resultStr += lIDStr + "," + aMessageName + "," +  aSize.ToString() + "," + aData + "|@@|@@|";
            
        }
        

差異在於我將表單物件的Form_Load事件,改為一個Start()的函式提供呼叫,並將結束的事件寫至一個Close()
調整insertRow不需要輸出到表單物件上,而是儲存在一個string字串中(使用StringBulider較好)

iii.加上GUID以利ActiveXObject使用

[Guid("C90E96C1-8534-4243-9530-960D9AF982CB")]
[ComVisible(true)]

iiii.撰寫測試網頁來試試看

test.html
<html>
<head>
<title></title>
<script language="javascript" type="text/javascript">
  function Start() {
            document.getElementById("3MObject").Start();
  }
    function getResult(){
        alert(document.getElementById("3MObject").resultStr);
    }
    function getError(){
        alert(document.getElementById("3MObject").ErrorStr);
    }    
</script>
</head> 
<body>
<input type="button" value="start" onclick="Start()"/>
<input type="button" value="get Return str" onclick="getResult()"/>
<input type="button" value="error" onclick="getError()"/>
<object id="3MObject" classid="clsid:C90E96C1-8534-4243-9530-960D9AF982CB"  width="0px" height="0px" />
</body>
</html>

結果,目前於本機上是可以測試成功的,但是真正的使用者是在遠端的網路上透過瀏覽器操作,所以還必須要做一些動作

讓遠端IE瀏覽器可以使用ActiveX Object

i.使用者IE瀏覽器設定,加入到信任的網站

ii.調整ActiveX設定

將程式打包成可以提供遠端使用者下載的cab檔

i.加入安裝專案

ii.將剛剛寫好的專案設定為主要輸出,建置就會產生一個SetUp.exe 與 msi檔

iii.撰寫install.inf 以讓IE知道如何運作

install.inf
[version]
signature="$CHICAGO$"
AdvancedINF=2.0
[Add.Code]
Setup2.msi=Setup2.msi
setup.exe=setup.exe
[Setup2.msi]
file-win32-x86=thiscab
clsid={C90E96C1-8534-4243-9530-960D9AF982CB}
hook=hook1
[setup.exe]
file-win32-x86=thiscab
[Setup Hooks]
hook1=hook1
[hook1]
run=%EXTRACT_DIR%\setup.exe

iii.將以上檔案打包成cab檔(建議參考朱大的部落格說明文章:[.NET] 使用 .NET Framework 開發 ActiveX Control (3) - 封裝,簽章與部署)
-需要先下載cab的生成工具
http://www.pixelsplasher.com/_downloads/software/Microsoft-Cabinet-SDK/cabsdk.exe

-開啟cmd.exe 設定執行目錄 例如 : D:\Cabinet\BIN
cmd > Set Path = D:\Cabinet\BIN

-移至目錄(setup.exe)的資料夾
cmd > cd C:..\Setup1\

-將install.inf複製貼上到目錄內

-將檔案產出成cab檔
cmd > CABARC n MyActiveX.cab install.inf Setup.exe "Setup2.msi"

調整HTML碼使用已編譯好的cab檔

<object id="myControl" classid="clsid:C90E96C1-8534-4243-9530-960D9AF982CB" codebase="3Mreader.cab" width="0px" height="0px" />

接下來就能夠正常的使用與測試,隨著每個人的應用方式而調整內容,但應用的技術是相同的

← Javascript location.href 在 Chrome中無效 JSON檔無法透過URL開啟 →
 
comments powered by Disqus