Beispiel für C++-Ereignissenken

Dieses Programm veranschaulicht, wie Sie eine Anwendung erstellen können, die InkCollector-Ereignisse nur mit C++ erfasst. Dieses Programm erstellt gemeinsam ein InkCollector-Objekt, um das Fenster zu öffnen und zu aktivieren. Jedes Mal, wenn ein Stroke-Ereignis empfangen wird, wird ein Meldungsfeld angezeigt.

Definieren eines Wrappers für Ink Collector-Ereignisse

Die InkCollectorEvents -Klasse verarbeitet die Übergabe von Ink-Collector-Ereignissen vom Ink-Collector an den Benutzer dieser Klasse. Die AdviseInkCollector -Methode richtet die Verbindung zwischen dem InkCollector-Objekt und dieser Klasse ein. Die Invoke -Methode konvertiert die IDispatch-Ereignisbenachrichtigung in einen Aufruf einer virtuellen Funktion, die der Benutzer dieser Klasse überschreiben kann, um ein bestimmtes Ereignis zu verarbeiten.

Hinweis

Sie müssen mehr als die virtuelle Funktion überschreiben, damit ein Ereignishandler dieses Ereignis abrufen kann. Für alle Ereignisse außer Standardereignissen müssen Sie die SetEventInterest-Methode des Ink-Collectors aufrufen, um das Abrufen eines Ereignisses zu gewährleisten. Zweitens marshallt sich dieses Objekt selbst mit freiem Thread, sodass auch alle implementierten Ereignishandler freigegeben werden müssen. Von besonderer Bedeutung ist die Verwendung von Windows-APIs. Dies kann dazu führen, dass ein Wechsel zu einem anderen Thread erfolgt, da der Ereignishandler nicht garantiert auf demselben Thread ausgeführt wird wie das Fenster, das mit dem Ink-Collector verbunden ist.

// Invoke translates from IDispatch to an event callout
//  that can be overriden 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;
}
...

Die Init -Methode ruft CoCreateFreeThreadedMarshaler auf, um einen freien Thread-Marshaller einzurichten.

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

Die AdviseInkCollector -Methode richtet die Verbindung zwischen dem InkCollector-Objekt und dieser Klasse ein. Zuerst wird ein Verbindungspunkt zum Ink-Collector abgerufen. Anschließend wird ein Zeiger auf die IInkCollectorEvents abgerufen, sodass eine Empfehlungsverbindung mit dem Steuerelement hergestellt werden kann.

// 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;
}

Die UnadviseInkCollector -Methode gibt die Verbindungen frei, die das Objekt mit dem -Steuerelement hat.

// 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;
}

Definieren eines Ink Collector-Ereignishandlers

Die CMyInkEvents-Klasse überschreibt das Standardverhalten des Stroke-Ereignishandlers der InkCollectorEvents-Klasse. Die Stroke-Methode zeigt ein Meldungsfeld an, wenn inkCollector ein Stroke-Ereignis empfängt.

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;
};

Definieren eines Ink Collector Wrappers

Die Init-Methode der CMyInkCollector-Klasse deklariert und initialisiert ein CMyInkEvents-Objekt. Anschließend wird ein InkCollector-Objekt erstellt und der Ink Collector und der Ereignishandler verknüpft. Schließlich wird der InkCollector an das Fenster angefügt und aktiviert.

// Handle all initializaton
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);
}

Zugreifen auf die Tablet PC-Schnittstellen und die Wrapperklassen

Schließen Sie zunächst die Header für Tablet PC Automation-Schnittstellen ein. Diese werden mit dem Microsoft Windows XP Tablet PC Edition Development Kit 1.7 installiert.

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

Schließen Sie dann die Header für die Wrapperklassen ein, und der InkCollector-Ereignishandler wurde definiert.

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

Aufrufen der Wrapperklassen

Wenn das Fenster erstellt wird, erstellt die Window-Prozedur einen Ink Collector-Wrapper und initialisiert den Wrapper. Wenn das Fenster zerstört wird, löscht die Window-Prozedur den Wrapper des Ink-Collectors. Der Wrapper des Ink-Collectors verarbeitet das Erstellen und Löschen des zugehörigen Ereignishandlers.

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;