Exemple récepteurs d’événements C++

Ce programme montre comment créer une application qui capture les événements InkCollector en utilisant uniquement C++. Ce programme co-crée un objet InkCollector pour ink-enable the window. Il affiche une boîte de message chaque fois qu’un événement Stroke est reçu.

Définition d’un wrapper pour les événements du collecteur d’encre

La InkCollectorEvents classe gère la transmission des événements du collecteur d’encre à l’utilisateur de cette classe. La AdviseInkCollector méthode configure la connexion entre l’objet InkCollector et cette classe. La Invoke méthode convertit la notification d’événement IDispatch en un appel à une fonction virtuelle que l’utilisateur de cette classe peut remplacer pour traiter un événement particulier.

Notes

Vous devez faire plus que remplacer la fonction virtuelle pour qu’un gestionnaire d’événements obtienne cet événement. Pour tous les événements sauf les événements par défaut, vous devez appeler la méthode SetEventInterest du collecteur d’encre pour garantir l’obtention d’un événement. Deuxièmement, cet objet marshale lui-même le thread libre, de sorte que tous les gestionnaires d’événements implémentés doivent également être threads libres. Il est particulièrement important d’utiliser les API Windows, qui peuvent entraîner un basculement vers un autre thread, car il n’est pas garanti que le gestionnaire d’événements s’exécute sur le même thread que la fenêtre connectée au collecteur d’encre.

 

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

La Init méthode appelle CoCreateFreeThreadedMarshaler pour configurer un marshaleur thread libre.

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

La AdviseInkCollector méthode configure la connexion entre l’objet InkCollector et cette classe. Il récupère d’abord un point de connexion au collecteur d’encre. Ensuite, il récupère un pointeur vers le IInkCollectorEvents afin qu’il puisse établir une connexion de conseil au contrôle.

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

La UnadviseInkCollector méthode libère les connexions de l’objet au contrôle.

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

Définition d’un gestionnaire d’événements du collecteur d’encre

La classe CMyInkEvents remplace le comportement par défaut du gestionnaire d’événements Stroke de la classe InkCollectorEvents. La méthode Stroke affiche une zone de message lorsque InkCollector reçoit un événement 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;
};

Définition d’un wrapper de collecteur d’encre

La méthode Init de la classe CMyInkCollector déclare et initialise un objet CMyInkEvents. Il crée ensuite un objet InkCollector et associe le collecteur d’encre et le gestionnaire d’événements. Enfin, inkCollector est attaché à la fenêtre et activé.

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

Accès aux interfaces Tablet PC et aux classes Wrapper

Tout d’abord, incluez les en-têtes pour les interfaces Tablet PC Automation. Ils sont installés avec le type d’entité Microsoft<="reg"/> entité Windows<type="reg"/> XP Tablet PC Edition Development Kit 1.7.

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

Ensuite, incluez les en-têtes des classes wrapper et le gestionnaire d’événements InkCollector a été défini.

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

Appel des classes Wrapper

Lorsque la fenêtre est créée, la procédure Window crée un wrapper de collecteur d’encre et initialise le wrapper. Lorsque la fenêtre est détruite, la procédure Window supprime le wrapper du collecteur d’encre. Le wrapper du collecteur d’encre gère la création et la suppression de son gestionnaire d’événements associé.

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;