C++ 事件接收範例

此程式示範如何建置只使用 C++ 擷取 InkCollector 事件的應用程式。 此程式會將 InkCollector 物件共同建立至筆跡啟用視窗。 每當收到 Stroke 事件時,它就會顯示訊息方塊。

定義筆跡收集器事件的包裝函式

類別 InkCollectorEvents 會處理將筆跡收集器事件從筆跡收集器傳遞至這個類別的使用者。 方法 AdviseInkCollector 會設定 InkCollector 物件與這個類別之間的連接。 方法 Invoke 會將 IDispatch 事件通知轉換成呼叫此類別的使用者可覆寫以處理特定事件的虛擬函式。

注意

您必須覆寫事件處理常式的虛擬函式,才能取得該事件。 對於所有預設事件,您必須呼叫筆跡收集器的 SetEventInterest 方法,以確保取得事件。 其次,這個物件會封送處理本身的可用執行緒,因此所有實作的事件處理常式也必須是自由執行緒。 特別重要的是使用 Windows API,這可能會導致切換到另一個執行緒,因為事件處理常式不保證在與筆跡收集器連接視窗的相同執行緒上執行。

 

// Invoke translates from IDispatch to an event callout
//  that can be overridden by a subclass of this class.
STDMETHOD(Invoke)(
   DISPID dispidMember, 
    REFIID riid,
    LCID lcid, 
    WORD /*wFlags*/, 
    DISPPARAMS* pdispparams, 
    VARIANT* pvarResult,
    EXCEPINFO* /*pexcepinfo*/, 
    UINT* /*puArgErr*/)
{
    switch(dispidMember)
    {
        case DISPID_ICEStroke:
            Stroke(
                (IInkCursor*) pdispparams->rgvarg[2].pdispVal,
                (IInkStrokeDisp*) pdispparams->rgvarg[1].pdispVal,
                (VARIANT_BOOL *)pdispparams->rgvarg[0].pboolVal);
            break;
        ...
    }
    return S_OK;
}

virtual void Stroke(
    IInkCursor* Cursor,
    IInkStrokeDisp* Stroke,
    VARIANT_BOOL *Cancel)
{
    // This is a place holder designed to be overridden by
    //  user of this class.
    return;
}
...

方法會 Init 呼叫 CoCreateFreeThreadedMarshaler 來設定免費的執行緒封送處理器。

// Init: set up free threaded marshaller.
HRESULT Init()
{
    return CoCreateFreeThreadedMarshaler(this, &m_punkFTM);
}

方法 AdviseInkCollector 會設定 InkCollector 物件與這個類別之間的連接。 它會先擷取筆跡收集器的連接點。 然後它會擷取 的 IInkCollectorEvents 指標,以便建立控制項的諮詢連線。

// Set up connection between sink and InkCollector
HRESULT AdviseInkCollector(
    IInkCollector *pIInkCollector)
{
    // Get the connection point container
    IConnectionPointContainer *pIConnectionPointContainer;
    HRESULT hr = pIInkCollector->QueryInterface(IID_IConnectionPointContainer, (void **) &pIConnectionPointContainer);
        
    if (FAILED(hr))
        ...
    
    // Find the connection point for Ink Collector events
    hr = pIConnectionPointContainer->FindConnectionPoint(__uuidof(_IInkCollectorEvents), &m_pIConnectionPoint);
        
    if (SUCCEEDED(hr))
    {
        // Hook up sink to connection point
        hr = m_pIConnectionPoint->Advise(this, &m_dwCookie);
    }
    
    if (FAILED(hr))
        ...
    
    // Don't need the connection point container any more.
    pIConnectionPointContainer->Release();
    return hr;
}

方法 UnadviseInkCollector 會釋放 物件與 控制項所需的連接。

// Remove the connection of the sink to the Ink Collector
HRESULT UnadviseInkCollector()
{
    HRESULT hr = m_pIConnectionPoint->Unadvise(m_dwCookie);m_pIConnectionPoint->Release();
m_pIConnectionPoint = NULL;
    return hr;
}

定義筆跡收集器事件處理常式

CMyInkEvents 類別會覆寫 InkCollectorEvents 類別 之 Stroke 事件處理常式的預設行為。 當 InkCollector 收到 Stroke 事件時,Stroke 方法會顯示訊息方塊。

class CMyInkEvents : public InkCollectorEvents
{
public:

    // Event: Stroke
    virtual void Stroke(
        IInkCursor* Cursor,
        IInkStrokeDisp* Stroke,
        VARIANT_BOOL *Cancel)
    {
        // Demonstrate that the event notification was received.
        MessageBox(m_hWnd, "Stroke Event", "Event Received", MB_OK);
    }
    
    CMyInkEvents()
    {
        m_hWnd = NULL;
    }
    
    HRESULT Init(
        HWND hWnd)
    {
        m_hWnd = hWnd;
        return InkCollectorEvents::Init();
    }    
    
    HWND m_hWnd;
};

定義筆跡收集器包裝函式

CMyInkCollector 類別的 Init 方法會宣告並初始化 CMyInkEvents 物件。 然後,它會建立 InkCollector 物件,並將筆跡收集器和事件處理常式產生關聯。 最後, InkCollector 會附加至視窗並啟用。

// Handle all initialization
HRESULT Init(
HWND hWnd)
{
    // Initialize event sink. This consists of setting
    //  up the free threaded marshaler.
    HRESULT hr = m_InkEvents.Init(hWnd);

    if (FAILED(hr))
        ...

    // Create the ink collector
    hr = CoCreateInstance(CLSID_InkCollector, NULL, CLSCTX_ALL, IID_IInkCollector, (void **) &m_pInkCollector);

    if (FAILED(hr))
        ...

    // Set up connection between Ink Collector and our event sink
    hr = m_InkEvents.AdviseInkCollector(m_pInkCollector);

    if (FAILED(hr))
        ...

    // Attach Ink Collector to window
    hr = m_pInkCollector->put_hWnd((long) hWnd);

    if (FAILED(hr))
        ...

    // Allow Ink Collector to receive input.
    return m_pInkCollector->put_Enabled(VARIANT_TRUE);
}

存取平板電腦介面和包裝函式類別

首先,包含平板電腦自動化介面的標頭。 這些是隨 Microsoft < 實體類型=「reg」/ > Windows < 實體類型=「reg」/ > XP Tablet PC Edition Development Kit 1.7 一起安裝。

#include <msinkaut.h>
#include <msinkaut_i.c>

然後,包含包裝函式類別的標頭,並已定義 InkCollector 事件處理常式

#include "TpcConpt.h"
#include "EventSink.h"

呼叫包裝函式類別

建立視窗時,Window 程式會建立筆跡收集器包裝函式,並初始化包裝函式。 當視窗終結時,Window 程式會刪除筆跡收集器包裝函式。 筆跡收集器包裝函式會處理其相關聯事件處理常式的建立和刪除。

case WM_CREATE:

    // Allocate and initialize memory for object
    pmic = new CMyInkCollector();

    if (pmic != NULL)
    {
        // Real initialization. This consists of creating
        //  an ink collector object and attaching it to
        //  the current window. 
        if (SUCCEEDED(pmic->Init(hWnd)))
        {
            return 0;
        }
        
        // Failure free resources.
        delete pmic;
        pmic = NULL;
    }
    
    return -1;
...
case WM_DESTROY:
    // The destructor for the object handles releasing the
    //  InkCollector and disconnecting the InkCollector
    //  from the object's event sink. 
    delete pmic;
    pmic = NULL;
    PostQuitMessage(0);
    break;