Copyright: Copyright (c) Chris Amos 2000
Citation: Help for CRCOCX.OCX


Introduction

This control (OCX) is really designed for 32 bit VB. It should work in other OCX containers but this cannot be guaranteed.

The reason for using an OCX written in C++ for fairly simple algorithms are speed. In short the OCX is about 500 times quicker even if you are only adding up bytes (it also skirts around the bug in VB where a byte (unsigned) becomes a short int (signed) when you compile the application, one of the reasons for writing this control).

Since version 1.5, most of the CRCs are calculated in assembly language, this means it can be twice as fast again.

Usage

In VB you simply give the OCX a string, byte array or a variant and ask for a CRC, you have the option of showing a progress bar or passing the string in chunks. The CRC is returned as a signed 32 bit number (long), this can be a problem for VB so there are functions to return the calculated CRC in a hex or decimal string.

Alternatively, you can pass the name of a file to be CRC’d, an array of data, a variant or even a whole bunch of files to CRC in the background.

An example VB project is included, but this is about it!

Form Declarations

'' declare a byte array

Dim Data() As Byte

Form Level

' fill the byte array

ReDim Data(4)

data(0) = 1

data(2) = 3

data(3) = 5

data(4) = 7

' set which algorithm to use - vb pops up valid types!

crcTest.CRCType = CRC32Fwd

' do the calculation, without a seed, ie not split up

crcTest.DoCRCByteArray Data, 4, False, Seed

' display the result in a label

lblResult = crcTest.GetCRCHexStr


About

CRCOCX OLE Control

Calculates various CRCs of a passed string, variant or byte array.

Version	1.5

Date	09/01/00

Copyright (c)  	Chris Amos, 1999, 2000

Home page: 	http://www.preface.co.uk

http://welcome.to/sirocco

http://www.sirocco.force9.co.uk

Email: 	crcocx@preface.co.uk

chrisaaa@email.com

crcocx@sirocco.force9.co.uk

Legal stuff:

In short I accept no responsibility for what this code does directly or indirectly,

use it at your own risk.

Don't use it to control a power plant or a life support unit.


Enum - CRCTypes

Currently the control supports 11 calculations, these are selected by number, however these enumeration’s are made to make life easier.

0: Exclusive OR (XOR)

1: CRC-32 (PkZip, Ethernet)

2: Adler (ZLib)

3: CRC-16 Forward

4: CCITT

5: 16 Bit Sum

6: 32 Bit Sum

7: Private Custom CRC

8: ModBUS

9: CRC-16 Reversed (LHA?)

10: CRC-8 Forward

11: Custom (User-defined see InitCustom)

See also: Algorithms


Property - GetCRCDecStr

This function/property will return the last CRC calculated as a string, this helps when VB cannot make a 32 unsigned number, i.e. the CRC is something like -2145215254, when 2149752042 looks neater.

See also: GetCRCHexStr


Property - GetCRCHexStr

This function/property will return the last CRC calculated as a hexadecimal string, this helps when VB cannot handle a 32 unsigned number, i.e. the CRC is something like -2145215254, when 80229CEA looks neater.

See also: GetCRCDecStr


Property - CRCType

Choose the algorithm to use.

See Also: CRCTypes


Method - DoCRC

This function calculates the CRC of a passed string, the vagaries of Unicode can make this function unreliable if you use CRCs across national boundaries, that is across character sets, Unicode, MBCS etc.

For this reason I recommend using the byte array function instead.

In VB it is defined as:

DoCRC(String Data, Long Count, Boolean UseSeed, Long Seed) as Long

In C it is defined as:

long DoCRC(LPCTSTR pData, long lCnt, BOOL fSeed, long lSeed);

Example:

Form Level

' fill the byte array

Dim Data as string

Data = "Hello world"	' Cheesy huh

' set which algorithm to use - vb pops up valid types!

crcTest.CRCType = CRC32Fwd

' do the calculation, without a seed, ie not split up

crcTest.DoCRC Data, Length(Data), False, Seed

' display the result in a label

lblResult = crcTest.GetCRCHexStr

See Also: DoCRCVar, DoCRCByteArray


Method - DoCRCVar

