/***************************************************************************** * (C) COPYRIGHT MICROSOFT CORPORATION, 2002 * * AUTHOR: ByronC * * DATE: 3/25/2002 * * @doc INTERNAL * * @module AsyncRPCEventClient.cpp - Declaration for | * * This file contains the implmentation for the class. * *****************************************************************************/ #include "precomp.h" /***************************************************************************** * @doc INTERNAL * * @mfunc | AsyncRPCEventClient | AsyncRPCEventClient | * * This constructor simply calls the base class constructor. * *****************************************************************************/ AsyncRPCEventClient::AsyncRPCEventClient( STI_CLIENT_CONTEXT SyncClientContext) : WiaEventClient(SyncClientContext) { DBG_FN(AsyncRPCEventClient); m_pAsyncState = NULL; m_pAsyncEventData = NULL; } /***************************************************************************** * @doc INTERNAL * * @mfunc | AsyncRPCEventClient | ~AsyncRPCEventClient | * * This destructor aborts any outstanding AsyncRPC calls. * Remember: The base classes's destructor will also be called. * *****************************************************************************/ AsyncRPCEventClient::~AsyncRPCEventClient() { DBG_FN(~AsyncRPCEventClient); // // Abort any outstanding Async RPC calls // if (m_pAsyncState) { RPC_STATUS rpcStatus = RpcAsyncAbortCall(m_pAsyncState, RPC_S_CALL_CANCELLED); m_pAsyncState = NULL; } } /***************************************************************************** * @doc INTERNAL * * @mfunc HRESULT | AsyncRPCEventClient | setAsyncState | * * Saves the async rpc params for this client * * @parm RPC_ASYNC_STATE | pAsyncState | * Pointer to the async rpc state structure used to keep track of a * specific Async call. * @parm WIA_ASYNC_EVENT_NOTIFY_DATA | pAsyncEventData | * Pointer to the out parameter used to store event notification data. * *****************************************************************************/ HRESULT AsyncRPCEventClient::saveAsyncParams( RPC_ASYNC_STATE *pAsyncState, WIA_ASYNC_EVENT_NOTIFY_DATA *pAsyncEventData) { HRESULT hr = S_OK; if (pAsyncState) { TAKE_CRIT_SECT t(m_csClientSync); // // We put an exception handler around our code to ensure that the // crtitical section is exited properly. // _try { // // Abort any outstanding Async RPC calls // if (m_pAsyncState) { RPC_STATUS rpcStatus = RpcAsyncAbortCall(m_pAsyncState, RPC_S_CALL_CANCELLED); m_pAsyncState = NULL; m_pAsyncEventData = NULL; } m_pAsyncState = pAsyncState; m_pAsyncEventData = pAsyncEventData; // // Now that we have an outstanding AsyncRPC call, send the next event // notification. // The return value for that call should not affect the return value for // here, so we use a new variable: hres. // HRESULT hres = SendNextEventNotification(); } _except(EXCEPTION_EXECUTE_HANDLER) { DBG_ERR(("We caught exception 0x%08X trying to update client's async state", GetExceptionCode())); hr = E_UNEXPECTED; // TBD: Rethrow the exception? } } else { hr = E_POINTER; } return hr; } /***************************************************************************** * @doc INTERNAL * * @mfunc HRESULT | AsyncRPCEventClient | AddPendingEventNotification | * * This method call's the base class * first. * * Then, if we have an outstanding Async RPC call, we complete it to signify * the event notification. * * @rvalue S_OK | * The method succeeded. * @rvalue E_XXXXXXX | * The method failed. It is not given whether the adding of the * event failed, or the actual notification *****************************************************************************/ HRESULT AsyncRPCEventClient::AddPendingEventNotification( WiaEventInfo *pWiaEventInfo) { HRESULT hr = S_OK; hr = WiaEventClient::AddPendingEventNotification(pWiaEventInfo); if (SUCCEEDED(hr)) { // // Send this event notification if possible. hr = SendNextEventNotification(); } else { DBG_ERR(("Runtime event client Error: Failed to add pending notification to AsyncRPCWiaEventClient")); } return hr; } /***************************************************************************** * @doc INTERNAL * * @mfunc BOOL | AsyncRPCEventClient | IsRegisteredForEvent | * * Checks whether the client has at least one event registration that matches * this event. * * This method first checks whether we have an outstanding AsyncRPC call - if * we do, it checks whether the client has died. If it has, it returns false. * Otherwise, it calls the base class method . * * @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 AsyncRPCEventClient::IsRegisteredForEvent( WiaEventInfo *pWiaEventInfo) { BOOL bRet = FALSE; RPC_STATUS rpcStatus = RPC_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 { // // Check whether we have an outstanding AsyncRPC call. // If we do, check the status. Is the status is abnormal, // abort the call (a normal status is RPC_S_CALL_IN_PROGRESS indicating that // the call is still in progress). // if (m_pAsyncState) { rpcStatus = RpcServerTestCancel(RpcAsyncGetCallHandle (m_pAsyncState)); if ((rpcStatus == RPC_S_CALL_IN_PROGRESS) || (rpcStatus == RPC_S_OK)) { rpcStatus = RPC_S_OK; } else { rpcStatus = RpcAsyncAbortCall(m_pAsyncState, RPC_S_CALL_CANCELLED); m_pAsyncState = NULL; MarkForRemoval(); } } if (rpcStatus == RPC_S_OK) { bRet = WiaEventClient::IsRegisteredForEvent(pWiaEventInfo); } } _except(EXCEPTION_EXECUTE_HANDLER) { DBG_ERR(("Runtime event client error: We caught exception 0x%08X trying to check client's registration", GetExceptionCode())); // TBD: Rethrow the exception? } return bRet; } /***************************************************************************** * @doc INTERNAL * * @mfunc HRESULT | AsyncRPCEventClient | SendNextEventNotification | * * The operation of this method is as follows: * 1. Checks whether client can receive notifications. * A client can receive notification if we have a valid Async RPC state. * 2. If it can, we check whether there are any pending events in the queue. * 3. If the client can receive notifications, and there are events pending, * we pop the next pending event and send it. * * If any condition is not met, it is not an error - we report back S_OK. * * @rvalue S_OK | * There were no errors. * @rvalue E_XXXXXXXX | * We could not send the notification. *****************************************************************************/ HRESULT AsyncRPCEventClient::SendNextEventNotification() { HRESULT hr = S_OK; WiaEventInfo *pWiaEventInfo = NULL; TAKE_CRIT_SECT t(m_csClientSync); // // We put an exception handler around our code to ensure that the // crtitical section is exited properly. // _try { // // Check whether the client is ready to receive events yet // if (m_pAsyncState && m_pAsyncEventData) { RPC_STATUS rpcStatus = RPC_S_OK; DWORD dwClientRet = RPC_S_OK; if (m_ListOfEventsPending.Dequeue(pWiaEventInfo)) { if (pWiaEventInfo) { // // We have the event - let's prepare the data. // m_pAsyncEventData->EventGuid = pWiaEventInfo->getEventGuid(); m_pAsyncEventData->bstrEventDescription = SysAllocString(pWiaEventInfo->getEventDescription()); m_pAsyncEventData->bstrDeviceID = SysAllocString(pWiaEventInfo->getDeviceID()); m_pAsyncEventData->bstrDeviceDescription = SysAllocString(pWiaEventInfo->getDeviceDescription()); m_pAsyncEventData->bstrFullItemName = SysAllocString(pWiaEventInfo->getFullItemName()); m_pAsyncEventData->dwDeviceType = pWiaEventInfo->getDeviceType(); m_pAsyncEventData->ulEventType = pWiaEventInfo->getEventType(); // // We're done with pWiaEventInfo, so we can release it here // pWiaEventInfo->Release(); pWiaEventInfo = NULL; // // Let's send the event notification // rpcStatus = RpcAsyncCompleteCall(m_pAsyncState, &dwClientRet); if (rpcStatus != RPC_S_OK) { hr = HRESULT_FROM_WIN32(rpcStatus); } // // Since we've sent the notification, our async params are invalid. // Clear them now. // m_pAsyncState = NULL; m_pAsyncEventData = NULL; } } } } _except(EXCEPTION_EXECUTE_HANDLER) { DBG_ERR(("Runtime event client error: We caught exception 0x%08X trying to send pending event", GetExceptionCode())); hr = E_UNEXPECTED; // TBD: Rethrow the exception? } return hr; }