/***************************************************************************** * (C) COPYRIGHT MICROSOFT CORPORATION, 2002 * * AUTHOR: ByronC * * DATE: 4/10/2002 * * @doc INTERNAL * * @module WiaEventHandlerLookup.cpp - Implementation for | * * This file contains the implementation for the class. * *****************************************************************************/ #include "precomp.h" /***************************************************************************** * @doc INTERNAL * * @mfunc | WiaEventHandlerLookup | WiaEventHandlerLookup | * * We initialize all member variables. In general, this sets the values to 0, * except: * is set to be WiaEventHandlerLookup_INIT_SIG. * is set to be 1. * *****************************************************************************/ WiaEventHandlerLookup::WiaEventHandlerLookup( const CSimpleStringWide &cswEventKeyRoot) : m_ulSig(WiaEventHandlerLookup_INIT_SIG), m_cRef(1), m_cswEventKeyRoot(cswEventKeyRoot), m_pEventHandlerInfo(NULL) { } /***************************************************************************** * @doc INTERNAL * * @mfunc | WiaEventHandlerLookup | WiaEventHandlerLookup | * * We initialize all member variables. In general, this sets the values to 0, * except: * is set to be WiaEventHandlerLookup_INIT_SIG. * is set to be 1. * *****************************************************************************/ WiaEventHandlerLookup::WiaEventHandlerLookup() : m_ulSig(WiaEventHandlerLookup_INIT_SIG), m_cRef(1), m_pEventHandlerInfo(NULL) { } /***************************************************************************** * @doc INTERNAL * * @mfunc | WiaEventHandlerLookup | ~WiaEventHandlerLookup | * * Do any cleanup that is not already done. * * Also: * is set to be WiaEventHandlerLookup_DEL_SIG. * *****************************************************************************/ WiaEventHandlerLookup::~WiaEventHandlerLookup() { m_ulSig = WiaEventHandlerLookup_DEL_SIG; m_cRef = 0; } /***************************************************************************** * @doc INTERNAL * * @mfunc ULONG | WiaEventHandlerLookup | 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 WiaEventHandlerLookup::AddRef() { InterlockedIncrement((long*) &m_cRef); return m_cRef; } /***************************************************************************** * @doc INTERNAL * * @mfunc ULONG | WiaEventHandlerLookup | 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 WiaEventHandlerLookup::Release() { ULONG ulRefCount = m_cRef - 1; if (InterlockedDecrement((long*) &m_cRef) == 0) { delete this; return 0; } if (m_pEventHandlerInfo) { m_pEventHandlerInfo->Release(); m_pEventHandlerInfo = NULL; } return ulRefCount; } /***************************************************************************** * @doc INTERNAL * * @mfunc EventHandlerInfo* | WiaEventHandlerLookup | getPersistentHandlerForDeviceEvent | * * This static method is used to find the WIA persistent event handler * registered for a particular device event. * * The heuristics used is as follows: * * 1. First, let's look for the prompt registered for this event. * 2. If one doesn't exist, try and grab the prompt for the STI_PROXY_EVENT. * 3. If we cannot find it, grab the first event handler for this event we can find. * 4. If that doesn't exist, just find the first handler for the STI_PROXY_EVENT. * 5. If none was found, we have no handlers for this event. * * Note: This method clears * * @parm CSimpleString& | cswDeviceID | * The WIA DeviceID on which this event occured * @parm GUID& | guidEvent | * The WIA event guid indicating which event occured * * @rvalue NULL | * There is no handler registered which can accept this device event. * @rvalue non-NULL | * A pointer to a describing the registered * handler. Caller must Release. *****************************************************************************/ EventHandlerInfo* WiaEventHandlerLookup::getPersistentHandlerForDeviceEvent( const CSimpleStringWide &cswDeviceID, const GUID &guidEvent) { EventHandlerInfo *pEventHandlerInfo = NULL; m_cswEventKeyRoot = L""; // // Get the device key for this device id. We can then do a lookup on the device's event // subkey to look for a default handler. // We will skip this lookup if we cannot find the Device key path // WiaDeviceKey wiaDeviceKey(cswDeviceID); if (wiaDeviceKey.getDeviceKeyPath().Length() > 0) { CSimpleString cswDeviceEventKey = wiaDeviceKey.getDeviceKeyPath() + EVENT_STR; setEventKeyRoot(cswDeviceEventKey); pEventHandlerInfo = getHandlerRegisteredForEvent(guidEvent); } // // If we haven't found it yet, let's check for global handlers // if (!pEventHandlerInfo) { // // 1. First, let's look for the prompt registered for this event. // 2. If one doesn't exist, try and grab the prompt for the STI_PROXY_EVENT. // 3. If we cannot find it, grab the first event handler for this event we can find. // 4. If that doesn't exist, just find the first handler for the STI_PROXY_EVENT. // 5. If none was found, we have no handlers for this event. // setEventKeyRoot(GLOBAL_HANDLER_REGPATH); pEventHandlerInfo = getHandlerFromCLSID(guidEvent, WIA_EVENT_HANDLER_PROMPT); if (!pEventHandlerInfo) { // // 2. Try and grab the prompt for the STI_PROXY_EVENT. // pEventHandlerInfo = getHandlerFromCLSID(WIA_EVENT_STI_PROXY, WIA_EVENT_HANDLER_PROMPT); } if (!pEventHandlerInfo) { // // 3. Grab the first event handler for this event we can find. // pEventHandlerInfo = getHandlerRegisteredForEvent(guidEvent); } if (!pEventHandlerInfo) { // // 4. Just find the first handler for the STI_PROXY_EVENT.. // pEventHandlerInfo = getHandlerRegisteredForEvent(WIA_EVENT_STI_PROXY); } } return pEventHandlerInfo; } /***************************************************************************** * @doc INTERNAL * * @mfunc VOID | WiaEventHandlerLookup | setEventKeyRoot | * * Description goes here * * @parm CSimpleString& | cswNewEventKeyPath | * The new event key path to use as root for our lookups. * *****************************************************************************/ VOID WiaEventHandlerLookup::setEventKeyRoot( const CSimpleString& cswNewEventKeyPath) { m_cswEventKeyRoot = cswNewEventKeyPath; } /***************************************************************************** * @doc INTERNAL * * @mfunc EventHandlerInfo* | WiaEventHandlerLookup | getHandlerRegisteredForDeviceEvent | * * In WIA, a handler registers for Device/Event pairs. When an event occurs, * a handler registered for that event needs to be found. * Note that by the time we use this class to look for an event handler, we already * know that we have a match on Device ID (WIA events are always matched by * Event and Device pairs). This is quitre easily explained with an example: * When searching for a handler, we might use logic like: * EventHandlerInfo *pInfo = NULL; * WiaEventHandlerLookup deviceSpecificLookup(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Class\\{6BDD1FC6-810F-11D0-BEC7-08002BE2092F}\\0003\\Events"); * pInfo = deviceSpecificLookup.getHandlerRegisteredForEvent(guidEvent); * if (!pInfo) * { * // * // Didn't find a handler registered for that device so let's try the globals * // * WiaEventHandlerLookup globalLookup(L"SYSTEM\\CurrentControlSet\\Control\\StillImage\\Events"); * pInfo.globalLookup.getHandlerRegisteredForEvent(guidEvent); * . * . * . and so on * . * }; * * This method walks the registry, starting from , * and returns a pointer to a describing the registered * handler for this device event. * * @parm GUID | guidEvent | * A guid indicating the WIA event. * * @rvalue NULL | * There is no handler registered which can accept this device event. * @rvalue non-NULL | * A pointer to a describing the registered * handler. Caller must Release. *****************************************************************************/ EventHandlerInfo* WiaEventHandlerLookup::getHandlerRegisteredForEvent( const GUID &guidEvent) { EventHandlerInfo *pEventHandlerInfo = NULL; // // Ensure we do not have any event info left lying around. // if (m_pEventHandlerInfo) { m_pEventHandlerInfo->Release(); m_pEventHandlerInfo = NULL; } // // Save the parameters in member fields so we can search on them during // reg key enumeration. Enumeration is done via procedure callbacks, // in which we pass (this) as a parameter. // WCHAR wszGuid[40]; if (StringFromGUID2(guidEvent, wszGuid, sizeof(wszGuid)/sizeof(wszGuid[0]))) { wszGuid[(sizeof(wszGuid)/sizeof(wszGuid[0])) - 1] = L'\0'; m_cswEventGuidString = wszGuid; } // // Open the registery at the desired place. We only require READ access and // we do not want to create it if it doesn't exist. // CSimpleReg csrEventRoot(HKEY_LOCAL_MACHINE, m_cswEventKeyRoot, false, KEY_READ, NULL); // // Enumerate the sub-keys looking for the sub-key corresponding to guidEvent. // bool bKeyNotFound = csrEventRoot.EnumKeys(WiaEventHandlerLookup::ProcessEventSubKey, (LPARAM)this); if (bKeyNotFound) { DBG_TRC(("Key was not found!")); } else { DBG_TRC(("We found key %ws, looking for default handler...", m_cswEventKey.String())); // // First, check whether we have a specific entry for the default handler. // CSimpleReg csrEventKey(csrEventRoot.GetKey(), m_cswEventKey.String()); CSimpleStringWide cswDefault = csrEventKey.Query(DEFAULT_HANDLER_VALUE_NAME, L""); if (cswDefault.Length() > 0) { // // Try and open the key specified by the default handler entry. // CSimpleReg csrDefautHandler(csrEventKey.GetKey(), cswDefault); if (csrEventKey.OK()) { // // Fill in the handler info from the handler entry // pEventHandlerInfo = CreateHandlerInfoFromKey(csrDefautHandler); } } // // If we could not find the default, we will just take the first one we find. // TBD: Should we enumerate and return the last one registered instead? WinXP bits // did not do this... // if (!pEventHandlerInfo) { // // Set the Handler CLSID to the empty string, since we're not looking for a specific handler, // any one while do. // m_cswHandlerCLSID = L""; csrEventKey.EnumKeys(WiaEventHandlerLookup::ProcessHandlerSubKey, (LPARAM)this); // // Swap pEventHandlerInfo with m_pEventHandlerInfo. m_pEventHandlerInfo will // be non-NULL if we were successfull. // Be sure to set it to NULL so we don't release it if this function is called again // - only the caller should release this object. // pEventHandlerInfo = m_pEventHandlerInfo; m_pEventHandlerInfo = NULL; } // Diagnostic only if (pEventHandlerInfo) { DBG_TRC(("Found handler:")); pEventHandlerInfo->Dump(); } else { DBG_TRC(("No handler could be found")); } } return pEventHandlerInfo; } /***************************************************************************** * @doc INTERNAL * * @mfunc EventHandlerInfo* | WiaEventHandlerLookup | getHandlerRegisteredForDeviceEvent | * * This method walks the registry, starting from , * searches for the event subkey matching

