Este contenido no se encuentra disponible en su idioma, pero aquí tiene la versión en inglés.

Using the Automation Library

Using the Automation Library

Description of using the Automation Library for the Tablet PC.

This topic contains notes on using the Tablet PC platform Automation Library.

Working with Collections

If you pass in a NULL value as the index to any of the collection objects in the Automation Library, you receive the first item in the collection because these argument values are coerced to 0 when the call is made.

The _NewEnum property is marked restricted in the Interface Definition Language (IDL) definition for the collection interfaces. It is not shown in the Microsoft® Visual Basic® object browser. It is automatically used internally when you use the For Each In construct in Visual Basic. In Visual Basic 6.0, use the For...Each operator to iterate through collections.

In C++, use a for loop to iterate through a collection by first obtaining the collection's length. The example below shows how to iterate through the strokes of an InkDisp object, pInk.

IInkStrokes* pStrokes;
HRESULT result = pInk->get_Strokes(&pStrokes);
if (SUCCEEDED(result))
    // Loop over strokes
    long nStrokes;
    result = pStrokes->get_Count(&nStrokes);
    if (SUCCEEDED(result))
        for (int i =0; i < nStrokes; i++)
            IInkStrokeDisp* pStroke;
            result = pStrokes->Item(i, &pStroke);
            if (SUCCEEDED(result))
              // Code that uses pStroke
              // ...


If you pass in VT_EMPTY or VT_NULL as the index to any of the collection objects in the Automation Library, you receive the first item in the collection because these argument values are coerced to 0 when the call is made.

Arguments that are shown in C++ method signatures as float values should be passed as single-type variables when called from Visual Basic 6.0.

Using IDispatch

To increase performance, the Tablet PC Platform Automation application programming interface (API) does not support calling IDispatchImpl::Invoke with a DISPPARAMS structure with named arguments. The IDispatchImpl::GetIDsOfNames is also not supported. Instead, call Invoke with the DISPIDs supplied in the SDK headers.

Waiting for Events

The Tablet PC environment is multithreaded. Use the CoWaitForMultipleHandles Leave Site function instead of other wait methods to allow re-entrant COM calls to enter your apartment while your application is waiting on an event.

Support for Aggregation

Aggregation has been tested for only the InkEdit control, the InkPicture control, the InkDisp object, and the InkOverlay object. Aggregation has not been tested for other controls and objects in the library.


Using the Tablet PC SDK in C++ requires the use of some COM concepts, such as VARIANT, SAFEARRAY, and BSTR. This section describes how to use them.


The VARIANT structure is used for communication between COM objects. Essentially, the VARIANT structure is a container for a large union that carries many types of data.

The value in the first member of the structure, vt, describes which of the union members is valid. When you receive information in a VARIANT structure, check the vt member to find out which member contains valid data. Similarly, when you send information using a VARIANT structure, always set vt to reflect the union member that contains the information.

Before using the structure, initialize it by calling the VariantInit COM function. When finished with the structure, clear it before the memory that contains the VARIANT is freed by calling VariantClear.

For more information on the VARIANT structure, see VARIANT Overview Leave Site.

The SAFEARRAY structure is provided as a way to safely work with arrays in Automation. The VARIANT's parray field is a pointer to a SAFEARRAY. Use functions such as SafeArrayCreateVector, SafeArrayAccessData, and SafeArrayUnaccessData to create and fill a SAFEARRAY in a VARIANT.

For more information on the SAFEARRAY data type, see SafeArray Overview Leave Site.

This C++ example creates a IInkStrokeDisp, pInkStrokeDisp, in an InkDisp object, pInk, from an array of point data.

VARIANT   var, varPK;
LONG*   plongArray=NULL;
POINT   ptArray[2]={0};
long   lSize=0;
IInkStrokeDisp* pInkStrokeDisp;

IInkDisp*   pInk;   // the object should be created correctly
                    // elsewhere and assigned here.

ptArray[0].x = 20;
ptArray[0].y = 100;
ptArray[1].x = 30;
ptArray[1].y = 110;
lSize = 2;   // two points

VariantInit( &var );
VariantInit( &varPK );
SAFEARRAY* psa = SafeArrayCreateVector( VT_I4, 0, lSize*2 );
if( psa )
  if( SUCCEEDED( hr = SafeArrayAccessData( psa, (void**)&plongArray) ))
      for( long i = 0; i < lSize; i++ )
         plongArray[2*i] = ptArray[i].x;
         plongArray[2*i+1] = ptArray[i].y;
      hr = SafeArrayUnaccessData( psa );

      if ( SUCCEEDED( hr ) )
         var.vt     = VT_ARRAY | VT_I4;
         var.parray = psa;

        // varPK (packet description) is currently reserved, so it is
        // just empty variant for now.
         pInk->CreateStroke( var, varPK, &pInkStrokeDisp );
VariantClear( &var );
VariantClear( &varPK );


The supported string format for Automation is BSTR. The "B" stands for Basic — this is the string format Visual Basic uses internally. A BSTR has a pointer to a zero-terminated string, but it also contains the length of the string (in bytes, not counting the terminator), which is stored in the 4 bytes immediately preceding the first character of the string.

For more information on BSTR, see BSTR Overview Leave Site.

This C++ sample shows how to set the factoid on an InkRecognizerContext using a BSTR.

IInkRecognizerContext* pRecognizerContext = NULL;
result = CoCreateInstance(CLSID_InkRecognizerContext,
    (void **) &pRecognizerContext);
if SUCCEEDED(result)
    BSTR bstrFactoid = SysAllocString(FACTOID_DATE);
    result = pRecognizerContext->put_Factoid(bstrFactoid);
    if SUCCEEDED(result)
      // Use recognizer context...
      // ...