C++ 事件接收器示例

此程序演示如何生成仅使用 C++ 捕获 InkCollector 事件的应用程序。 此程序共同创建 一个 InkCollector 对象来启用窗口墨迹。 每当收到 Stroke 事件时,它将显示一个消息框。

定义墨迹收集器事件的包装器

InkCollectorEvents 处理墨迹收集器事件从墨迹收集器传递给此类的用户。 方法 AdviseInkCollector 设置 InkCollector 对象与此类之间的连接。 方法 InvokeIDispatch 事件通知转换为对虚拟函数的调用,此类用户可以重写该函数来处理特定事件。

注意

要获取该事件,必须执行更多操作,而不是重写事件处理程序的虚拟函数。 对于除默认事件之外的所有事件,必须调用墨迹收集器的 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);
}

访问平板电脑接口和包装类

首先,包括适用于 Tablet PC 自动化接口的标头。 它们随 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;