/***************************************************************************** * (C) COPYRIGHT MICROSOFT CORPORATION, 2002 * * AUTHOR: ByronC * * DATE: 3/24/2002 * * @doc INTERNAL * * @module WiaEventClient.cpp - Implementation of the class | * * This file contains the implementation for the base class. * *****************************************************************************/ #include "precomp.h" #include "wia.h" /***************************************************************************** * @doc INTERNAL * * @mfunc | WiaEventClient | WiaEventClient | * * We initialize all member variables. In general, this sets the values to 0, * except: * is set to be WiaEventClient_UNINIT_SIG. * is set to be 1. * is set to be ClientContext. * *****************************************************************************/ WiaEventClient::WiaEventClient(STI_CLIENT_CONTEXT ClientContext) : m_ulSig(WiaEventClient_UNINIT_SIG), m_cRef(1), m_ClientContext(ClientContext), m_bRemove(FALSE) { DBG_FN(WiaEventClient); } /***************************************************************************** * @doc INTERNAL * * @mfunc | WiaEventClient | ~WiaEventClient | * * Do any cleanup that is not already done. We call: * * * * Also: * is set to be WiaEventClient_DEL_SIG. * *****************************************************************************/ WiaEventClient::~WiaEventClient() { DBG_FN(~WiaEventClient destructor); m_ulSig = WiaEventClient_DEL_SIG; m_cRef = 0; m_ClientContext = NULL; DestroyRegistrationList(); DestroyPendingEventList(); } /***************************************************************************** * @doc INTERNAL * * @mfunc ULONG | WiaEventClient | AddRef | * * Increments this object's ref count. We should always AddRef when handing * out a pointer to this object. * * @rvalue Count | * The reference count after the count has been incremented. *****************************************************************************/ ULONG __stdcall WiaEventClient::AddRef() { InterlockedIncrement((long*) &m_cRef); return m_cRef; } /***************************************************************************** * @doc INTERNAL * * @mfunc ULONG | WiaEventClient | Release | * * Decrement this object's ref count. We should always Release when finished * with a pointer to this object. * * @rvalue Count | * The reference count after the count has been decremented. *****************************************************************************/ ULONG __stdcall WiaEventClient::Release() { ULONG ulRefCount = m_cRef - 1; if (InterlockedDecrement((long*) &m_cRef) == 0) { delete this; return 0; } return ulRefCount; } /***************************************************************************** * @doc INTERNAL * * @mfunc HRESULT | WiaEventClient | Initialize | * * Create and initialize any dependant objects/resources. Specifically: * - Check that is initialized * correctly. * * If this method fails, the object should not be used - it should be * destroyed immediately. * * @rvalue S_OK | * The method succeeded. * @rvalue E_UNEXPECTED | * The object could not be intialized sucessfully. *****************************************************************************/ HRESULT WiaEventClient::Initialize() { HRESULT hr = S_OK; if (!m_csClientSync.IsInitialized()) { DBG_ERR(("Runtime event Error: WiaEventClient's sync primitive could not be created")); hr = E_UNEXPECTED; } if (SUCCEEDED(hr)) { m_ulSig = WiaEventNotifier_INIT_SIG; } return hr; } /***************************************************************************** * @doc INTERNAL * * @mfunc BOOL | WiaEventClient | IsRegisteredForEvent | * * Checks whether the client has at least one event registration that matches * this event. * * @parm WiaEventInfo* | pWiaEventInfo | * Indicates WIA Device event * * @rvalue TRUE | * The client is registered to receive this event. * @rvalue FALSE | * The client is not registered. *****************************************************************************/ BOOL WiaEventClient::IsRegisteredForEvent( WiaEventInfo *pWiaEventInfo) { BOOL bRegistered = FALSE; if (pWiaEventInfo) { BSTR bstrDeviceID = pWiaEventInfo->getDeviceID(); GUID guidEvent = pWiaEventInfo->getEventGuid(); TAKE_CRIT_SECT t(m_csClientSync); // // We put an exception handler around our code to ensure that the // crtitical section is exited properly. // _try { // // Walk the list and see if we can find it // EventRegistrationInfo *pEventRegistrationInfo = NULL; CSimpleLinkedList::Iterator iter; for (iter = m_ListOfEventRegistrations.Begin(); iter != m_ListOfEventRegistrations.End(); ++iter) { pEventRegistrationInfo = *iter; if (pEventRegistrationInfo) { if (pEventRegistrationInfo->MatchesDeviceEvent(bstrDeviceID, guidEvent)) { // // We found a registration matching this event, set the return and break from the loop // bRegistered = TRUE; break; } } else { // // Log Error // pEventRegistrationInfo should never be NULL DBG_ERR(("Runtime event Error: While searching for an equal registration, we hit a NULL pEventRegistrationInfo!")); } } } _except(EXCEPTION_EXECUTE_HANDLER) { DBG_ERR(("Runtime event Error: The WiaEventClient caught an exception (0x%08X) trying to check for an event registration", GetExceptionCode())); // TBD: Should we re-throw the exception? } } else { DBG_ERR(("Runtime event Error: The WiaEventClient cannot check whether the client is registered for a NULL WIA Event")); } return bRegistered; } /***************************************************************************** * @doc INTERNAL * * @mfunc HRESULT | WiaEventClient | RegisterUnregisterForEventNotification | * * Description goes here * * @parm EventRegistrationInfo | pEventRegistrationInfo | * Pointer to a class containing the registration data to add. * This method will make a copy of the structure and insert it into the * relevant list. * * @rvalue S_OK | * The method succeeded. * @rvalue S_FALSE | * We are already registered for this. * @rvalue E_XXXXXXXX | * Could not update event registration. *****************************************************************************/ HRESULT WiaEventClient::RegisterUnregisterForEventNotification( EventRegistrationInfo *pEventRegistrationInfo) { HRESULT hr = S_OK; if (pEventRegistrationInfo) { // // We always have to walk through the list. This is because when we add, we need // to check whether it already exists. When we remove, we need to find the // element to remove. // So, try and find the element here. // EventRegistrationInfo *pExistingReg = FindEqualEventRegistration(pEventRegistrationInfo); // // Check whether this is registration or unregistration. // NOTE: Since unregistration is typically done via the RegistrationCookie, // our hueristic for this is that if it is not specifically an UnRegistration, // then it is considered a registration. // if (pEventRegistrationInfo->getFlags() & WIA_UNREGISTER_EVENT_CALLBACK) { if (pExistingReg != NULL) { // // Release it and remove it from our list. // m_ListOfEventRegistrations.Remove(pExistingReg); pExistingReg->Release(); DBG_TRC(("Removed registration:")); pExistingReg->Dump(); } else { DBG_ERR(("Runtime event Error: Attempting to unregister when you have not first registered")); hr = E_INVALIDARG; } } else // This is considered a registration { if (pExistingReg == NULL) { // // Add it to our list. We AddRef it here since we're keeping a reference to it. // m_ListOfEventRegistrations.Prepend(pEventRegistrationInfo); pEventRegistrationInfo->AddRef(); DBG_TRC(("Added new registration:")); pEventRegistrationInfo->Dump(); hr = S_OK; } else { DBG_WRN(("Runtime event client Error: Registration already exists in the list")); hr = S_FALSE; } } // // We need to release pExistingReg due to the AddRef from the lookup. // if (pExistingReg) { pExistingReg->Release(); pExistingReg = NULL; } } else { DBG_ERR(("Runtime event Error: Cannot handle a NULL registration")); hr = E_POINTER; } return hr; } /***************************************************************************** * @doc INTERNAL * * @mfunc HRESULT | WiaEventClient | AddPendingEventNotification | * * Description goes here * * @parm WiaEventInfo* | pWiaEventInfo | * Pointer to a object which contains event info that * must be sent to the client. This class is AddRef'd when added to the * list. * * @rvalue S_OK | * The method succeeded. * @rvalue E_UNEXPECTED | * The object could not be added sucessfully. *****************************************************************************/ HRESULT WiaEventClient::AddPendingEventNotification( WiaEventInfo *pWiaEventInfo) { HRESULT hr = S_OK; TAKE_CRIT_SECT t(m_csClientSync); // // We put an exception handler around our code to ensure that the // crtitical section is exited properly. // _try { DBG_TRC(("Added another pending event to %p", m_ClientContext)); m_ListOfEventsPending.Enqueue(pWiaEventInfo); pWiaEventInfo->AddRef(); } _except(EXCEPTION_EXECUTE_HANDLER) { DBG_ERR(("Runtime event Error: The WiaEventClient caught an exception (0x%08X) trying to add a pending event", GetExceptionCode())); // TBD: Should we re-throw the exception? hr = E_UNEXPECTED; } return hr; } /***************************************************************************** * @doc INTERNAL * * @mfunc STI_CLIENT_CONTEXT | WiaEventClient | getClientContext | * * Returns the context which uniquely identifies the client. * * @rvalue STI_CLIENT_CONTEXT | * The context identifyin this client. *****************************************************************************/ STI_CLIENT_CONTEXT WiaEventClient::getClientContext() { return m_ClientContext; } /***************************************************************************** * @doc INTERNAL * * @mfunc EventRegistrationInfo* | WiaEventClient | FindEqualEventRegistration | * * Checks whether a semantically equal is in the list. * If it is, we retrieve it. Note that caller must Release it. * * @parm EventRegistrationInfo | pEventRegistrationInfo | * Specifies a we're looking for in our list. * * @rvalue NULL | * We could not find it. * @rvalue non-NULL | * The equivalent exists. Caller must Release. *****************************************************************************/ EventRegistrationInfo* WiaEventClient::FindEqualEventRegistration( EventRegistrationInfo *pEventRegistrationInfo) { EventRegistrationInfo *pRet = NULL; if (pEventRegistrationInfo) { TAKE_CRIT_SECT t(m_csClientSync); // // We put an exception handler around our code to ensure that the // crtitical section is exited properly. // _try { // // Walk the list and see if we can find it // EventRegistrationInfo *pElem = NULL; CSimpleLinkedList::Iterator iter; for (iter = m_ListOfEventRegistrations.Begin(); iter != m_ListOfEventRegistrations.End(); ++iter) { pElem = *iter; if (pElem) { if (pElem->Equals(pEventRegistrationInfo)) { // // We found it, so AddRef it and set the return // pElem->AddRef(); pRet = pElem; break; } } else { // // Log Error // pEventRegistrationInfo should never be NULL DBG_ERR(("Runtime event Error: While searching for an equal registration, we hit a NULL pEventRegistrationInfo!")); } } } _except(EXCEPTION_EXECUTE_HANDLER) { DBG_ERR(("Runtime event Error: The WiaEventClient caught an exception (0x%08X) trying to find an equal event registration", GetExceptionCode())); // TBD: Should we re-throw the exception? } } return pRet; } /***************************************************************************** * @doc INTERNAL * * @mfunc VOID | WiaEventClient | DestroyRegistrationList | * * Frees all resources associated with the registration list by releasing all elements * in it, and then destroying the links in the list. *****************************************************************************/ VOID WiaEventClient::DestroyRegistrationList() { TAKE_CRIT_SECT t(m_csClientSync); // // We put an exception handler around our code to ensure that the // crtitical section is exited properly. // _try { // // Walk the list of registrations release all elements. Then destroy the list. // EventRegistrationInfo *pElem = NULL; CSimpleLinkedList::Iterator iter; for (iter = m_ListOfEventRegistrations.Begin(); iter != m_ListOfEventRegistrations.End(); ++iter) { pElem = *iter; if (pElem) { pElem->Release(); } } m_ListOfEventRegistrations.Destroy(); } _except(EXCEPTION_EXECUTE_HANDLER) { DBG_ERR(("Runtime event Error: The WiaEventClient caught an exception (0x%08X) trying to destroy the registration list", GetExceptionCode())); // TBD: Should we re-throw the exception? } } /***************************************************************************** * @doc INTERNAL * * @mfunc VOID | WiaEventClient | DestroyPendingEventList | * * Frees all resources associated with the pending event list by releasing all elements * in it, and then destroying the links in the list. *****************************************************************************/ VOID WiaEventClient::DestroyPendingEventList() { TAKE_CRIT_SECT t(m_csClientSync); // // We put an exception handler around our code to ensure that the // crtitical section is exited properly. // _try { // // Walk the list of registrations release all elements. Then destroy the list. // WiaEventInfo *pElem = NULL; CSimpleLinkedList::Iterator iter; for (iter = m_ListOfEventsPending.Begin(); iter != m_ListOfEventsPending.End(); ++iter) { pElem = *iter; if (pElem) { pElem->Release(); } } m_ListOfEventsPending.Destroy(); } _except(EXCEPTION_EXECUTE_HANDLER) { DBG_ERR(("Runtime event Error: The WiaEventClient caught an exception (0x%08X) trying to destroy the registration list", GetExceptionCode())); // TBD: Should we re-throw the exception? } } /***************************************************************************** * @doc INTERNAL * * @mfunc VOID | WiaEventClient | MarkForRemoval | * * Sets the mark to indicate that this object should be removed at the next * possible convenience (i.e. we use lazy deletion). * *****************************************************************************/ VOID WiaEventClient::MarkForRemoval() { DBG_TRC(("Client %p marked for removal", m_ClientContext)); m_bRemove = TRUE; } /***************************************************************************** * @doc INTERNAL * * @mfunc BOOL | WiaEventClient | isMarkedForRemoval | * * Check the mark to indicate whether this object should be removed. * * @rvalue TRUE | * This object can/should be removed. * @rvalue FALSE | * This object is not marked for removal. *****************************************************************************/ BOOL WiaEventClient::isMarkedForRemoval() { return m_bRemove; }