This function is designed to CRC whatever variant is thrown at it. It returns 0 if it cannot understand the variant passed.

The following variant types are supported (there are too many to do them all). This is in C++ shorthand, it means U for unsigned, I for integer, R for real etc:

VT_ARRAY

VT_I1, VT_UI1, VT_I2, VT_UI2, VT_I4, VT_UI4, VT_R4

VT_I8, VT_UI8, VT_R8, VT_DATE,

VT_I1, VT_UI1, VT_I2, VT_UI2, VT_I4, VT_UI4, VT_R4

VT_R8, VT_DATE, VT_BSTR

VT_BYREF

VT_I1, VT_UI1, VT_I2, VT_UI2, VT_I4, VT_UI4, VT_R4

VT_BYREF | VT_VARIANT

VT_ARRAY

VT_I1, VT_UI1, VT_I2, VT_UI2, VT_I4, VT_UI4,

VT_R4, VT_I8, VT_UI8, VT_R8, VT_DATE

VT_BYREF

VT_I1, VT_UI1, VT_I2, VT_UI2, VT_I4, VT_UI4,

VT_R4

VT_I1, VT_UI1, VT_I2, VT_UI2, VT_I4, VT_UI4, VT_R4,

VT_R8, VT_DATE, VT_BSTR,

In VB it is defined as:

DoCRCVar(Variant Data) as Long

In C it is defined as:

long DoCRCVar(const VARIANT FAR& vData);

Example:

Form Level

' fill the byte array

Dim Data

Data = "Hello world"	' Cheesy huh

' set which algorithm to use - vb pops up valid types!

crcTest.CRCType = CRC32Fwd

' do the calculation, without a seed, ie not split up

crcTest.DoCRCVar Data

' display the result in a label

lblResult = crcTest.GetCRCHexStr

See Also: DoCRC, DoCRCByteArray


Method - DoCRCByteArray

This is the preferred and fastest way of calculating a CRC, it goes through a memory array at very high speed. It returns 0 if array passed is invalid, i.e. a single dimension byte array.

In VB it is defined as:

DoCRCByteArray(Variant Data, Long Count, Boolean UseSeed, Long Seed) as Long

In C it is defined as:

long DoCRCByteArray(const VARIANT FAR& vData, long lCnt, BOOL fSeed, long lSeed)

Example:

Form Declarations

'' declare a byte array

Dim Data() As Byte

Form Level

' fill the byte array

ReDim Data(4)

data(0) = 1

data(2) = 3

data(3) = 5

data(4) = 7

' set which algorithm to use - vb pops up valid types!

crcTest.CRCType = CRC32Fwd

' do the calculation, without a seed, ie not split up

crcTest.DoCRCByteArray Data, 4, False, Seed

' display the result in a label

lblResult = crcTest.GetCRCHexStr

See Also: DoCRC, DoCRCVar


Method - DoCRCFile

Rather than got to the trouble of loading a file into VB, if you just want to CRC it, then just call this function to CRC it in-place, this will be a lot quicker! It returns 0 if it fails.

In VB it is defined as:

DoCRCFile(String FileName) as Long

In C it is defined as:

long DoCRCFile(LPCTSTR pFileName)

Example:

Form Level

' set which algorithm to use - vb pops up valid types!

crcTest.CRCType = CRC32Fwd

' do the calculation, without a seed, ie not split up

crcTest.DoCRCFile "c:\autoexec.bat"

' display the result in a label

lblResult = crcTest.GetCRCHexStr


Method - DoCRCFileAsyncStart

Asynchronous version of the file CRC function, pass a reference number so that you can id the returned event. It returns 0 if it fails to start.

Reference 0 is reserved, it has special meaning in the DoCRCFileAsyncStop function.

In VB it is defined as:

DoCRCFileAsyncStart(String FileName, Long Reference) as Long

In C it is defined as:

long DoCRCFileAsyncStart(LPCTSTR pFileName, long lReference)

Example:

Form Level

' set which algorithm to use - vb pops up valid types!

crcTest.CRCType = CRC32Fwd

' do the calculation, without a seed, ie not split up

crcTest.DoCRCFileAsyncStart "c:\autoexec.bat", 1001

