Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

768 lines
24 KiB

#include "hwxobj.h"
#include "memmgr.h"
#include "hwxfe.h" //980803:ToshiaK
#include "dbg.h"
#include "cmnhdr.h"
#ifdef UNDER_CE // Windows CE Stub for unsupported APIs
#include "stub_ce.h"
#endif // UNDER_CE
// implementation of CHwxThread, CHwxThreadMB, and CHwxThreadCAC
//----------------------------------------------------------------
//971217:ToshiaK: comment outed. changed to m_hHwxjpn as non static
//----------------------------------------------------------------
//HINSTANCE CHwxThread::m_hHwxjpn = NULL;
PHWXCONFIG CHwxThread::lpHwxConfig = NULL;
PHWXCREATE CHwxThread::lpHwxCreate = NULL;
PHWXSETCONTEXT CHwxThread::lpHwxSetContext = NULL;
PHWXSETGUIDE CHwxThread::lpHwxSetGuide = NULL;
PHWXALCVALID CHwxThread::lpHwxAlcValid = NULL;
PHWXSETPARTIAL CHwxThread::lpHwxSetPartial = NULL;
PHWXSETABORT CHwxThread::lpHwxSetAbort = NULL;
PHWXINPUT CHwxThread::lpHwxInput = NULL;
PHWXENDINPUT CHwxThread::lpHwxEndInput = NULL;
PHWXPROCESS CHwxThread::lpHwxProcess = NULL;
PHWXRESULTSAVAILABLE CHwxThread::lpHwxResultsAvailable = NULL;
PHWXGETRESULTS CHwxThread::lpHwxGetResults = NULL;
PHWXDESTROY CHwxThread::lpHwxDestroy = NULL;
CHwxThread::CHwxThread():CHwxObject(NULL)
{
m_thrdID = 0 ;
m_hThread = NULL ;
m_thrdArg = HWX_PARTIAL_ALL;
m_hStopEvent = NULL;
//----------------------------------------------------------------
//971217:ToshiaK changed m_hHwxjpn to non static data.
//so, Initialize it in Constructor.
//----------------------------------------------------------------
m_hHwxjpn = NULL;
}
CHwxThread::~CHwxThread()
{
Dbg(("CHwxThread::~CHwxThread START\n"));
// if ( IsThreadStarted() )
// {
//----------------------------------------------------------------
//970729: ToshiaK temporary, comment out.
//----------------------------------------------------------------
// StopThread();
// }
if ( m_hHwxjpn )
{
// decreament library ref count until it is equal to zero
FreeLibrary(m_hHwxjpn);
m_hHwxjpn = NULL;
}
if (m_hStopEvent)
{
CloseHandle(m_hStopEvent);
m_hStopEvent = NULL;
}
}
BOOL CHwxThread::Initialize(TCHAR * pClsName)
{
BOOL bRet = CHwxObject::Initialize(pClsName);
if ( bRet )
{
TCHAR tchPath[MAX_PATH];
//TCHAR tchMod[32];
//----------------------------------------------------------------
//980803:ToshiaK. Fareast merge.
//----------------------------------------------------------------
CHwxFE::GetRecognizerFileName(m_hInstance,
tchPath,
sizeof(tchPath)/sizeof(tchPath[0]));
//OutputDebugString("hwxthd\n");
//OutputDebugString(tchPath);
//OutputDebugString("\n");
//lstrcat(tchPath, tchMod);
if ( !m_hHwxjpn )
{
// first time load
//OutputDebugString(tchPath);
m_hHwxjpn = LoadLibrary(tchPath);
//m_hHwxjpn = LoadLibrary(TEXT("hwxjpn.dll"));
if ( m_hHwxjpn )
{
// get HwxXXXXX() API address from hwxjpn.dll
#ifndef UNDER_CE
lpHwxConfig =(PHWXCONFIG)GetProcAddress(m_hHwxjpn,"HwxConfig");
lpHwxCreate= (PHWXCREATE)GetProcAddress(m_hHwxjpn,"HwxCreate");
lpHwxSetContext= (PHWXSETCONTEXT)GetProcAddress(m_hHwxjpn,"HwxSetContext");
lpHwxSetGuide= (PHWXSETGUIDE)GetProcAddress(m_hHwxjpn,"HwxSetGuide");
lpHwxAlcValid= (PHWXALCVALID)GetProcAddress(m_hHwxjpn,"HwxALCValid");
lpHwxSetPartial= (PHWXSETPARTIAL)GetProcAddress(m_hHwxjpn,"HwxSetPartial");
lpHwxSetAbort= (PHWXSETABORT)GetProcAddress(m_hHwxjpn,"HwxSetAbort");
lpHwxInput= (PHWXINPUT)GetProcAddress(m_hHwxjpn,"HwxInput");
lpHwxEndInput= (PHWXENDINPUT)GetProcAddress(m_hHwxjpn,"HwxEndInput");
lpHwxProcess= (PHWXPROCESS)GetProcAddress(m_hHwxjpn,"HwxProcess");
lpHwxResultsAvailable= (PHWXRESULTSAVAILABLE)GetProcAddress(m_hHwxjpn,"HwxResultsAvailable");
lpHwxGetResults= (PHWXGETRESULTS)GetProcAddress(m_hHwxjpn,"HwxGetResults");
lpHwxDestroy= (PHWXDESTROY)GetProcAddress(m_hHwxjpn,"HwxDestroy");
#else // UNDER_CE
lpHwxConfig =(PHWXCONFIG)GetProcAddress(m_hHwxjpn,TEXT("HwxConfig"));
lpHwxCreate= (PHWXCREATE)GetProcAddress(m_hHwxjpn,TEXT("HwxCreate"));
lpHwxSetContext= (PHWXSETCONTEXT)GetProcAddress(m_hHwxjpn,TEXT("HwxSetContext"));
lpHwxSetGuide= (PHWXSETGUIDE)GetProcAddress(m_hHwxjpn,TEXT("HwxSetGuide"));
lpHwxAlcValid= (PHWXALCVALID)GetProcAddress(m_hHwxjpn,TEXT("HwxALCValid"));
lpHwxSetPartial= (PHWXSETPARTIAL)GetProcAddress(m_hHwxjpn,TEXT("HwxSetPartial"));
lpHwxSetAbort= (PHWXSETABORT)GetProcAddress(m_hHwxjpn,TEXT("HwxSetAbort"));
lpHwxInput= (PHWXINPUT)GetProcAddress(m_hHwxjpn,TEXT("HwxInput"));
lpHwxEndInput= (PHWXENDINPUT)GetProcAddress(m_hHwxjpn,TEXT("HwxEndInput"));
lpHwxProcess= (PHWXPROCESS)GetProcAddress(m_hHwxjpn,TEXT("HwxProcess"));
lpHwxResultsAvailable= (PHWXRESULTSAVAILABLE)GetProcAddress(m_hHwxjpn,TEXT("HwxResultsAvailable"));
lpHwxGetResults= (PHWXGETRESULTS)GetProcAddress(m_hHwxjpn,TEXT("HwxGetResults"));
lpHwxDestroy= (PHWXDESTROY)GetProcAddress(m_hHwxjpn,TEXT("HwxDestroy"));
#endif // UNDER_CE
if ( !lpHwxConfig || !lpHwxCreate || !lpHwxSetContext ||
!lpHwxSetGuide || !lpHwxAlcValid || !lpHwxSetPartial ||
!lpHwxSetAbort || !lpHwxInput || !lpHwxEndInput ||
!lpHwxProcess || !lpHwxResultsAvailable || !lpHwxGetResults ||
!lpHwxDestroy )
{
FreeLibrary(m_hHwxjpn);
m_hHwxjpn = NULL;
bRet = FALSE;
}
else
{
(*lpHwxConfig)();
}
}
else
{
bRet = FALSE;
}
}
}
if ( bRet && m_hHwxjpn && !IsThreadStarted() )
{
bRet = StartThread();
}
return bRet;
}
BOOL CHwxThread::StartThread()
{
BOOL bRet = FALSE;
if ( !(m_hStopEvent = CreateEvent(NULL,FALSE,FALSE,NULL)) )
return bRet;
m_Quit = FALSE;
#ifndef UNDER_CE // Windows CE does not support THREAD_QUERY_INFORMATION
m_hThread = CreateThread(NULL, 0, RealThreadProc, (void *)this, THREAD_QUERY_INFORMATION, &m_thrdID);
#else // UNDER_CE
m_hThread = CreateThread(NULL, 0, RealThreadProc, (void *)this, 0, &m_thrdID);
#endif // UNDER_CE
if ( m_hThread )
{
if ( IsMyHwxCls(TEXT("CHwxThreadCAC")) )
{
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
// SetThreadPriority(m_hThread, THREAD_PRIORITY_BELOW_NORMAL);
SetThreadPriority(m_hThread, THREAD_PRIORITY_LOWEST);
}
bRet = TRUE;
}
return bRet;
}
void CHwxThread::StopThread()
{
Dbg(("StopThread START\n"));
DWORD dwReturn = 0;
if ( m_hThread && IsMyHwxCls(TEXT("CHwxThreadCAC")) )
{
//----------------------------------------------------------------
//980817:ToshiaK.Removed SetPriorityClass() line.
//This is very dangerous code, because we don't know what applicatin
//does about Priority.
//In KK's case, In WordPerfect, if we use SetPriorityClass(),
//WordPerfect never quit. I don't know why Li-zhang wrote this line.
//Anyway, it should be removed.
//----------------------------------------------------------------
//SetPriorityClass(GetCurrentProcess(),REALTIME_PRIORITY_CLASS);
SetThreadPriority(m_hThread, THREAD_PRIORITY_HIGHEST);
}
if (m_hThread &&
GetExitCodeThread(m_hThread,&dwReturn) &&
STILL_ACTIVE == dwReturn )
{
INT ret, i;
ret = PostThreadMessage(m_thrdID, THRDMSG_EXIT, 0, 0);
for(i = 0; i < 100; i++) {
Sleep(100);
if(m_Quit) {
//OutputDebugString("Thread END\n");
Dbg(("Thread Quit\n"));
break;
}
}
m_hThread = NULL;
//----------------------------------------------------------------
//971202:By Toshiak. Do not use WaitForSigleObject() to syncronize
//----------------------------------------------------------------
#ifdef RAID_2926
PostThreadMessage(m_thrdID, THRDMSG_EXIT, 0,0);
WaitForSingleObject(m_hStopEvent,INFINITE);
m_hThread = NULL ;
#endif
}
Dbg(("StopThread End\n"));
}
DWORD WINAPI CHwxThread::RealThreadProc(void * pv)
{
CHwxThread * pCHwxThread = reinterpret_cast<CHwxThread*>(pv);
return pCHwxThread->ClassThreadProc() ;
}
DWORD CHwxThread::ClassThreadProc()
{
return RecognizeThread(m_thrdArg);
}
CHwxThreadMB::CHwxThreadMB(CHwxMB * pMB,int nSize)
{
m_pMB = pMB;
#ifdef FE_CHINESE_SIMPLIFIED
m_recogMask = ALC_CHS_EXTENDED;
#elif FE_KOREAN
m_recogMask = ALC_KOR_EXTENDED;
#else
m_recogMask = ALC_JPN_EXTENDED;
#endif
m_prevChar = INVALID_CHAR;
m_hrcActive = NULL;
m_giSent = 0;
m_bDirty = FALSE;
m_guide.xOrigin = 0;
m_guide.yOrigin = 0;
m_guide.cxBox = nSize << 3;
m_guide.cyBox = nSize << 3;
// m_guide.cxBase = 0;
m_guide.cyBase = nSize << 3;
m_guide.cHorzBox = 256;
m_guide.cVertBox = 1;
m_guide.cyMid = nSize << 3;
m_guide.cxOffset = 0;
m_guide.cyOffset = 0;
m_guide.cxWriting = nSize << 3;
m_guide.cyWriting = nSize << 3;
m_guide.nDir = HWX_HORIZONTAL;
}
CHwxThreadMB::~CHwxThreadMB()
{
m_pMB = NULL;
}
BOOL CHwxThreadMB::Initialize(TCHAR * pClsName)
{
return CHwxThread::Initialize(pClsName);
}
DWORD CHwxThreadMB::RecognizeThread(DWORD dummy)
{
MSG msg;
int count;
// Now we are sitting in our message loop to wait for
// the message sent by the main thread
while (1)
{
if (!m_bDirty)
{
GetMessage(&msg, NULL, 0, 0);
}
else
{
if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
m_bDirty = FALSE;
(*lpHwxProcess)(m_hrcActive);
count = (*lpHwxResultsAvailable)(m_hrcActive);
if (count > m_giSent)
{
GetCharacters(m_giSent, count);
m_giSent = count;
}
continue;
}
}
if (!HandleThreadMsg(&msg))
{
//SetEvent(m_hStopEvent);
m_Quit = TRUE;
return 0;
}
}
m_Quit = TRUE;
Unref(dummy);
}
void CHwxThreadMB::GetCharacters(int iSentAlready, int iReady)
{
HWXRESULTPRI *pResult, *pHead;
HWXRESULTS *pBox;
int iIndex;
int count = iReady - iSentAlready;
pBox = (HWXRESULTS *)MemAlloc(count * (sizeof(HWXRESULTS) + (MB_NUM_CANDIDATES - 1)*sizeof(WCHAR)));
if (pBox)
{
iIndex = (*lpHwxGetResults)(m_hrcActive, MB_NUM_CANDIDATES, iSentAlready, count, pBox);
pHead = NULL;
for (iIndex = count - 1; iIndex >= 0; iIndex--)
{
// Index to the correct box results structure.
HWXRESULTS *pBoxCur = (HWXRESULTS *) (((char *) pBox) +
(iIndex *
(sizeof(HWXRESULTS) +
(MB_NUM_CANDIDATES - 1) * sizeof(WCHAR))));
pResult = GetCandidates(pBoxCur);
if (pResult == NULL)
{
break;
}
pResult->pNext = pHead;
pHead = pResult;
}
MemFree((void *)pBox);
// Call back to the main thread to dispatch the BOXRESULTS
if (pHead)
{
PostMessage(m_pMB->GetMBWindow(), MB_WM_HWXCHAR, (WPARAM)pHead, 0);
}
}
}
//////////////////////////////////////////////////////////////////
// Function : CHwxThreadMB::HandleThreadMsg
// Type : BOOL
// Purpose :
// Args :
// : MSG * pMsg
// Return :
// DATE : Fri Oct 06 20:45:37 2000
// Histroy : 00/10/07: for Satori #2471.
// It's very difficult bug.
// Old code are following..
//
// switch(pMsg->message){
// :
// case THRDMSG_EXIT:
// default:
// return FALSE;
// }
// if HandlThreadMsg() receive unknown message,
// it always return False, then Thread quits!!!!.
// In Cicero environment, somebody post unkonwn message,
// to this Thread ID, when IMM IME is switched to Another IMM IME.
// IMEPad uses AttachThreadInput() attached application process's thread ID,
// Message is duplicated and HW thread receive this illegal
// message ID.
// So, I changed to return TRUE if HW thread receive unkonwn message
//
// switch(pMsg->message){
// :
// case THRDMSG_EXIT:
// return FALSE;
// default:
// return TRUE;
// }
//
//////////////////////////////////////////////////////////////////
BOOL CHwxThreadMB::HandleThreadMsg(MSG *pMsg)
{
PSTROKE pstr;
int iIndex;
int count;
switch (pMsg->message)
{
case THRDMSG_ADDINK:
pstr = (PSTROKE) pMsg->lParam;
if (!pstr)
return TRUE;
if (m_hrcActive == NULL)
{
m_giSent = 0;
m_hrcActive = (*lpHwxCreate)((HRC)NULL);
if (m_hrcActive == NULL)
return TRUE;
m_guide.cxBox = m_guide.cyBox = m_guide.cyBase = pMsg->wParam << 3;
m_guide.cyMid = m_guide.cxWriting = m_guide.cyWriting = pMsg->wParam << 3;
(*lpHwxSetGuide)(m_hrcActive, &m_guide);
// Setup the ALC mask everytime we do recognization
(*lpHwxAlcValid)(m_hrcActive, m_recogMask);
// Setup the context information if we have a valid prevChar
if (m_prevChar != INVALID_CHAR)
{
WCHAR ctxtChar;
// Get the correct context
if( FoldStringW(MAP_FOLDCZONE, &m_prevChar, 1, &ctxtChar, 1) )
{
(*lpHwxSetContext)(m_hrcActive, ctxtChar);
}
}
}
count = (pstr->iBox * pMsg->wParam) << 3; // Compute the offset for the box logically.
for (iIndex = 0; iIndex < pstr->cpt; iIndex++)
{
pstr->apt[iIndex].x = ((pstr->apt[iIndex].x - pstr->xLeft) << 3) + count;
pstr->apt[iIndex].y = (pstr->apt[iIndex].y << 3);
}
(*lpHwxInput)(m_hrcActive, pstr->apt,pstr->cpt,0);
MemFree((void *)pstr);
m_bDirty = TRUE;
return TRUE;
case THRDMSG_RECOGNIZE:
if (m_hrcActive == NULL)
{
return(TRUE);
}
(*lpHwxEndInput)(m_hrcActive);
(*lpHwxProcess)(m_hrcActive);
//
// We only get back the top 6 candidates.
//
count = pMsg->wParam; // # of boxes written in is sent here.
if (count > m_giSent)
{
GetCharacters(m_giSent, count);
m_giSent = count;
}
(*lpHwxDestroy)(m_hrcActive);
m_bDirty = FALSE;
m_hrcActive = NULL;
return TRUE;
// case THRDMSG_CHAR:
// PostMessage(m_pMB->GetMBWindow(), MB_WM_COMCHAR, pMsg->wParam, 0);
// return TRUE;
case THRDMSG_SETMASK:
m_recogMask = pMsg->wParam;
return TRUE;
case THRDMSG_SETCONTEXT:
m_prevChar = (WCHAR) pMsg->wParam;
return TRUE;
case THRDMSG_EXIT:
default:
//----------------------------------------------------------------
//Satori #2471:return TRUE not to quit thread accicentaly.
//----------------------------------------------------------------
return TRUE;
}
}
HWXRESULTPRI * CHwxThreadMB::GetCandidates(HWXRESULTS *pbox)
{
HWXRESULTPRI *pResult;
int i;
pResult = (HWXRESULTPRI *)MemAlloc(sizeof(HWXRESULTPRI));
if (!pResult)
return NULL;
pResult->pNext = NULL;
for ( i=0; i<MB_NUM_CANDIDATES; i++ )
{
pResult->chCandidate[i] = pbox->rgChar[i];
if ( !pbox->rgChar[i] )
break;
}
pResult->cbCount = (USHORT)i;
pResult->iSelection = 0;
return pResult;
}
CHwxThreadCAC::CHwxThreadCAC(CHwxCAC * pCAC)
{
m_pCAC = pCAC;
}
CHwxThreadCAC::~CHwxThreadCAC()
{
m_pCAC = NULL;
}
BOOL CHwxThreadCAC::Initialize(TCHAR * pClsName)
{
return CHwxThread::Initialize(pClsName);
}
DWORD CHwxThreadCAC::RecognizeThread(DWORD dwPart)
{
MSG msg;
//UINT nPartial = dwPart;
HRC hrc;
HWXGUIDE guide;
BOOL bRecog;
DWORD cstr;
STROKE *pstr;
// Create the initial hrc for this thread, set the recognition paramters.
hrc = (*lpHwxCreate)((HRC) NULL);
if ( !hrc )
return 0;
guide.xOrigin = 0;
guide.yOrigin = 0;
guide.cxBox = 1000;
guide.cyBox = 1000;
// guide.cxBase = 0;
guide.cyBase = 1000;
guide.cHorzBox = 1;
guide.cVertBox = 1;
guide.cyMid = 1000;
guide.cxOffset = 0;
guide.cyOffset = 0;
guide.cxWriting = 1000;
guide.cyWriting = 1000;
guide.nDir = HWX_HORIZONTAL;
(*lpHwxSetGuide)(hrc, &guide); // Set the guide
// (*lpHwxSetPartial)(hrc, nPartial); // Set the recognition type
(*lpHwxSetAbort)(hrc,(UINT *)m_pCAC->GetStrokeCountAddress()); // Set the abort address
// Begin the message loop
while (TRUE)
{
bRecog = FALSE;
// Wait until we're told to recognize.
if(GetMessage(&msg, NULL, 0, 0) == FALSE)
{
if ( hrc )
(*lpHwxDestroy)(hrc);
hrc = NULL;
//971202: removed by Toshiak
//SetEvent(m_hStopEvent);
m_Quit = TRUE;
Dbg(("Recognize Thread END\n"));
return 0;
}
// We'll eat all the incoming messages
do
{
switch (msg.message)
{
case THRDMSG_SETGUIDE:
guide.cxBox = msg.wParam;
guide.cyBox = msg.wParam;
guide.cyBase = msg.wParam;
guide.cyMid = msg.wParam;
guide.cxWriting = msg.wParam;
guide.cyWriting = msg.wParam;
(*lpHwxSetGuide)(hrc, &guide); // Set the guide
break;
case THRDMSG_RECOGNIZE:
bRecog = TRUE;
break;
case THRDMSG_EXIT:
if ( hrc )
(*lpHwxDestroy)(hrc);
hrc = NULL;
//971202: removed by ToshiaK
//SetEvent(m_hStopEvent);
m_Quit = TRUE;
Dbg(("Recognize Thread END\n"));
return 0;
default:
break;
}
} while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE));
// Was there a message to recognize?
if (!bRecog)
continue;
bRecog = FALSE;
// Count the number of valid strokes
cstr = 0;
pstr = m_pCAC->GetStrokePointer();
while (pstr)
{
cstr++;
pstr = pstr->pNext;
}
// If the available stroke count doesn't match the actual stroke count, exit
if ((cstr != (DWORD)m_pCAC->GetStrokeCount()) || (!cstr))
{
continue;
}
recoghelper(hrc,HWX_PARTIAL_ALL,cstr);
recoghelper(hrc,HWX_PARTIAL_ORDER,cstr);
recoghelper(hrc,HWX_PARTIAL_FREE,cstr);
}
m_Quit = TRUE;
Unref(dwPart);
}
void CHwxThreadCAC::recoghelper(HRC hrc,DWORD dwPart,DWORD cstr)
{
UINT nPartial = dwPart;
HRC hrcTmp;
DWORD dwTick;
HWXRESULTS *pbox;
int ires;
STROKE *pstr;
int nSize = dwPart != HWX_PARTIAL_ALL ? PREFIXLIST : FULLLIST;
pbox = (HWXRESULTS *)MemAlloc(sizeof(HWXRESULTS) + nSize * sizeof(WCHAR));
if ( !pbox )
{
return;
}
hrcTmp = (*lpHwxCreate)(hrc);
(*lpHwxSetPartial)(hrcTmp, nPartial); // Set the recognition type
// (*lpHwxSetAbort)(hrcTmp,(UINT *)m_pCAC->GetStrokeCountAddress()); // Set the abort address
pstr = m_pCAC->GetStrokePointer();
dwTick = 0;
while (pstr)
{
dwTick +=3641L;
(*lpHwxInput)(hrcTmp, pstr->apt,pstr->cpt, dwTick);
pstr = pstr->pNext;
}
memset(pbox, '\0', sizeof(HWXRESULTS) + nSize * sizeof(WCHAR));
// Call the recognizer for results
(*lpHwxEndInput)(hrcTmp);
(*lpHwxProcess)(hrcTmp);
(*lpHwxGetResults)(hrcTmp, nSize, 0, 1, pbox);
(*lpHwxDestroy)(hrcTmp);
// Return the results
ires = 0;
while (pbox->rgChar[ires])
{
if (cstr != (DWORD)m_pCAC->GetStrokeCount())
break;
SendMessage(m_pCAC->GetCACWindow(), CAC_WM_RESULT, (nPartial << 8) | cstr, MAKELPARAM((pbox->rgChar[ires]), ires));
ires++;
}
MemFree((void *)pbox);
if ( ires )
{
SendMessage(m_pCAC->GetCACWindow(), CAC_WM_SHOWRESULT,0,0);
}
}
void CHwxThreadCAC::RecognizeNoThread(int nSize)
{
HRC hrc;
HWXGUIDE guide;
STROKE *pstr;
long numstrk = 0;
if (( pstr = m_pCAC->GetStrokePointer()) == (STROKE *) NULL)
return;
// Create the initial hrc for this thread, set the recognition paramters.
hrc = (*lpHwxCreate)((HRC) NULL);
if ( !hrc )
return;
guide.xOrigin = 0;
guide.yOrigin = 0;
guide.cxBox = nSize;
guide.cyBox = nSize;
// guide.cxBase = 0;
guide.cyBase = nSize;
guide.cHorzBox = 1;
guide.cVertBox = 1;
guide.cyMid = 0;
guide.cxOffset = 0;
guide.cyOffset = 0;
guide.cxWriting = nSize;
guide.cyWriting = nSize;
guide.nDir = HWX_HORIZONTAL;
(*lpHwxSetGuide)(hrc, &guide); // Set the guide
// (*lpHwxSetPartial)(hrc,HWX_PARTIAL_ALL); // Set the recognition type
(*lpHwxSetAbort)(hrc,(UINT *)m_pCAC->GetStrokeCountAddress());
numstrk = m_pCAC->GetStrokeCount();
recoghelper(hrc,HWX_PARTIAL_ALL,numstrk);
recoghelper(hrc,HWX_PARTIAL_ORDER,numstrk);
// recoghelper(hrc,HWX_PARTIAL_FREE,numstrk);
(*lpHwxDestroy)(hrc);
}