The optional CreateInksetHRCRESULT function creates a corresponding inkset from the data in an HPENDATA object. For a description of inksets and the INTERVAL structure, see "The HINKSET Object" in Chapter 4.

A description of the CreateInksetHRCRESULT function first requires a brief discussion of stroke start and end times. Some of this information also appears in the section "Timing Information" in Chapter 4, but it is presented here from the point of view of the recognizer rather than the application.

A stroke's start time is the starting tick count of the first group of points that AddPenInputHRC receives when a new stroke begins. The member dwTick of the STROKEINFO structure is the number of milliseconds that have elapsed since the system tick reference determined at system startup time. A recognizer can retrieve this value in an ABSTIME structure through a call to the Pen API function GetPenMiscInfo:

ABSTIME atTickRef;

GetPenMiscInfo( PMI_TICKREF, (LPARAM)((LPABSTIME) &atTickRef) );

The STROKEINFO structure also contains in its cPnt member the number of points in the collection. Because the pen device sends points at a constant rate (called the sampling rate), the number of points in the collection implies how much time has elapsed between the first and last points.

The sampling rate does not change, so the recognizer need only determine the rate during initialization and store the value. The following example shows how a recognizer can get the sampling rate from the pen driver:

PENINFO pinfo;

HDRVR hPenDrv;

int vnSamplingRate;




hPenDrv = OpenDriver( "pen", 0, 0 );

if (hPenDrv)


if (SendDriverMessage( hPenDrv, DRV_GetPenInfo, (LPARAM)&pinfo, 0 ))

  • nSamplingRate = pinfo.nSamplingRate;

CloseDriver( hDriverPen, 0, 0 );


With this information, CreateInksetHRCRESULT can fill an INTERVAL structure with a stroke's start and stop times as shown below. The code assumes the HRCRESULT object contains the HRC handle. This allows the internal function NGetStrokeFromHPENDATA to locate the internal HPENDATA object with the raw input data.


UINT isyv, UINT csyv)


HINKSET hinkset;

INTERVAL interval;


DWORD dwMsec;

UINT i, j;

// Call Pen API to create hinkset object

hinkset = CreateInkset( GMEM_MOVEABLE | GMEM_DDESHARE );

// Initialize INTERVAL with tick reference (described above)

GetPenMiscInfo( PMI_TICKREF,

(LPARAM)((LPABSTIME) &interval.atBegin) );

// For each SYV in the HRCRESULT between the given indices ...

for (i = 0; i < csyv; i++, isyv++ )


j = 0;

// For each stroke in the SYV ...

while ( NGetStrokeFromHPENDATA( hrcresult, &si, isyv, j++ ))



// Calculate the interval for the stroke.

// Note si.dwTick is the number of milliseconds

// that have elapsed since system start-up.


dwMsec = (DWORD)(1000L*interval.atBegin.sec + + si.dwTick);

interval.atBegin.sec = dwMsec/1000L; = (UINT)(dwMsec % 1000L);

dwMsec = (DWORD)(1000L*interval.atBegin.sec + +


interval.atEnd.sec = dwMsec/1000L; = (UINT)(dwMsec % 1000L);

// Call Pen API function to add interval to inkset

AddInksetInterval( hinkset, (LPINTERVAL) &interval );



return (hinkset);


Software for developers
Delphi Components
.Net Components
Software for Android Developers
More information resources
Unix Manual Pages
Delphi Examples