' I am not suggesting this is the right way to do this, use the event!

Do While (crcTest.GetAsyncStatus(1001) = crcStillExecuting) and (not cancelflag)

' set the cancel flag elsewhere!

DoEvents

Loop

' display the result in a label

lblResult = crcTest.GetCRCHexStr


Method - DoCRCFileAsyncStop

Stops the asynchronous version of the file CRC function, pass a reference number to id the one to stop. Pass 0 to stop all currently executing CRCs, I advise calling this in your form unload.

In VB it is defined as:

DoCRCFileAsyncStop(String FileName, Long Reference) as Long

In C it is defined as:

long DoCRCFileAsyncStop(LPCTSTR pFileName, long lReference)

Examples:

Form Level

' set which algorithm to use - vb pops up valid types!

crcTest.CRCType = CRC32Fwd

' do the calculation, without a seed, ie not split up

crcTest.DoCRCFileAsyncStart "c:\autoexec.bat", 1001

' I am not suggesting this is the right way to do this, use the event!

Do While (crcTest.GetAsyncStatus(1001) = crcStillExecuting) and (not cancelflag)

' set the cancel flag elsewhere!

DoEvents

Loop

' If we get here and it is still executing it must be cancelled

If crcTest.GetAsyncStatus(1001) = crcStillExecuting then

crcTest.DoCRCFileAsyncStop 1001

EndIf

' display the result in a label

lblResult = crcTest.GetCRCHexStr

- or -

Form Unload

' stop any executing CRCs, this is always safe

ctcTest.DoCRCFileAsyncStop 0


Method - GetAsyncStatus

This returns the state of the specified executing file CRC calculation. There are enumerated values for the two possible states.

crcNotExecuting = 0	' this also covers unknown references

crcStillExecuting = 1

In VB it is defined as:

GetAsyncStatus(Long Reference) as AsyncCRCStates

In C it is defined as:

AsyncCRCStates GetAsyncStatus(long lReference)

Example: DoCRCFileAsyncStart


Method - GetLastError

In general the CRC functions return 0 if there is a problem, the only errors possible are invalid variants or file errors. This introduces a slight possibility of reporting an error [0] when the CRC really is 0.

So if you get a CRC = 0 then call this function to get the last error, this will be 0 if there was no error. The other errors are as declared by Microsoft [winerror.h].

In VB it is defined as:

GetLastError() as Long

In C it is defined as:

long GetLastError()

Example:

Form Level

' fill the byte array

Dim Data as string

Data = "Hello world"	' Cheesy huh

' set which algorithm to use - vb pops up valid types!

crcTest.CRCType = CRC32Fwd

' do the calculation, without a seed, ie not split up

If crcTest.DoCRC(Data, Length(Data), False, Seed) = 0 Then

If crcTest.GetLastError <> 0 Then

' Report error

EndIf

EndIf

' display the result in a label

lblResult = crcTest.GetCRCHexStr


Method - InitCustom

Although the control implements all the algorithms I have found, I have had requests to identify various examples. This can be time consuming so I have added the ability for the user to define their own CRCs. This can be very complex, and I can’t even be sure that my way of specifying a particular CRC is the same as any other. See the theory for some tips on this.

It is best I give a couple of examples really:

CRC32 expressed as x^32,26,23,22,16,12,11,10,8,7,5,4,2,1,0. Translates to

Byte width:	4 (32 bit)

Polynomial:	04C11DB7

Reflect IP:	Yes

Reflect OP:	Yes

XOR OP with:	FFFFFFFF

Seed init:	FFFFFFFF

Use Seed:	False

CCITT expressed as x^16,12,5,0. Translates to

Byte width:	2 (16 bit)

Polynomial:	1021

Reflect IP:	No

Reflect OP:	No

XOR OP with:	0

Seed init:	FFFF

Use Seed:	Yes

You can deduce from this the polynomial is derived from the expression. For example  x^16,12,5,0 indicates bits 16,12,5 and 0 are used (1 0001 0000 0010 0001), the top bit is dropped (we only have 16 bits, 0..15) leaving 1021 hex.

The seed and output XOR value are usually 0 or –1 (all F’s in hex) and the reflection of input and output are usually both set the same. This makes reversing engineering a CRC a lot easier.

