共用方式為


將文字筆跡物件轉換為 Ink

從文字筆跡物件 (tInk) 轉換成筆跡的實作。

若要從文字筆跡物件轉換成筆跡

  1. 使用 IPersistStream 介面,將文字筆跡物件的內容寫入資料流程。 文字筆跡物件會使用筆跡序列化格式寫入至資料流程。
  2. 將資料流程的內容讀入 BYTE 陣列。
  3. 使用 InkDisp 物件的 Load 方法,將資料流程的內容載入 InkDisp 物件。

將 Ink 物件文字寫入 Ink 物件範例

下列程式碼片段會將文字筆跡物件轉換成筆跡。

首先,程式碼會取得文字筆跡物件。

/* Create a variable to hold the text ink object */
CComPtr<IInkObject *> spITextInk;

/* Obtain the text ink object */

然後,程式碼會為保存文字筆跡物件內容的資料流程建立指標。

// Create a Stream pointer to hold the saved object
CComPtr<IStream *> spStream = NULL; 

然後,程式碼會從文字筆跡物件取得 IPersistStream 介面。

// Declare the IPersistStream to be used for retrieving the saved data from the text ink
CComPtr<IPersistStream *> spIPersistStream = NULL;
// Get the actual IPersistStream interface off of the TextInk
HRESULT hr = pITextInk->QueryInterface(IID_IPersistStream, (void **)&spIPersistStream);
ASSERT(SUCCEEDED(hr) && spIPersistStream);

然後,程式碼會使用 IPersistStream 介面,將文字筆跡物件的內容儲存至資料流程。

if( SUCCEEDED(hr) && pIPersistStream )
{
    // Create the stream 
    if( SUCCEEDED(hr=CreateStreamOnHGlobal(NULL, TRUE, &spStream)) && spStream )
    {
        // Save the TextInk through IPersistStream Interface to the IStream
        hr = spIPersistStream->Save(spStream, FALSE);
    }
}

然後,程式碼會建立InkCollector物件、建立InkCollectorInkDisp物件、將InkCollector附加至應用程式視窗,並在InkCollector上啟用筆跡集合。

// Now create an InkCollector object along with InkDisp Object
if( SUCCEEDED(hr) && spStream)
{
    CComPtr<IInkCollector *> spIInkCollector;
    CComPtr<IInkDisp *> spIInkDisp = NULL;

    // Create the InkCollector object.
    hr = CoCreateInstance(CLSID_InkCollector, 
        NULL, CLSCTX_INPROC_SERVER, 
        IID_IInkCollector, 
        (void **) &spIInkCollector);
    if (FAILED(hr)) 
        return -1;

    // Get a pointer to the Ink object
    hr = spIInkCollector->get_Ink(&spIInkDisp);
    if (FAILED(hr)) 
        return -1;

    // Tell InkCollector the window to collect ink in
    hr = spIInkCollector->put_hWnd((long)hwnd);
    if (FAILED(hr)) 
        return -1;

    // Enable ink input in the window
    hr = spIInkCollector->put_Enabled(VARIANT_TRUE);
    if (FAILED(hr)) 
        return -1;

然後,程式碼會擷取資料流程的大小,並建立安全陣列來保存資料流程的內容。

    // Now create a variant data type based on the IStream data
    const LARGE_INTEGER li0 = {0, 0};
    ULARGE_INTEGER uli = {0,0};

    // Find the size of the stream
    hr = spStream->Seek(li0, STREAM_SEEK_END, &uli);
    ASSERT(0 == uli.HighPart);
    DWORD dwSize = uli.LowPart;

    // Set uli to point to the beginning of the stream.
    hr=spStream->Seek(li0, STREAM_SEEK_SET, &uli);
    ASSERT(SUCCEEDED(hr));

    // Create a safe array to hold the stream contents
    if( SUCCEEDED(hr) )
    {
        VARIANT vtData;
        VariantInit(&vtData);
        vtData.vt = VT_ARRAY | VT_UI1;

        vtData.parray = ::SafeArrayCreateVector(VT_UI1, 0, dwSize);
        if (vtData.parray)
        {

最後,程式碼會存取安全陣列,並使用 InkDisp 物件的 Load 方法從陣列載入筆跡。

            DWORD dwRead = 0;
            LPBYTE pbData = NULL; 

            if (SUCCEEDED(::SafeArrayAccessData(vtData.parray, (void**)&pbData)))
            {
                // Read the data from the stream to the varian data and load that into an InkDisp object
                if (TRUE == spStream->Read(pbData, uli.LowPart, &dwRead)
                    && SUCCEEDED(spIInkDisp->Load(vtData)))
                {
                    hr = S_OK;
                }
                ::SafeArrayUnaccessData(vtData.parray);
            }
            ::SafeArrayDestroy(vtData.parray);
        }
    }
}