1288 lines
36 KiB
C++
1288 lines
36 KiB
C++
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
// PARTICULAR PURPOSE.
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
// This recognizer implementation illustrates essentials of
|
|
// loading a recognizer DLL, obtaining ink strokes
|
|
// to recognize, and returning a recognition result.
|
|
|
|
#include "stdafx.h"
|
|
#include <assert.h>
|
|
#include <Strsafe.h>
|
|
#include <Objbase.h>
|
|
|
|
#include "Limits.h"
|
|
#include "RecApis.h"
|
|
#include "tpcError.h"
|
|
|
|
#include "RecoDll.h"
|
|
|
|
|
|
static void DestroyLattice( RECO_LATTICE *pLattice );
|
|
static HRESULT GetRecoAttributesHelper(HINSTANCE hDllInstance, RECO_ATTRS* pRecoAttrs);
|
|
|
|
static const GUID s_guid_x = { 0x598a6a8f, 0x52c0, 0x4ba0, { 0x93, 0xaf, 0xaf, 0x35, 0x74, 0x11, 0xa5, 0x61 } };
|
|
static const GUID s_guid_y = { 0xb53f9f75, 0x04e0, 0x4498, { 0xa7, 0xee, 0xc3, 0x0d, 0xbb, 0x5a, 0x90, 0x11 } };
|
|
static const PROPERTY_METRICS s_DefaultPropMetrics = { LONG_MIN, LONG_MAX, PROPERTY_UNITS_CENTIMETERS, 1000.0 };
|
|
|
|
|
|
static LPCWSTR TPG_REGPATH = L"Software\\Microsoft\\TPG";
|
|
static LPCWSTR RECOGNIZER_REGPATH = L"Software\\Microsoft\\TPG\\Recognizers";
|
|
static LPCWSTR MY_RECO_REGKEY = L"Software\\Microsoft\\TPG\\Recognizers\\" MY_RECO_GUID;
|
|
|
|
static LPCWSTR RECO_DLL_REGVALNAME = L"Recognizer dll";
|
|
static LPCWSTR RECO_LANGUAGES_REGVALNAME = L"Recognized Languages";
|
|
static LPCWSTR RECO_CAPABILITIES_REGVALNAME = L"Recognizer Capability Flags";
|
|
|
|
static HINSTANCE s_hDllInstance = NULL;
|
|
|
|
struct MY_RECOGNIZER
|
|
{
|
|
// Store runtime data here that your algorithm uses for recognizing ink.
|
|
GUID RecoGuid;
|
|
};
|
|
|
|
|
|
#define MAX_RESULT_CHARS 200
|
|
#define MAX_STROKES_IN_CONTEXT 50000
|
|
#define MAX_POINTS_IN_STROKE 100000
|
|
|
|
struct MY_STROKE
|
|
{
|
|
MY_STROKE *pNext;
|
|
ULONG cPoints; // number of points in the stroke
|
|
__field_ecount_full(cPoints)
|
|
POINT *aPoints; // array of x-y points in the stroke
|
|
};
|
|
|
|
struct MY_RECOCONTEXT
|
|
{
|
|
MY_RECOGNIZER *pRecognizer; // recognizer to use on pStrokeList
|
|
RECO_GUIDE *pGuide; // reference boundaries for strokes
|
|
ULONG uiGuideIndex; // set but not used (obsolete)
|
|
ULONG cStrokes; // Number of ink strokes added
|
|
ULONG cPointsTot; // number of x-y points in all strokes
|
|
MY_STROKE *pStrokeList; // new strokes are inserted at head of list
|
|
WCHAR wzBestResult[MAX_RESULT_CHARS]; // reco result based on the stroke list
|
|
RECO_LATTICE *pLattice; // mapping of reco result to strokes
|
|
};
|
|
|
|
|
|
BOOL APIENTRY DllMain( HANDLE hModule,
|
|
DWORD ul_reason_for_call,
|
|
void* lpReserved
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(lpReserved);
|
|
switch (ul_reason_for_call)
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
s_hDllInstance = (HINSTANCE) hModule;
|
|
break;
|
|
case DLL_THREAD_ATTACH:
|
|
case DLL_THREAD_DETACH:
|
|
case DLL_PROCESS_DETACH:
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// DllRegisterServer - Adds entries to the system registry
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
STDAPI DllRegisterServer(void)
|
|
{
|
|
LONG lRes = 0;
|
|
HKEY hkeyMyReco;
|
|
DWORD dwLength = 0;
|
|
DWORD dwDisposition;
|
|
WCHAR wzRecognizerPath[MAX_PATH];
|
|
HRESULT hr = S_OK;
|
|
RECO_ATTRS recoAttr;
|
|
|
|
// Write the path to this dll in the registry under
|
|
// the recognizer subkey
|
|
|
|
// Wipe out the previous values
|
|
RegDeleteKeyW(HKEY_LOCAL_MACHINE, MY_RECO_REGKEY);
|
|
// Create the new key
|
|
lRes = RegCreateKeyExW(HKEY_LOCAL_MACHINE, MY_RECO_REGKEY, 0, NULL,
|
|
REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkeyMyReco, &dwDisposition);
|
|
assert(lRes == ERROR_SUCCESS && "Can't write registry");
|
|
if (lRes != ERROR_SUCCESS)
|
|
{
|
|
RegCloseKey(hkeyMyReco);
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
// Get the Reco DLL's full pathname and write it to the registry
|
|
dwLength = GetModuleFileNameW((HMODULE)s_hDllInstance, wzRecognizerPath, MAX_PATH);
|
|
lRes = RegSetValueExW(hkeyMyReco, RECO_DLL_REGVALNAME, NULL, REG_SZ,
|
|
(BYTE*)wzRecognizerPath, sizeof(WCHAR)*dwLength);
|
|
assert(lRes == ERROR_SUCCESS && "Can't write registry");
|
|
if (lRes != ERROR_SUCCESS)
|
|
{
|
|
RegCloseKey(hkeyMyReco);
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
// Get the Reco attributes from the DLL and write them to registry
|
|
hr = GetRecoAttributesHelper(s_hDllInstance, &recoAttr);
|
|
if (FAILED(hr))
|
|
{
|
|
RegCloseKey(hkeyMyReco);
|
|
return E_UNEXPECTED;
|
|
}
|
|
lRes = RegSetValueExW(hkeyMyReco, RECO_LANGUAGES_REGVALNAME, 0, REG_BINARY,
|
|
(BYTE*)recoAttr.awLanguageId, 64 * sizeof(WORD));
|
|
assert(lRes == ERROR_SUCCESS);
|
|
if (lRes != ERROR_SUCCESS)
|
|
{
|
|
RegCloseKey(hkeyMyReco);
|
|
return E_UNEXPECTED;
|
|
}
|
|
lRes = RegSetValueExW(hkeyMyReco, RECO_CAPABILITIES_REGVALNAME, 0, REG_DWORD,
|
|
(BYTE*)&(recoAttr.dwRecoCapabilityFlags), sizeof(DWORD));
|
|
assert(lRes == ERROR_SUCCESS);
|
|
if (lRes != ERROR_SUCCESS)
|
|
{
|
|
RegCloseKey(hkeyMyReco);
|
|
return E_UNEXPECTED;
|
|
}
|
|
RegCloseKey(hkeyMyReco);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// DllUnregisterServer - Removes entries from the system registry
|
|
|
|
STDAPI DllUnregisterServer(void)
|
|
{
|
|
LONG lRes1 = 0;
|
|
|
|
// Wipe out the registry information
|
|
lRes1 = RegDeleteKeyW(HKEY_LOCAL_MACHINE, MY_RECO_REGKEY);
|
|
|
|
// Delete our parent keys if they contain no remaining subkeys
|
|
// (don't care if these fail)
|
|
RegDeleteKeyW(HKEY_LOCAL_MACHINE, RECOGNIZER_REGPATH);
|
|
RegDeleteKeyW(HKEY_LOCAL_MACHINE, TPG_REGPATH);
|
|
|
|
if (lRes1 != ERROR_SUCCESS && lRes1 != ERROR_FILE_NOT_FOUND)
|
|
{
|
|
return E_UNEXPECTED;
|
|
}
|
|
return S_OK ;
|
|
}
|
|
|
|
static BOOL IsResourceMatchClsId(REFCLSID pCLSID, HINSTANCE hDll)
|
|
{
|
|
// Make sure this GUID matches the one the DLL was built with.
|
|
WCHAR awcRecoGUID[ARRAYSIZE(MY_RECO_GUID)];
|
|
LPOLESTR pszCLSID = NULL;
|
|
BOOL bRet = FALSE;
|
|
|
|
if (NULL == hDll)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// convert the passed CLSID to a str
|
|
if (!SUCCEEDED(StringFromCLSID(pCLSID, &pszCLSID)))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// load the recognizer's GUID string from resources and compare it with the passed argument
|
|
if (!LoadStringW (hDll, RESID_MY_RECO_GUID, awcRecoGUID, ARRAYSIZE(awcRecoGUID)) )
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
if (0 == _wcsicmp (pszCLSID, awcRecoGUID))
|
|
{
|
|
// Clsid matches
|
|
bRet = TRUE;
|
|
}
|
|
|
|
exit:
|
|
if (NULL != pszCLSID)
|
|
{
|
|
CoTaskMemFree (pszCLSID);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
////////////////////////
|
|
// IRecognizer
|
|
////////////////////////
|
|
HRESULT WINAPI CreateRecognizer(CLSID *pCLSID, HRECOGNIZER *phrec)
|
|
{
|
|
// Initialize a recognizer. Our example requires no special action here.
|
|
// A more elaborate example might require loading of data to assist
|
|
// with recognition.
|
|
|
|
if( !pCLSID )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
if( !s_hDllInstance )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
if( !IsResourceMatchClsId((REFCLSID)*pCLSID, s_hDllInstance) )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
MY_RECOGNIZER *pRec = new MY_RECOGNIZER;
|
|
if( !pRec )
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
pRec->RecoGuid = *pCLSID;
|
|
*phrec = (HRECOGNIZER) pRec;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT WINAPI DestroyRecognizer(HRECOGNIZER hrec)
|
|
{
|
|
if( !hrec )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
delete (MY_RECOGNIZER*) hrec;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT GetRecoAttributesHelper(HINSTANCE hDllInstance, RECO_ATTRS* pRecoAttrs)
|
|
{
|
|
|
|
HRSRC hrsrc = NULL;
|
|
HGLOBAL hg = NULL;
|
|
LPBYTE pv = NULL;
|
|
DWORD dwRecoCapabilityFlags;
|
|
WORD wLanguageCount;
|
|
WORD iLang;
|
|
|
|
if (!pRecoAttrs)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
if( !hDllInstance )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
// Initialize the Reco Attribute structure
|
|
ZeroMemory(pRecoAttrs, sizeof(RECO_ATTRS));
|
|
|
|
// Load the recognizer friendly name
|
|
if (0 == LoadStringW(s_hDllInstance, // handle to resource module
|
|
RESID_MY_FRIENDLYNAME, // resource identifier
|
|
pRecoAttrs->awcFriendlyName, // resource buffer
|
|
ARRAYSIZE(pRecoAttrs->awcFriendlyName) // size of buffer
|
|
))
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
// Load the recognizer vendor name
|
|
if (0 == LoadStringW(s_hDllInstance, // handle to resource module
|
|
RESID_MY_VENDORNAME, // resource identifier
|
|
pRecoAttrs->awcVendorName, // resource buffer
|
|
ARRAYSIZE(pRecoAttrs->awcVendorName) // size of buffer
|
|
))
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
// Load the resources
|
|
hrsrc = FindResource(s_hDllInstance, // module handle
|
|
MAKEINTRESOURCE(RESID_MY_RECO_INFO), // resource name
|
|
RT_RCDATA // resource type
|
|
);
|
|
if (NULL == hrsrc)
|
|
{
|
|
// The resource is not found!
|
|
return E_FAIL;
|
|
}
|
|
hg = LoadResource(
|
|
s_hDllInstance, // module handle
|
|
hrsrc // resource handle
|
|
);
|
|
if (NULL == hg)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
pv = (LPBYTE)LockResource(
|
|
hg // handle to resource
|
|
);
|
|
if (NULL == pv)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
dwRecoCapabilityFlags = *((DWORD*)pv);
|
|
pv += sizeof(dwRecoCapabilityFlags);
|
|
|
|
wLanguageCount = *((WORD*)pv);
|
|
pv += sizeof(wLanguageCount);
|
|
|
|
// Fill the reco attribute structure for this recognizer
|
|
|
|
// Add the languages
|
|
if( wLanguageCount > MAX_LANGUAGES-1 )
|
|
{
|
|
wLanguageCount = MAX_LANGUAGES-1;
|
|
}
|
|
for (iLang = 0; iLang < wLanguageCount; iLang++)
|
|
{
|
|
WORD iLanguage, iSubLang;
|
|
|
|
iLanguage = *((WORD *)pv);
|
|
pv += sizeof (iLang);
|
|
|
|
iSubLang = *((WORD *)pv);
|
|
pv += sizeof (iSubLang);
|
|
|
|
pRecoAttrs->awLanguageId[iLang] = MAKELANGID((USHORT)iLanguage, (USHORT)iSubLang);
|
|
}
|
|
|
|
// End the list with a NULL
|
|
pRecoAttrs->awLanguageId[wLanguageCount] = 0;
|
|
|
|
pRecoAttrs->dwRecoCapabilityFlags = dwRecoCapabilityFlags;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT WINAPI GetRecoAttributes(HRECOGNIZER hrec, RECO_ATTRS* pRecoAttrs)
|
|
{
|
|
|
|
if (NULL == hrec)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
return GetRecoAttributesHelper( s_hDllInstance, pRecoAttrs);
|
|
}
|
|
|
|
|
|
HRESULT WINAPI CreateContext(HRECOGNIZER hrec, HRECOCONTEXT *phrc)
|
|
{
|
|
if( !hrec || !phrc )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
MY_RECOCONTEXT *pRC = new MY_RECOCONTEXT;
|
|
if( !pRC )
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
ZeroMemory( pRC, sizeof(MY_RECOCONTEXT) );
|
|
pRC->pRecognizer = (MY_RECOGNIZER*) hrec;
|
|
|
|
*phrc = (HRECOCONTEXT) pRC;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static void DestroyStrokeList( MY_STROKE *pStrokeList )
|
|
{
|
|
while( pStrokeList )
|
|
{
|
|
MY_STROKE *pStrokeToDelete = pStrokeList;
|
|
pStrokeList = pStrokeList->pNext;
|
|
if( pStrokeToDelete->aPoints )
|
|
{
|
|
delete [] pStrokeToDelete->aPoints;
|
|
}
|
|
delete pStrokeToDelete;
|
|
}
|
|
}
|
|
|
|
|
|
HRESULT WINAPI DestroyContext(HRECOCONTEXT hrc)
|
|
{
|
|
if( !hrc )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
MY_RECOCONTEXT *pRC = (MY_RECOCONTEXT *) hrc;
|
|
if( pRC->pGuide )
|
|
{
|
|
delete pRC->pGuide;
|
|
}
|
|
DestroyStrokeList( pRC->pStrokeList );
|
|
if( pRC->pLattice ) // The lattice contains dynamic data to free
|
|
{
|
|
DestroyLattice( pRC->pLattice );
|
|
}
|
|
ZeroMemory(pRC, sizeof(MY_RECOCONTEXT));
|
|
delete (MY_RECOCONTEXT *) hrc;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT WINAPI GetResultPropertyList(HRECOGNIZER hrec, ULONG* pPropertyCount, GUID*pPropertyGuid)
|
|
{
|
|
UNREFERENCED_PARAMETER(hrec);
|
|
UNREFERENCED_PARAMETER(pPropertyCount);
|
|
UNREFERENCED_PARAMETER(pPropertyGuid);
|
|
return E_NOTIMPL;
|
|
}
|
|
HRESULT WINAPI GetPreferredPacketDescription(HRECOGNIZER hrec, PACKET_DESCRIPTION* pPacketDescription)
|
|
{
|
|
if ( !pPacketDescription )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// We can be called with pPacketProperties
|
|
// equal to NULL, just to get the size of the buffers
|
|
|
|
if (pPacketDescription->pPacketProperties)
|
|
{
|
|
// Set the packet size to the size of x and y
|
|
pPacketDescription->cbPacketSize = 2 * sizeof(LONG);
|
|
|
|
// We are only setting 2 properties (X and Y)
|
|
if (pPacketDescription->cPacketProperties < 2)
|
|
{
|
|
return TPC_E_INSUFFICIENT_BUFFER;
|
|
}
|
|
pPacketDescription->cPacketProperties = 2;
|
|
|
|
// We are not setting buttons
|
|
pPacketDescription->cButtons = 0;
|
|
|
|
// Make sure that the pPacketProperties is of a valid size
|
|
if (!pPacketDescription->pPacketProperties )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
// Fill in pPacketProperties
|
|
// Add the GUID_X
|
|
pPacketDescription->pPacketProperties[0].guid = s_guid_x;
|
|
pPacketDescription->pPacketProperties[0].PropertyMetrics = s_DefaultPropMetrics;
|
|
|
|
// Add the GUID_Y
|
|
pPacketDescription->pPacketProperties[1].guid = s_guid_y;
|
|
pPacketDescription->pPacketProperties[1].PropertyMetrics = s_DefaultPropMetrics;
|
|
}
|
|
else
|
|
{
|
|
// Just fill in the PacketDescription structure leaving NULL
|
|
// pointers for the pguidButtons and pPacketProperies
|
|
|
|
// Set the packet size to the size of x and y
|
|
pPacketDescription->cbPacketSize = 2 * sizeof(LONG);
|
|
|
|
// We are only setting 2 properties (X and Y)
|
|
pPacketDescription->cPacketProperties = 2;
|
|
|
|
// We are not setting buttons
|
|
pPacketDescription->cButtons = 0;
|
|
|
|
// There are no guid buttons
|
|
pPacketDescription->pguidButtons = NULL;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT WINAPI GetUnicodeRanges(HRECOGNIZER hrec, ULONG *pcRanges, CHARACTER_RANGE *pcr)
|
|
{
|
|
UNREFERENCED_PARAMETER(hrec);
|
|
UNREFERENCED_PARAMETER(pcRanges);
|
|
UNREFERENCED_PARAMETER(pcr);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
////////////////////////
|
|
// IRecoContext
|
|
////////////////////////
|
|
|
|
|
|
static int RealToInt( double dVal )
|
|
{
|
|
return dVal<0.0 ? (int)(dVal-0.5) : (int)(dVal+0.5);
|
|
}
|
|
|
|
static void Transform(const XFORM *pXf, POINT * aPoints, ULONG cPoints)
|
|
{
|
|
// Transform POINT array in place
|
|
ULONG iPoint = 0;
|
|
LONG xp = 0;
|
|
|
|
if(NULL != pXf)
|
|
{
|
|
assert((cPoints == 0) || aPoints);
|
|
for(iPoint = 0; iPoint < cPoints; ++iPoint)
|
|
{
|
|
xp = RealToInt(aPoints[iPoint].x * pXf->eM11 + aPoints[iPoint].y * pXf->eM21 + pXf->eDx);
|
|
aPoints[iPoint].y = RealToInt(aPoints[iPoint].x * pXf->eM12 + aPoints[iPoint].y * pXf->eM22 + pXf->eDy);
|
|
aPoints[iPoint].x = xp;
|
|
}
|
|
}
|
|
}
|
|
|
|
HRESULT WINAPI AddStroke(HRECOCONTEXT hrc,
|
|
const PACKET_DESCRIPTION *pPacketDesc,
|
|
ULONG cbPacket, // I: Size of packet array (in BYTEs)
|
|
const BYTE *pPacket, // I: Array of packets
|
|
const XFORM *pXForm) // I: Transform to apply to each point
|
|
{
|
|
// Add a copy of the given stroke points to the reco context.
|
|
|
|
ULONG ulPacketSize; // Size of one packet (in LONGs)
|
|
ULONG cPoints; // number of points in the stroke
|
|
|
|
MY_RECOCONTEXT *pRC = (MY_RECOCONTEXT *) hrc;
|
|
|
|
if (NULL == pRC )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
if ( !pPacket || !cbPacket )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
if( MAX_STROKES_IN_CONTEXT <= pRC->cStrokes )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
//
|
|
// Get the number of packets (== number of points)
|
|
|
|
if (pPacketDesc)
|
|
{
|
|
if ( !pPacketDesc->cbPacketSize )
|
|
{
|
|
return TPC_E_INVALID_PACKET_DESCRIPTION;
|
|
}
|
|
if (pPacketDesc->cbPacketSize % sizeof(LONG) != 0)
|
|
{
|
|
return TPC_E_INVALID_PACKET_DESCRIPTION;
|
|
}
|
|
if (cbPacket % pPacketDesc->cbPacketSize != 0)
|
|
{
|
|
return TPC_E_INVALID_PACKET_DESCRIPTION;
|
|
}
|
|
ulPacketSize = pPacketDesc->cbPacketSize / sizeof(LONG);
|
|
cPoints = cbPacket / pPacketDesc->cbPacketSize;
|
|
if (ulPacketSize < 2) // Need 2+ values in a packet; i.e. X and Y
|
|
{
|
|
return TPC_E_INVALID_PACKET_DESCRIPTION;
|
|
}
|
|
}
|
|
else // Preferred packet description
|
|
{
|
|
if (cbPacket % (2 * sizeof(LONG)) != 0)
|
|
{
|
|
return TPC_E_INVALID_PACKET_DESCRIPTION;
|
|
}
|
|
ulPacketSize = 2;
|
|
cPoints = cbPacket / (2 * sizeof(LONG));
|
|
}
|
|
|
|
if (cPoints == 0) // Don't add strokes with 0 points
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
if( MAX_POINTS_IN_STROKE < cPoints )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
//
|
|
// Find the index (offset) in packet of GUID_X and GUID_Y
|
|
|
|
ULONG ulXIndex, ulYIndex;
|
|
if (pPacketDesc)
|
|
{
|
|
if (pPacketDesc->cPacketProperties < 2 || // Need 2+ properties
|
|
NULL == pPacketDesc->pPacketProperties) // Corrupted structure
|
|
{
|
|
assert(0); // This should never happen!
|
|
return TPC_E_INVALID_PACKET_DESCRIPTION;
|
|
}
|
|
BOOL bXFound = FALSE;
|
|
BOOL bYFound = FALSE;
|
|
for (ULONG ulIndex = 0; ulIndex < pPacketDesc->cPacketProperties; ulIndex++)
|
|
{
|
|
if (IsEqualGUID(pPacketDesc->pPacketProperties[ulIndex].guid, s_guid_x))
|
|
{
|
|
bXFound = TRUE;
|
|
ulXIndex = ulIndex;
|
|
}
|
|
else if (IsEqualGUID(pPacketDesc->pPacketProperties[ulIndex].guid, s_guid_y))
|
|
{
|
|
bYFound = TRUE;
|
|
ulYIndex = ulIndex;
|
|
}
|
|
if (bXFound && bYFound)
|
|
break;
|
|
}
|
|
if (!bXFound || !bYFound) // X- or Y-coordinates are
|
|
{ // not part of the packet!
|
|
return TPC_E_INVALID_PACKET_DESCRIPTION;
|
|
}
|
|
}
|
|
else // Preferred packet description
|
|
{
|
|
ulXIndex = 0;
|
|
ulYIndex = 1;
|
|
}
|
|
|
|
// Get ready to copy the ink points to MY_STROKE struct
|
|
MY_STROKE *pStroke = new MY_STROKE;
|
|
if( !pStroke )
|
|
{
|
|
goto OutOfMemory;
|
|
}
|
|
|
|
pStroke->aPoints = new POINT[cPoints];
|
|
if( !pStroke->aPoints )
|
|
{
|
|
goto OutOfMemory;
|
|
}
|
|
|
|
// Copy the points
|
|
POINT *pPoint = pStroke->aPoints;
|
|
const LONG *pLongs = (const LONG *)pPacket;
|
|
for( ULONG iPoint=0; iPoint<cPoints; iPoint++ )
|
|
{
|
|
pPoint->x = *(pLongs+ulXIndex);
|
|
pPoint->y = *(pLongs+ulYIndex);
|
|
pPoint++;
|
|
pLongs += ulPacketSize;
|
|
}
|
|
pStroke->cPoints = cPoints;
|
|
|
|
// Transform points from Tablet space to ink space
|
|
Transform(pXForm, pStroke->aPoints, cPoints);
|
|
|
|
// Insert the new stroke at front of the list
|
|
pStroke->pNext = pRC->pStrokeList;
|
|
pRC->pStrokeList = pStroke;
|
|
|
|
pRC->cStrokes++; // Update number of strokes
|
|
|
|
// Update number of points in all strokes.
|
|
// (We track this for our example. It is not essential.)
|
|
pRC->cPointsTot += cPoints;
|
|
|
|
return S_OK;
|
|
|
|
OutOfMemory:
|
|
if( pStroke )
|
|
{
|
|
if( pStroke->aPoints )
|
|
{
|
|
delete [] pStroke->aPoints;
|
|
}
|
|
delete pStroke;
|
|
}
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
|
|
HRESULT WINAPI GetBestResultString(HRECOCONTEXT hrc, __inout ULONG *pcTCH, __out_ecount_opt(*pcTCH) PTCH* pwcBestResult)
|
|
{
|
|
// Return the recognition result string that was computed in Process().
|
|
// Note: pwcBestResult does not include a NULL-terminator, nor does the
|
|
// buffer length count a NULL-terminator.
|
|
|
|
HRESULT hr = S_OK;
|
|
if( !hrc || !pcTCH )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
MY_RECOCONTEXT *pRC = (MY_RECOCONTEXT*) hrc;
|
|
|
|
if( !pRC->wzBestResult[0] ) // No reco result available
|
|
{
|
|
return TPC_E_NOT_RELEVANT;
|
|
}
|
|
|
|
ULONG cWChar = wcsnlen( pRC->wzBestResult, ARRAYSIZE(pRC->wzBestResult) );
|
|
if( !pwcBestResult ) // Caller is querying for buffer size
|
|
{
|
|
*pcTCH = cWChar;
|
|
return S_OK;
|
|
}
|
|
memcpy_s( pwcBestResult, *pcTCH*sizeof(WCHAR), pRC->wzBestResult, cWChar*sizeof(WCHAR) );
|
|
if( cWChar > *pcTCH )
|
|
{
|
|
hr = TPC_S_TRUNCATED;
|
|
}
|
|
*pcTCH = cWChar;
|
|
return hr;
|
|
}
|
|
|
|
HRESULT WINAPI DestroyAlternate(HRECOALT hrcalt)
|
|
{
|
|
UNREFERENCED_PARAMETER(hrcalt);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT WINAPI SetGuide(HRECOCONTEXT hrc, const RECO_GUIDE* pGuide, ULONG iIndex)
|
|
{
|
|
if( !hrc )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
MY_RECOCONTEXT *pRC = (MY_RECOCONTEXT*) hrc;
|
|
|
|
if( pGuide ) // pGuide not NULL means lined or boxed mode
|
|
{
|
|
if ((pGuide->cHorzBox < 0 || pGuide->cVertBox < 0) || // invalid
|
|
(pGuide->cHorzBox > 0 && pGuide->cVertBox == 0)) // vertical lined mode
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
}
|
|
|
|
// If there is no guide already present, allocate one
|
|
if (!pRC->pGuide)
|
|
{
|
|
pRC->pGuide = new RECO_GUIDE;
|
|
}
|
|
if (!pRC->pGuide)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (pGuide)
|
|
*(pRC->pGuide) = *pGuide;
|
|
else
|
|
{
|
|
ZeroMemory(pRC->pGuide, sizeof(RECO_GUIDE)); // free mode
|
|
}
|
|
pRC->uiGuideIndex = iIndex;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT WINAPI GetGuide(HRECOCONTEXT hrc, RECO_GUIDE* pGuide, ULONG *piIndex)
|
|
{
|
|
if( !hrc || !pGuide || !piIndex )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
MY_RECOCONTEXT *pRC = (MY_RECOCONTEXT*) hrc;
|
|
|
|
if( !pRC->pGuide )
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
|
|
*pGuide = *(pRC->pGuide);
|
|
*piIndex = pRC->uiGuideIndex;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT WINAPI AdviseInkChange(HRECOCONTEXT hrc, BOOL bNewStroke)
|
|
{
|
|
UNREFERENCED_PARAMETER(hrc);
|
|
UNREFERENCED_PARAMETER(bNewStroke);
|
|
return S_OK;
|
|
}
|
|
HRESULT WINAPI SetCACMode(HRECOCONTEXT hrc, int iMode)
|
|
{
|
|
UNREFERENCED_PARAMETER(hrc);
|
|
UNREFERENCED_PARAMETER(iMode);
|
|
return E_NOTIMPL;
|
|
}
|
|
HRESULT WINAPI CloneContext(HRECOCONTEXT hrc, HRECOCONTEXT* pCloneHrc)
|
|
{
|
|
UNREFERENCED_PARAMETER(hrc);
|
|
UNREFERENCED_PARAMETER(pCloneHrc);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT WINAPI ResetContext(HRECOCONTEXT hrc)
|
|
{
|
|
// Deletes the current ink and recognition results from the context.
|
|
if( !hrc )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
MY_RECOCONTEXT *pRC = (MY_RECOCONTEXT*) hrc;
|
|
DestroyStrokeList( pRC->pStrokeList ); pRC->pStrokeList = NULL;
|
|
pRC->cStrokes = 0;
|
|
pRC->cPointsTot = 0;
|
|
pRC->wzBestResult[0] = 0;
|
|
if( pRC->pLattice )
|
|
{
|
|
DestroyLattice( pRC->pLattice ); pRC->pLattice = NULL;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT WINAPI Process(HRECOCONTEXT hrc, BOOL *pbPartialProcessing)
|
|
{
|
|
// Recognize the strokes in the given context.
|
|
// We don't actually recognize anything. Instead we illustrate how
|
|
// to process the ink and guide information so that you can provide
|
|
// your own recognition algorithm.
|
|
|
|
int iRet = S_OK;
|
|
BYTE *abIsBoxDirty = NULL;
|
|
|
|
if( !hrc || !pbPartialProcessing )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
MY_RECOCONTEXT *pRC = (MY_RECOCONTEXT*) hrc;
|
|
|
|
if( !pRC->cStrokes )
|
|
{
|
|
iRet = S_OK;
|
|
goto Exit;
|
|
}
|
|
if( !pRC->pStrokeList )
|
|
{
|
|
iRet = E_FAIL;
|
|
goto Exit;
|
|
}
|
|
|
|
HRESULT hr = StringCchPrintfW( pRC->wzBestResult, ARRAYSIZE(pRC->wzBestResult), L"Strokes=%d Points=%d",
|
|
pRC->cStrokes, pRC->cPointsTot );
|
|
if( FAILED(hr) )
|
|
{
|
|
iRet = E_FAIL;
|
|
goto Exit;
|
|
}
|
|
|
|
// Find number of rows and columns in guide.
|
|
// Determine if lined mode.
|
|
ULONG cRow = 0;
|
|
ULONG cCol = 0;
|
|
bool bIsLined = false;
|
|
if( pRC->pGuide )
|
|
{
|
|
cRow = pRC->pGuide->cVertBox;
|
|
cCol = pRC->pGuide->cHorzBox;
|
|
if( cRow ) // lined or boxed mode
|
|
{
|
|
if( !cCol ) // lined mode
|
|
{
|
|
cCol = 1;
|
|
bIsLined = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( !cRow ) // free mode.
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// At this point we are in either lined mode or boxed mode but
|
|
// not free mode. The remainder of this routine enumerates the
|
|
// lines or boxes containing ink.
|
|
|
|
// Allocate 2D array of booleans to keep track of which boxes contain ink points.
|
|
// For lined mode, the array has a single column.
|
|
if( ULONG_MAX / cRow < cCol )
|
|
{
|
|
assert(0 && "Overflow");
|
|
iRet = E_FAIL;
|
|
goto Exit;
|
|
}
|
|
abIsBoxDirty = new BYTE[cRow*cCol];
|
|
if( !abIsBoxDirty )
|
|
{
|
|
iRet = E_FAIL;
|
|
goto Exit;
|
|
}
|
|
ZeroMemory( abIsBoxDirty, cRow*cCol*sizeof(BYTE) );
|
|
|
|
// Scan through the ink to mark boxes containing ink points
|
|
MY_STROKE *pStroke = pRC->pStrokeList;
|
|
for( ;pStroke; pStroke = pStroke->pNext )
|
|
{
|
|
POINT *pPoint = pStroke->aPoints;
|
|
for( ULONG iPoint=0; iPoint < pStroke->cPoints; iPoint++, pPoint++ )
|
|
{
|
|
ULONG iRow = (pPoint->y - pRC->pGuide->yOrigin) / pRC->pGuide->cyBox;
|
|
ULONG iCol = bIsLined ? 0 : (pPoint->x - pRC->pGuide->xOrigin) / pRC->pGuide->cxBox;
|
|
if( iRow >= cRow || iCol >= cCol )
|
|
{
|
|
assert(0 && "Buffer overrun");
|
|
iRet = E_FAIL;
|
|
goto Exit;
|
|
}
|
|
abIsBoxDirty[iRow*cCol + iCol] = 1;
|
|
}
|
|
}
|
|
|
|
// Prepare to concatenate line/box numbers to the result
|
|
hr = StringCchCatW(
|
|
pRC->wzBestResult,
|
|
ARRAYSIZE(pRC->wzBestResult),
|
|
bIsLined ? L" Lines used=" : L" Boxes used=" );
|
|
if( FAILED(hr) )
|
|
{
|
|
iRet = E_FAIL;
|
|
goto Exit;
|
|
}
|
|
|
|
// Concatenate the numbers iteratively to the end of the result string.
|
|
// For simplicity, we opt for a less efficient implementation which
|
|
// scans for the end of the result string for each concatenation.
|
|
|
|
bool bIsTruncated = false; // true if result string runs out of space
|
|
for( ULONG iRow=0; iRow < cRow && !bIsTruncated; iRow++ )
|
|
{
|
|
for( ULONG iCol=0; iCol < cCol && !bIsTruncated; iCol++ )
|
|
{
|
|
if( abIsBoxDirty[iRow*cCol + iCol] )
|
|
{
|
|
// Get the next item to concatenate
|
|
WCHAR wzTmp[20];
|
|
if( bIsLined )
|
|
{
|
|
hr = StringCchPrintfW( wzTmp, ARRAYSIZE(wzTmp), L"%d ", iRow );
|
|
if( FAILED(hr) )
|
|
{
|
|
iRet = E_FAIL;
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = StringCchPrintfW( wzTmp, ARRAYSIZE(wzTmp), L"(%d,%d)", iRow, iCol );
|
|
if( FAILED(hr) )
|
|
{
|
|
iRet = E_FAIL;
|
|
goto Exit;
|
|
}
|
|
}
|
|
// Concatenate the item to the end of the result
|
|
hr = StringCchCatW( pRC->wzBestResult, ARRAYSIZE(pRC->wzBestResult), wzTmp );
|
|
if( FAILED(hr) )
|
|
{
|
|
// overwrite tail of wzBestResult with "<truncated>"
|
|
const WCHAR wzTrunc[] = L"<truncated>";
|
|
const size_t len = ARRAYSIZE(wzTrunc);
|
|
hr = StringCchCopyW(
|
|
pRC->wzBestResult+ARRAYSIZE(pRC->wzBestResult)-len,
|
|
len,
|
|
wzTrunc);
|
|
if( FAILED(hr) )
|
|
{
|
|
iRet = E_FAIL;
|
|
goto Exit;
|
|
}
|
|
bIsTruncated = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Exit:
|
|
*pbPartialProcessing = FALSE; // No more ink to process
|
|
if( abIsBoxDirty )
|
|
{
|
|
delete [] abIsBoxDirty;
|
|
}
|
|
return iRet;
|
|
}
|
|
|
|
HRESULT WINAPI SetFactoid(HRECOCONTEXT hrc, ULONG cwcFactoid, const WCHAR *pwcFactoid)
|
|
{
|
|
UNREFERENCED_PARAMETER(hrc);
|
|
UNREFERENCED_PARAMETER(cwcFactoid);
|
|
UNREFERENCED_PARAMETER(pwcFactoid);
|
|
return S_OK; // ignore factoid
|
|
}
|
|
HRESULT WINAPI SetFlags(HRECOCONTEXT hrc, DWORD dwFlags)
|
|
{
|
|
UNREFERENCED_PARAMETER(hrc);
|
|
UNREFERENCED_PARAMETER(dwFlags);
|
|
return S_OK; // ignore flags
|
|
}
|
|
|
|
static void DestroyLattice( RECO_LATTICE *pLattice )
|
|
{
|
|
if( !pLattice )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( pLattice->pLatticeColumns )
|
|
{
|
|
if( pLattice->pLatticeColumns->pStrokes )
|
|
{
|
|
delete [] pLattice->pLatticeColumns->pStrokes;
|
|
}
|
|
if( pLattice->pLatticeColumns->pLatticeElements )
|
|
{
|
|
delete [] pLattice->pLatticeColumns->pLatticeElements;
|
|
}
|
|
delete [] pLattice->pLatticeColumns;
|
|
}
|
|
if( pLattice->pulBestResultColumns )
|
|
{
|
|
delete [] pLattice->pulBestResultColumns;
|
|
}
|
|
if( pLattice->pulBestResultIndexes )
|
|
{
|
|
delete [] pLattice->pulBestResultIndexes;
|
|
}
|
|
delete pLattice;
|
|
}
|
|
|
|
|
|
|
|
HRESULT WINAPI GetLatticePtr(HRECOCONTEXT hrc, RECO_LATTICE **ppLattice)
|
|
{
|
|
// We trivialize the lattice by providing just
|
|
// one segmentation using all the strokes, and just one
|
|
// recognition result with no alternates.
|
|
|
|
if( !hrc )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
if( !ppLattice )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
MY_RECOCONTEXT *pRC = (MY_RECOCONTEXT*) hrc;
|
|
if( !pRC->wzBestResult[0] ) // No reco result available
|
|
{
|
|
return TPC_E_NOT_RELEVANT;
|
|
}
|
|
|
|
if( pRC->pLattice ) // free existing lattice data
|
|
{
|
|
DestroyLattice( pRC->pLattice ); pRC->pLattice = NULL;
|
|
}
|
|
|
|
// RECO_LATTICE initialization
|
|
RECO_LATTICE *pLattice = pRC->pLattice = new RECO_LATTICE;
|
|
if( !pLattice )
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
ZeroMemory( pLattice, sizeof(RECO_LATTICE) );
|
|
pLattice->ulColumnCount = 1;
|
|
pLattice->pLatticeColumns = new RECO_LATTICE_COLUMN[pLattice->ulColumnCount];
|
|
if( !pLattice->pLatticeColumns )
|
|
{
|
|
goto OutOfMemory;
|
|
}
|
|
ZeroMemory( pLattice->pLatticeColumns, sizeof(RECO_LATTICE_COLUMN) );
|
|
pLattice->ulPropertyCount = 0;
|
|
pLattice->pGuidProperties = NULL;
|
|
pLattice->ulBestResultColumnCount = 1;
|
|
pLattice->pulBestResultColumns = new ULONG[pLattice->ulBestResultColumnCount];
|
|
if( !pLattice->pulBestResultColumns )
|
|
{
|
|
goto OutOfMemory;
|
|
}
|
|
pLattice->pulBestResultColumns[0] = 0;
|
|
pLattice->pulBestResultIndexes = new ULONG[1];
|
|
if( !pLattice->pulBestResultIndexes )
|
|
{
|
|
goto OutOfMemory;
|
|
}
|
|
pLattice->pulBestResultIndexes[0] = 0;
|
|
|
|
// RECO_LATTICE_COLUMN initialization
|
|
// We have just one Lattice Column to initialize
|
|
RECO_LATTICE_COLUMN *pLatticeColumn = pLattice->pLatticeColumns;
|
|
pLatticeColumn->key = 0;
|
|
pLatticeColumn->cpProp.cProperties = 0;
|
|
pLatticeColumn->cpProp.apProps = NULL;
|
|
// fake the stroke mapping:
|
|
pLatticeColumn->cStrokes = pRC->cStrokes;
|
|
pLatticeColumn->pStrokes = new ULONG[pRC->cStrokes];
|
|
if( !pLatticeColumn->pStrokes )
|
|
{
|
|
goto OutOfMemory;
|
|
}
|
|
for( ULONG ii=0; ii<pRC->cStrokes; ii++ )
|
|
{
|
|
pLatticeColumn->pStrokes[ii] = ii;
|
|
}
|
|
pLatticeColumn->cLatticeElements = 1;
|
|
pLatticeColumn->pLatticeElements = new RECO_LATTICE_ELEMENT[pLatticeColumn->cLatticeElements];
|
|
if( !pLatticeColumn->pLatticeElements )
|
|
{
|
|
goto OutOfMemory;
|
|
}
|
|
|
|
// RECO_LATTICE_ELEMENT initialization
|
|
// We have just one Column Element to initialize
|
|
RECO_LATTICE_ELEMENT *pLatticeElement = pLatticeColumn->pLatticeElements;
|
|
pLatticeElement->score = 0;
|
|
pLatticeElement->type = RECO_TYPE_WSTRING;
|
|
pLatticeElement->pData = (BYTE*) pRC->wzBestResult;
|
|
pLatticeElement->ulNextColumn = 1;
|
|
pLatticeElement->ulStrokeNumber = pRC->cStrokes;
|
|
pLatticeElement->epProp.cProperties = 0;
|
|
pLatticeElement->epProp.apProps = NULL;
|
|
|
|
*ppLattice = pLattice;
|
|
return S_OK;
|
|
|
|
OutOfMemory:
|
|
if( pLattice->pLatticeColumns )
|
|
{
|
|
if( pLattice->pLatticeColumns->pStrokes )
|
|
{
|
|
delete [] pLattice->pLatticeColumns->pStrokes;
|
|
}
|
|
if( pLattice->pLatticeColumns->pLatticeElements )
|
|
{
|
|
delete [] pLattice->pLatticeColumns->pLatticeElements;
|
|
}
|
|
delete [] pLattice->pLatticeColumns;
|
|
}
|
|
if( pLattice->pulBestResultColumns )
|
|
{
|
|
delete [] pLattice->pulBestResultColumns;
|
|
}
|
|
if( pLattice->pulBestResultIndexes )
|
|
{
|
|
delete [] pLattice->pulBestResultIndexes;
|
|
}
|
|
if( pLattice )
|
|
{
|
|
delete pLattice;
|
|
}
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
HRESULT WINAPI SetTextContext(HRECOCONTEXT hrc, ULONG cwcBefore, const WCHAR *pwcBefore, ULONG cwcAfter, const WCHAR *pwcAfter)
|
|
{
|
|
UNREFERENCED_PARAMETER(hrc);
|
|
UNREFERENCED_PARAMETER(cwcBefore);
|
|
UNREFERENCED_PARAMETER(pwcBefore);
|
|
UNREFERENCED_PARAMETER(cwcAfter);
|
|
UNREFERENCED_PARAMETER(pwcAfter);
|
|
return E_NOTIMPL;
|
|
}
|
|
HRESULT WINAPI GetEnabledUnicodeRanges(HRECOCONTEXT hrc, ULONG *pcRanges, CHARACTER_RANGE *pcr)
|
|
{
|
|
UNREFERENCED_PARAMETER(hrc);
|
|
UNREFERENCED_PARAMETER(pcRanges);
|
|
UNREFERENCED_PARAMETER(pcr);
|
|
return E_NOTIMPL;
|
|
}
|
|
HRESULT WINAPI SetEnabledUnicodeRanges(HRECOCONTEXT hrc, ULONG cRanges, CHARACTER_RANGE *pcr)
|
|
{
|
|
UNREFERENCED_PARAMETER(hrc);
|
|
UNREFERENCED_PARAMETER(cRanges);
|
|
UNREFERENCED_PARAMETER(pcr);
|
|
return E_NOTIMPL;
|
|
}
|
|
HRESULT WINAPI GetContextPropertyList(HRECOCONTEXT hrc, ULONG *pcProperties, GUID *pPropertyGUIDS)
|
|
{
|
|
UNREFERENCED_PARAMETER(hrc);
|
|
UNREFERENCED_PARAMETER(pcProperties);
|
|
UNREFERENCED_PARAMETER(pPropertyGUIDS);
|
|
return E_NOTIMPL;
|
|
}
|
|
HRESULT WINAPI GetContextPropertyValue(HRECOCONTEXT hrc, GUID *pGuid, ULONG *pcbSize, BYTE *pProperty)
|
|
{
|
|
UNREFERENCED_PARAMETER(hrc);
|
|
UNREFERENCED_PARAMETER(pGuid);
|
|
UNREFERENCED_PARAMETER(pcbSize);
|
|
UNREFERENCED_PARAMETER(pProperty);
|
|
return E_NOTIMPL;
|
|
}
|
|
HRESULT WINAPI SetContextPropertyValue(HRECOCONTEXT hrc, GUID *pGuid, ULONG cbSize, BYTE *pProperty)
|
|
{
|
|
UNREFERENCED_PARAMETER(hrc);
|
|
UNREFERENCED_PARAMETER(pGuid);
|
|
UNREFERENCED_PARAMETER(cbSize);
|
|
UNREFERENCED_PARAMETER(pProperty);
|
|
return E_NOTIMPL;
|
|
}
|
|
HRESULT WINAPI IsStringSupported(HRECOCONTEXT hrc, ULONG wcString, const WCHAR *pwcString)
|
|
{
|
|
UNREFERENCED_PARAMETER(hrc);
|
|
UNREFERENCED_PARAMETER(wcString);
|
|
UNREFERENCED_PARAMETER(pwcString);
|
|
return E_NOTIMPL;
|
|
}
|
|
HRESULT WINAPI SetWordList(HRECOCONTEXT hrc, HRECOWORDLIST hwl)
|
|
{
|
|
UNREFERENCED_PARAMETER(hrc);
|
|
UNREFERENCED_PARAMETER(hwl);
|
|
return E_NOTIMPL;
|
|
}
|
|
HRESULT WINAPI GetContextPreferenceFlags(HRECOCONTEXT hrc, DWORD *pdwContextPreferenceFlags)
|
|
{
|
|
UNREFERENCED_PARAMETER(hrc);
|
|
UNREFERENCED_PARAMETER(pdwContextPreferenceFlags);
|
|
return E_NOTIMPL;
|
|
}
|
|
HRESULT WINAPI GetRightSeparator(HRECOCONTEXT hrc, __inout ULONG *pcSize, __out_ecount(*pcSize) OPTIONAL WCHAR* pwcRightSeparator)
|
|
{
|
|
UNREFERENCED_PARAMETER(hrc);
|
|
UNREFERENCED_PARAMETER(pcSize);
|
|
UNREFERENCED_PARAMETER(pwcRightSeparator);
|
|
return E_NOTIMPL;
|
|
}
|
|
HRESULT WINAPI GetLeftSeparator(HRECOCONTEXT hrc, __inout ULONG *pcSize, __out_ecount(*pcSize) OPTIONAL WCHAR* pwcLeftSeparator)
|
|
{
|
|
UNREFERENCED_PARAMETER(hrc);
|
|
UNREFERENCED_PARAMETER(pcSize);
|
|
UNREFERENCED_PARAMETER(pwcLeftSeparator);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
////////////////////////
|
|
// IRecoWordList
|
|
////////////////////////
|
|
HRESULT WINAPI DestroyWordList(HRECOWORDLIST hwl)
|
|
{
|
|
UNREFERENCED_PARAMETER(hwl);
|
|
return E_NOTIMPL;
|
|
}
|
|
HRESULT WINAPI AddWordsToWordList(HRECOWORDLIST hwl, __in WCHAR *pwcWords)
|
|
{
|
|
UNREFERENCED_PARAMETER(hwl);
|
|
UNREFERENCED_PARAMETER(pwcWords);
|
|
return E_NOTIMPL;
|
|
}
|
|
HRESULT WINAPI MakeWordList(HRECOGNIZER hrec, __in WCHAR *pBuffer, HRECOWORDLIST *phwl)
|
|
{
|
|
UNREFERENCED_PARAMETER(hrec);
|
|
UNREFERENCED_PARAMETER(pBuffer);
|
|
UNREFERENCED_PARAMETER(phwl);
|
|
return E_NOTIMPL;
|
|
}
|