Tablet PC: Gettting started with InkAnalysis using C++ / COM

In this post, I’m going to guide you through the process of creating an InkAnalysis application written in C++ using MFC and COM. It’s more difficult than writing an InkAnalysis application with .NET, but it’s doable J

Here’s the basic approach for this sample application:

1. Create an MFC dialog project with the app wizard in VS.NET 2005

2. Hook up in InkOverlay to the dialog and enable it to collect ink

3. Add a “Recognize” button and add a handler which instantiates an InkAnalyzer, adds the current strokes from the InkOverlay, performs analysis, and displays the recognized string

**Note that I’ve created helper methods for error handling and some InkAnalysis functionality – this helps to clean up the code and cleanly demonstrate how to use the APIs. See InkAnalysisHelper.cpp for those implementation details.

Steps:

Create a new MFC Project:

FileàNewàProjectàMFC Application

Application TypeàDialog Based

Advanced FeaturesàAutomation (check)

Finish

Build and run

Open the dialog in the resource editor (Double click on IDD_xxx_DIALOG in resource tab)

Remove placeholder text

Remove cancel and OK buttons

Add a new button with text “Recognize”

In stdafx.h:

#include <msinkaut.h>

#include <iacom.h>

In xxxApplicationDlg.cpp:

#include <msinkaut_i.c>

#include <iacom_i.c>

In project settings (All configurations) add the following to C++ à General à Additional Include Directories:

$(ProgramFiles)\Microsoft Tablet PC Platform SDK\Include

Add InkOverlay member: (xxxDlg.h file)

            CComPtr<IInkOverlay> inkOverlay;

In OnInitDialog(), initialize the InkOverlay:

try

{

            // Create our InkOverlay and InkAnalyzer objects

            CheckHRESULT(

                        this->inkOverlay.CoCreateInstance(CLSID_InkOverlay),

                        L"Failed to create InkOverlay");

            CheckHRESULT(

                        this->inkOverlay->put_hWnd((long)this->m_hWnd),

                        L"Failed to set InkOverlay's attached HWND");

            CheckHRESULT(

                        this->inkOverlay->put_Enabled(VARIANT_TRUE),

                        L"Failed to enable InkOverlay");

}

catch(CString &message)

{

            ::MessageBoxEx(NULL, message, L"Error", NULL, NULL);

}

Double Click on the “Recognize” button in the resource editor and add the following code to the button handler:

try

{

            // Declare our IInkAnalyzer auto pointer

            CComPtr<IInkAnalyzer> inkAnalyzer;

            // Create an InkAnalyzer instance we can use

            CheckHRESULT(

                        inkAnalyzer.CoCreateInstance(CLSID_InkAnalyzer),

                        L"Failed to create InkAnalyzer");

            // Get the IInkDisp object from the InkOverlay

            CComPtr<IInkDisp> ink;

            CheckHRESULT(

                        this->inkOverlay->get_Ink(&ink),

                        L"Failed to get InkDisp from InkOverlay");

            // Get the strokes from the IInkDisp

            CComPtr<IInkStrokes> strokes;

            CheckHRESULT(

                        ink->get_Strokes(&strokes),

                        L"Failed to get strokes from InkDisp");

            // Add the strokes to the InkAnalyzer (See InkAnalysisHelper.cpp)

            AddStrokesToInkAnalyzer(inkAnalyzer, strokes);

            // Perform synchronous analysis

            CComPtr<IAnalysisStatus> status;

            CheckHRESULT(

                        inkAnalyzer->Analyze(&status),

                        L"Analyze() failed");

            // Confirm that analysis was successful

            VARIANT_BOOL wasSuccessful = VARIANT_FALSE;

            CheckHRESULT(

                        status->IsSuccessful(&wasSuccessful),

                        L"Failed to get IsSuccessful property from IAnalysisStatus");

            CheckCondition(

                        wasSuccessful == VARIANT_TRUE,

                        L"Analyze() failed...");

            // Get the recognized string from analysis

            CComBSTR recoString;

            CheckHRESULT(

                        inkAnalyzer->GetRecognizedString(&recoString),

                        L"Failed to get recognized string");

            // Display the reco result

            ::MessageBoxEx(NULL, recoString, L"Recognized string from analysis", NULL, NULL);

           

}

catch(CString &message)

{

            ::MessageBoxEx(NULL, message, L"Error", NULL, NULL);

}

That’s your basic C++ InkAnalysis handwriting recognition application. Using our error handling helper methods and corresponding exceptions allows us to avoid the typical nested if(SUCCEEDED(hr))… statements. Using autopointers (CComPtr<>) also ensures that our COM object interface pointers are properly released when they go out of scope.

For more information on the COM InkAnalysis API, see the following section in the Tablet PC Platform SDK documentation:

Tablet PC API ReferenceàCOM Library ReferenceàInk Analysis Reference

You can experiment with the example code for this project by downloading the attached .zip file à hope it’s helpful!

See ya,

Gavin

MFC_InkAnalysis_App.zip

Comments

  • Anonymous
    February 14, 2008
    The life of a Programmer/Writer is exciting! We frequently have the opportunity to be learning new technology

  • Anonymous
    February 14, 2008
    PingBack from http://msdnrss.thecoderblogs.com/2008/02/14/hello-tablet/

  • Anonymous
    February 14, 2008
    The life of a Programmer/Writer is exciting! We frequently have the opportunity to be learning new technology