In VB it is defined as:

InitCustom(Bytes As Integer, Polynomial As Long, Seed As Long, ReflectOP As Integer,

ReflectIP As Integer, XOROP As Long) As Long

In C it is defined as:

long InitCustom(short iByteWidth, long lPolynomial, long lSeed,
 	short bReflectOP, short bReflectIP, long lXorOP);

Example:

Private Sub cmdInitCust_Click()

    Dim bytes As Integer

    Dim poly As Long

    Dim xorop As Long

    Dim reflectip As Integer

    Dim reflectop As Integer

    If opt16.Value = True Then bytes = 2 Else bytes = 4

    seed = Val("&H" & txtCustSeed)

    poly = Val("&H" & txtCustPoly)

    xorop = Val("&H" & txtCustXOR)

    If chkReflectOP = vbChecked Then reflectop = True Else reflectop = False

    If chkReflectIP = vbChecked Then reflectip = True Else reflectip = False

    crcTest.InitCustom bytes, poly, seed, reflectop, reflectip, xorop

End Sub


Event - AsyncFileCRC

When an asynchronous file CRC completes, this event is fired, this is much safer than taking the last result as two files could complete together!

In VB it is defined as:

AsyncFileCRC(ByVal Error As Long, ByVal Reference As Long, ByVal CRC As Long)

In C it is defined as:

void AsyncFileCRC(long Error, long Reference, long CRC);

See Also: DoCRCFileAsyncStart, DoCRCFileAsyncStop


Event - AsyncFileProgress

This fires to indicate progress so far, the value runs from 0 to 100 [percent].

In VB it is defined as:

AsyncFileProgress(ByVal Reference As Long, ByVal Progress As Integer)

In C it is defined as:

void AsyncFileProgress(long Reference, int Progress);

See Also: DoCRCFileAsyncStart, DoCRCFileAsyncStop


Property Page

From this page you can set the CRC type to use for all calculations, as a mater of programming practise and ease of maintenance I would say setting properties like this is a bad idea. It is much better to set these things in code which is more transparent when you come to read it later.

See Also: CRCTypes, CRCType


Property - Visible

I will include this property here [in my custom help] as it can make a dramatic difference to the speed of this OCX, when visible the control will display a progress bar this is pretty, but slow! Internally, the control will not bother to update the display if it is not visible.


Installation

This is a programmers tool, if you need to ask...

Installation should be simple!

Copy OCX and help files somewhere on you PC.

CrcOCX.OCX

crcocx.hlp	<- your reading this now, I hope!

crcocx.cnt

It requires the following files on your PC:

Support file	Version	CRC32

MSVCRT.DLL	6.00.8397.0	A7F18460

MSVCIRT.DLL	6.00.8168.0	0571D0E6

MFC42.DLL	6.00.8447.0	E9F90051

It requires something to host it, e.g. VB6.

It needs to be registered, double click on the OCX where you put it. Most systems will register it at this point, if your system asks what to do with an OCX, lead it to regsvr32.exe in you system directory.

When you first ask for help, you will probably have to lead it to the help file.

That’s it!


Version History

1.0	Initial release, requires a progress bar control in VB project that uses the control.

1.1	Fixed requirement for second progress bar.

1.2	Added ModBUS CRC

1.3	CCITT16 Reversed

1.4 	Added DoCRCVar to CRC most things found in a variant

Added DoCRCByteArray to CRC a Byte array, gets round some

Unicode problems on Japanese systems

1.5 	Added 8 bit CRC, by request source supplied, unsure of its use.

Added functions to retrieve CRC as hex/decimal string, for VB!

Optimised most CRC calculations with ASM language.

Added [this] help file

Unsorted property page listbox and change size to please VB

Added custom CRC algorithms


Algorithms

0: XOR

Bitwise XOR. Simply XORs all the bytes with the XOR of the previous bytes. Not a lot of use but it is quick to decode if you need to support it. This algorithm is done in assembly.

Example &H34, &H12, &H7A => &H26, &H7A => &H5C

1: CRC32