. It enumerates all handlers * under that key and finds the one whose CLSID matches

and * returns a pointer to a . * * @parm GUID | guidEvent | * A guid indicating the WIA event. * @parm GUID& | guidHandlerCLSID | * A guid indicating the CLSID of the registered handler. * * @rvalue NULL | * There is no handler registered with this CLSID. * @rvalue non-NULL | * A pointer to a describing the registered * handler. Caller must Release. *****************************************************************************/ EventHandlerInfo* WiaEventHandlerLookup::getHandlerFromCLSID( const GUID &guidEvent, const GUID &guidHandlerCLSID) { EventHandlerInfo *pEventHandlerInfo = NULL; // // Ensure we do not have any event info left lying around. // if (m_pEventHandlerInfo) { m_pEventHandlerInfo->Release(); m_pEventHandlerInfo = NULL; } // // Save the parameters in member fields so we can search on them during // reg key enumeration. Enumeration is done via procedure callbacks, // in which we pass (this) as a parameter. // WCHAR wszGuid[40]; if (StringFromGUID2(guidHandlerCLSID, wszGuid, sizeof(wszGuid)/sizeof(wszGuid[0]))) { wszGuid[(sizeof(wszGuid)/sizeof(wszGuid[0])) - 1] = L'\0'; m_cswHandlerCLSID = wszGuid; } if (StringFromGUID2(guidEvent, wszGuid, sizeof(wszGuid)/sizeof(wszGuid[0]))) { wszGuid[(sizeof(wszGuid)/sizeof(wszGuid[0])) - 1] = L'\0'; m_cswEventGuidString = wszGuid; } DBG_TRC(("Looking for event %ws and CLSID %ws", m_cswEventGuidString.String(), m_cswHandlerCLSID.String())); // // Open the registery at the desired place. We only require READ access and // we do not want to create it if it doesn't exist. // CSimpleReg csrEventRoot(HKEY_LOCAL_MACHINE, m_cswEventKeyRoot, false, KEY_READ, NULL); // // Enumerate the sub-keys looking for the sub-key corresponding to guidEvent. // bool bKeyNotFound = csrEventRoot.EnumKeys(WiaEventHandlerLookup::ProcessEventSubKey, (LPARAM)this); if (bKeyNotFound) { DBG_TRC(("Key was not found!")); } else { DBG_TRC(("We found key %ws, looking for specific handler...", m_cswEventKey.String())); CSimpleReg csrEventKey(csrEventRoot.GetKey(), m_cswEventKey.String()); // // Search for the specific handler. m_cswHandlerCLSID has been primed with the // CLSID we're looking for. // csrEventKey.EnumKeys(WiaEventHandlerLookup::ProcessHandlerSubKey, (LPARAM)this); // // Swap pEventHandlerInfo with m_pEventHandlerInfo. m_pEventHandlerInfo will // be non-NULL if we were successfull. // Be sure to set it to NULL so we don't release it if this function is called again // - only the caller should release this object. // pEventHandlerInfo = m_pEventHandlerInfo; m_pEventHandlerInfo = NULL; // Diagnostic only if (pEventHandlerInfo) { DBG_TRC(("Found specific handler:")); pEventHandlerInfo->Dump(); } else { DBG_TRC(("No specific handler could be found")); } } return pEventHandlerInfo; } /***************************************************************************** * @doc INTERNAL * * @mfunc EventHandlerInfo* | WiaEventHandlerLookup | CreateHandlerInfoFromKey | * * Creates a object for the specified handler registry key. * * @parm CSimpleReg | csrHandlerKey | * Reg key of the handler entry * * @rvalue NULL | * We could not create the event handler info object. * @rvalue non-NULL | * We created the event handler info object. Caller must Release. *****************************************************************************/ EventHandlerInfo* WiaEventHandlerLookup::CreateHandlerInfoFromKey( CSimpleReg &csrHandlerKey) { EventHandlerInfo *pEventHandlerInfo = NULL; if (csrHandlerKey.OK()) { CSimpleString cswCLSID = csrHandlerKey.GetSubKeyName(); CSimpleString cswName = csrHandlerKey.Query(NAME_VALUE, L""); CSimpleString cswDescription = csrHandlerKey.Query(DESC_VALUE_NAME, L""); CSimpleString cswIcon = csrHandlerKey.Query(ICON_VALUE_NAME, L"");; CSimpleString cswCommandline = csrHandlerKey.Query(CMDLINE_VALUE_NAME, L""); GUID guidCLSID = GUID_NULL; CLSIDFromString((LPOLESTR)cswCLSID.String(), &guidCLSID); pEventHandlerInfo = new EventHandlerInfo(cswName, cswDescription, cswIcon, cswCommandline, guidCLSID); } return pEventHandlerInfo; } /***************************************************************************** * @doc INTERNAL * * @mfunc bool | WiaEventHandlerLookup | ProcessEventSubKey | * * This method is called on each sub-key as part of an enumeration of all * the event sub-keys. The enumeration will stop if we return false from * this method. * * @parm CKeyEnumInfo& | enumInfo | * Indicates the current sub-key we're on. * * @rvalue false | * Indicates we can stop with the enumeration. We found the correct * event key. * @rvalue true | * Indicates we should continue with the enumeration. *****************************************************************************/ bool WiaEventHandlerLookup::ProcessEventSubKey( CSimpleReg::CKeyEnumInfo &enumInfo) { bool bContinueEnumeration = TRUE; // // Check that we have a This pointer // WiaEventHandlerLookup *This = (WiaEventHandlerLookup*)enumInfo.lParam; if (This) { // // Open this sub-key. We're looking for a sub-key which contains a GUID entry // matching m_cswEventGuidString. // CSimpleReg csrEventSubKey(enumInfo.hkRoot, enumInfo.strName); CSimpleStringWide cswGuidValue = csrEventSubKey.Query(GUID_VALUE_NAME, L"{00000000-0000-0000-0000-000000000000}"); if (cswGuidValue.CompareNoCase(This->m_cswEventGuidString) == 0) { // // We found the key we're looking for. All we need to store is the name. // This->m_cswEventKey = enumInfo.strName; bContinueEnumeration = FALSE; } } return bContinueEnumeration; } /***************************************************************************** * @doc INTERNAL * * @mfunc bool | WiaEventHandlerLookup | ProcessHandlerSubKey | * * This method is called on each sub-key as part of an enumeration of * the handler sub-keys. Our current behavior is one of two options: * If is empty, stop enumeration after the * first one. * If is not empty, stop enumeration * only after finding the handler corresponding to that CLSID. * * On return, we set the * member. * * @parm CKeyEnumInfo& | enumInfo | * Indicates the current sub-key we're on. * * @rvalue false | * Indicates we can stop with the enumeration. We found the correct * handler. * @rvalue true | * Indicates we should continue with the enumeration. *****************************************************************************/ bool WiaEventHandlerLookup::ProcessHandlerSubKey( CSimpleReg::CKeyEnumInfo &enumInfo) { bool bContinueEnumeration = TRUE; // // Check that we have a This pointer // WiaEventHandlerLookup *This = (WiaEventHandlerLookup*)enumInfo.lParam; if (This) { // // Open this sub-key. // CSimpleReg csrHandlerSubKey(enumInfo.hkRoot, enumInfo.strName); if (csrHandlerSubKey.OK()) { // // Check whether we have to find a specific handler or just the first one. // if (This->m_cswHandlerCLSID.Length() > 0) { if (enumInfo.strName.CompareNoCase(This->m_cswHandlerCLSID) == 0) { // // This is the specific handler we're looking for. // This->m_pEventHandlerInfo = This->CreateHandlerInfoFromKey(csrHandlerSubKey); bContinueEnumeration = FALSE; } } else { // // We only want the first one, so this one will do // This->m_pEventHandlerInfo = This->CreateHandlerInfoFromKey(csrHandlerSubKey); bContinueEnumeration = FALSE; } } } return bContinueEnumeration; }