Saturday, September 12, 2009

Generate DataMatrix Barcode from Your .NET Application

Data Matrix barcode has several advantages over 1D barcodes such as:
  • Contains more character even alphanumeric.
  • Has square form for easier layout on printout.
  • Digital camera friendly even using your old cellphone camera.
  • Redundant information, you can scan 75% area of the barcode only for scanning.
  • A little bit omni scan direction.
Too bad my trusted DevExpress XtraReport XRBarcode doesn't have this symbology. Since I can't wait for DevExpress to implement Data Matrix so I decided to find open source solutions. Thanks God, I found external link on Data Matrix Wiki page for iec16022sharp an open source .NET Data Matrix generator library. Since I use VB.NET, I built the iec16022sharp assembly and use it by adding a reference to it. I am glad that iec16022sharp usage is very easy.
Here is my iec16022sharp usage snippet:
...
Imports IEC16022Sharp
...
Dim aReport As New RptBarcode
Dim aDataMatrix As New DataMatrix(BindSrcMaster.GetDataValue("BarcodeNum").ToString.Trim)

HierarchyRefreshDataRow(BindSrcMaster.GetDataRow)
With aReport
.CallingForm = Me
.PbDataMatrix.Image = DMImgUtility.SimpleResizeBmp(aDataMatrix.Image, 6, 0)
.QueryLoad(Application.StartupPath + "\CustomReport\Barcode.xml", BindSrcMaster)
.ShowPreview()
End With
...

The only functions I called from this library is a DataMatrix constructor and a static function DMImgUtility.SimpleResizeBmp. From the DataMatrix constructor I already have a small DataMatrix barcode. For enlarging the generated DataMatrix I just called the SimpleResizeBmp for enlarging it six times with zero pixel border. Hope my post give you an idea on using DataMatrix. Thank you.
...Read more

Wednesday, September 2, 2009

Application for Enabling Your WM Camera into a Barcode Scanner

I was really excited when I found QuickMark (I am not affiliated with QuickMark). This Taiwan company makes 2D and 1D barcode scanner software for Windows Mobile and Symbian. You can find a lot of similar software like QuickMark on the web. But QuickMark has one thing that stands in the crowd. You can call QuickMark using its API from your .NET Compact Framework 2.0 application and get the scan result. I already tested their API and it worked even for my EAN13 1D barcode. For only U$ 10 your WM Camera becomes a barcode scanner yippeee. I have polished their API demo below (sorry the source codes are not colored).
FrmQuickMarkAPIDemo (the form that uses QuickMarkAPI):
Public Class FrmQuickMarkAPIDemo
Private WithEvents aQuickMarkAPI As New QuickMarkAPI(AddressOf GetMsgString)

Public Sub New()
InitializeComponent()
End Sub

Private Sub MnuOK_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MnuOK.Click
aQuickMarkAPI.LaunchQuickMark()
End Sub

Private Sub GetMsgString(ByVal MsgString As String)
MsgBox(MsgString)
End Sub
'Just an alternative receive the message string using an event
'Private Sub aQuickMarkAPI_OnGetMsgString(ByVal MsgString As String) Handles aQuickMarkAPI.OnGetMsgString
' MsgBox(MsgString)
'End Sub
End Class

QuickMarkAPIDemo (The API itself):
Imports System.Diagnostics
Imports System.Runtime.InteropServices
Imports Microsoft.Win32
Imports System.IO
Imports Microsoft.WindowsCE.Forms
'QuickMark

'Flow of QuickMark Messenger
'Open msgapi --> Register a window message for inter-application communication (RegisterWindowMessage)
'-->launch QuickMark (Press OK button) --> send a unique message for inter-application communication(HWND_BROADCAST)
' --> QuickMark recevie the handle of msgapi's window. --> Decoding using QuickMark
' --> QuickMark send result to handle. --> msgapi show the result.

Class QuickMarkAPI
Inherits MessageWindow

<DllImport("coredll.dll")> _
Private Shared Function RegisterWindowMessage(ByVal lpString As String) As UInteger
End Function