This is the most widely used CRC, it expressed as x^32,26,23,22,16,12,11,10,8,7,5,4,2,1,0. This is used in zip archives. This algorithm has a pre-calculated lookup table and is done in assembly.

2: Adler

I believe this is the method used in GZIP archives. I found the code on the net, it said feel free to use it with these copyrights declared so here they are: "Copyright Jason Teagle (jteagle@geocities.com) and Mark Adler"

unsigned long cCRCAccum::UpdAdler( unsigned char *pb_data, long lCnt )

{

unsigned long s1 = dw_adler & 0xffff;

unsigned long s2 = (dw_adler >> 16) & 0xffff;

for (long n = 0; n < lCnt; n++)

{

s1 = (s1 + pb_data[n]) % ADBASE;

s2 = (s2 + s1) % ADBASE;

}

return dw_adler = (s2 << 16) + s1;

}

3: CRC16

Fairly widely used CRC, it expressed as x^16,15,2,0. This algorithm has a precalculated lookup table and is done in assembly.

4: CCITT

Its a standard, 16 x^16,12,5,0. Whether I got it wrong or others did, it is less often used than the ModBUS variant below This algorithm has a precalculated lookup table and is done in assembly.

5: 16 Bit Sum

Simply adds up the bytes, way quicker than VB and bug free. Sometimes called a longitudinal redundancy check (LRC) in some specifications, but there must be more to something with a name like that. This algorithm is done in assembly.

6: 32 Bit Sum

As 16 bit sum, but bigger. This algorithm is done in assembly.

7: Private Custom type

Please ignore this type.

8: CCITT Reflected and byte swapped (i.e. Motorola byte order)

As use on ModBUS systems, 16 x^16,12,5,0, variant of type 4, possibly explains why I found few users of type 4. This algorithm has a precalculated lookup table and is done in assembly.

9: CCITT16 Reversed

As 8, 16 x^16,12,5,0, without the twist. This algorithm has a precalculated lookup table and is done in assembly.

10: CRC8

By request CRC, it is expressed as x^8,5,4,3,0.

11: Custom CRC

User-defined custom CRC see InitCustom.


License

I have released this control as what I call 'swapware', this means you can use this control in any personal project for free (send me an email anyway for my interest at freereg_crcocx@preface.co.uk or freereg_crcocx@sirocco.force9.co.uk).

I would like to get something back so if you use this control to produce a shareware or commercial product, I would like a copy of that product, DO NOT email me an application, send me an email with a description, a URL to get the program and the registration code etc.

If it is a big app that is only distributed on CD send me details and we'll take it from there. The address for swaps is swapreg_crcocx@preface.co.uk or swapreg_crcocx@sirocco.force9.co.uk.


Theory

I shall try to think what to put here maybe something graphical, I tend to look at these things as electronic devices, as shift registers with XOR gates.

The math is horrendous and out of my league. I understand the math proves that the CRCs of a well chosen algorithm are as widely spaced as possible. So even though the numbers are not random, they are as near as possible.

In other words, if you start with a given CRC and work backwards you will find 256 pairs of previous CRCs and bytes that will produce the number you first thought of.

On the web there is a paper called, "A Painless Guide To CRC Error Detection Algorithms" by Ross N. Williams, this has worked examples (http://www.repairfaq.org/filipg/LINK/F_crc_v3.html). This paper dispenses with some of the maths and reduces it a simple kind of division. It also shows various implementations of CRC calculations. This OCX uses the table driven type shown at the end, forward, reversed and reflected.


Source Code

I understand that commercial organisations must be able to guarantee continuity of support if they choose to use a component especially from a one-man-band.

The best way I can ensure this is to make the source code available. If you wish to 'buy' the source code go to http://www.sw-reg.com and look up product id 201692.

They will send the password to open the source code archive (http://www.preface.co.uk/crcsrc.zip or http://www.sirocco.force9.co.uk/crcsrc.zip) and inform me of your purchase.

This will not guarantee I will provide support and upgrades etc, it is your guarantee that YOU can support the component.


Support

As this product is free, I will not guarantee to answer any queries, I, and a few others, have tested it and it does what I wanted.

Send any queries to: freesupt_crcocx@preface.co.uk or freesupt_crcocx@sirocco.force9.co.uk