<DllImport("coredll.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Private Shared Function PostMessageW( _
ByVal hWnd As IntPtr, _
ByVal Msg As UInteger, _
ByVal wParam As IntPtr, _
ByVal lParam As IntPtr) As Boolean
End Function

Friend Shared ReadOnly HWND_BROADCAST As New IntPtr(65535)

'a unique message for inter-application communication
Private RM_QuickMarkMessengerAPIApp As UInt32 = 0

'Handle to the window whose window procedure will receive the decoded result.
Public Delegate Sub OnGetMsgStringHandler(ByVal MsgString As String)
Public DefaultBarcodeType As Integer = 2 'Default is 2D scanning.
Event OnGetMsgString As OnGetMsgStringHandler
Private Const WM_COPYDATA As Integer = 74
Private aGetMsgString As OnGetMsgStringHandler = Nothing
Public Sub LaunchQuickMark()
' Step 1: Get application path of QuickMark from registry.
Dim szQuickMarkApp As String = ""
Dim QuickMarkKey As RegistryKey = Registry.CurrentUser
QuickMarkKey = QuickMarkKey.OpenSubKey("Software\QuickMark", False)
szQuickMarkApp = QuickMarkKey.GetValue("QuickMarkAppPath").ToString()
QuickMarkKey.Close()

' Step 2: Set default path of QuickMark.
If szQuickMarkApp.Length = 0 Then
szQuickMarkApp = "\Program Files\QuickMark\QuickMark.exe"
End If

' Step 3: Launch QuickMark.
If File.Exists(szQuickMarkApp) Then
'Launch application
Dim P As New Process()
P.StartInfo.FileName = szQuickMarkApp
P.StartInfo.Verb = "Open"
P.Start()
P.WaitForExit(1000)
'wait 1 second
'step 4: send RM_QuickMarkMessengerAPIApp to all top windows.
'parameters:
' HWND hWnd : HWND_BROADCAST , all top windows.
' UINT Msg : A unique message for inter-application communication.
' WPARAM wParam : Handle to the window whose window procedure will receive the decoded result.
' LPARAM lParam : Set QuickMark application to 1D or 2D scanning. (1:1D 2:2D)
PostMessageW(HWND_BROADCAST, RM_QuickMarkMessengerAPIApp, Me.Hwnd, DefaultBarcodeType)
Else
MessageBox.Show("QuickMark not found!")
End If
End Sub
'Receive the decoded result.
'STRUCT COPYDATASTRUCT member
'dwData:Data types of data.
' TYPE_CHAR: The data is a Binary data.
' TYPE_WIDECHAR: The data is a Unicode string.
'lpData:Long pointer to data.
'cbData:Specifies the size, in bytes, of the data pointed to by the lpData member.
Public Structure COPYDATASTRUCT
Public dwData As Integer
Public cbData As Integer
Public lpData As IntPtr
End Structure
Public Sub New(ByVal aGetMsgString As OnGetMsgStringHandler)
Me.aGetMsgString = aGetMsgString
'Register a window message for inter-application communication
Me.RM_QuickMarkMessengerAPIApp = RegisterWindowMessage("QuickMarkMessengerAPIApplication")
End Sub

Protected Overloads Overrides Sub WndProc(ByRef msg As Message)
Select Case msg.Msg
Case WM_COPYDATA
Dim str As String = GetMsgString(msg.LParam)
'TODO:Add your code here to process with the str.
'MessageBox.Show(str, "Result")
If aGetMsgString IsNot Nothing Then
aGetMsgString.Invoke(str)
End If
RaiseEvent OnGetMsgString(str)
Exit Select
End Select
MyBase.WndProc(msg)
End Sub

Public Shared Function GetMsgString(ByVal lParam As IntPtr) As String
If lParam <> IntPtr.Zero Then
Dim st As COPYDATASTRUCT = DirectCast(Marshal.PtrToStructure(lParam, GetType(COPYDATASTRUCT)), COPYDATASTRUCT)
Dim str As String = Marshal.PtrToStringUni(st.lpData)
Return str
Else
Return Nothing
End If
End Function
End Class


...Read more