/*++ © 1998 Seagate Software, Inc. All rights reserved. Module Name: fsascan.cpp Abstract: This class represents a scanning process that is being carried out upon one FsaResource. Author: Chuck Bardeen [cbardeen] 16-Feb-1997 Revision History: --*/ #include "stdafx.h" #include "wsb.h" #include "fsa.h" #include "job.h" #include "hsmscan.h" #define WSB_TRACE_IS WSB_TRACE_BIT_JOB DWORD HsmStartScanner( void* pVoid ) /*++ --*/ { return(((CHsmScanner*) pVoid)->StartScan()); } HRESULT CHsmScanner::Cancel( HSM_JOB_EVENT event ) /*++ Implements: IHsmScanner::Cancel(). --*/ { HRESULT hr = S_OK; try { // If we have started, but haven't finished, then change the state of the job. The thread // will exit on it's own. if ((HSM_JOB_STATE_IDLE != m_state) && (HSM_JOB_STATE_DONE != m_state) && (HSM_JOB_STATE_FAILED != m_state) && (HSM_JOB_STATE_CANCELLED != m_state)) { if (HSM_JOB_EVENT_CANCEL == event) { WsbAffirmHr(SetState(HSM_JOB_STATE_CANCELLED)); } else if (HSM_JOB_EVENT_SUSPEND == event) { WsbAffirmHr(SetState(HSM_JOB_STATE_SUSPENDED)); } else if (HSM_JOB_EVENT_FAIL == event) { WsbAffirmHr(SetState(HSM_JOB_STATE_FAILED)); } else { WsbAssert(FALSE, E_UNEXPECTED); } } } WsbCatch(hr); return(hr); } HRESULT CHsmScanner::DoIfMatches( IN IFsaScanItem* pScanItem ) /*++ Implements: IHsmScanner::DoIfMatches(). --*/ { HRESULT hr = S_OK; HRESULT hrDo = S_OK; HRESULT hrShould = S_OK; BOOL notMatched = TRUE; BOOL shouldDo = FALSE; CComPtr pRuleStack; WsbTraceIn(OLESTR("CFsaScanner::DoIfMatches"), OLESTR("")); try { // Each policy has it's own rule stack, check each one of until a match is found (if // one exists). WsbAffirmHr(m_pEnumStacks->First(IID_IHsmRuleStack, (void**) &pRuleStack)); while (notMatched) { hr = pRuleStack->DoesMatch(pScanItem, &shouldDo); if (S_OK == hr) { notMatched = FALSE; if (!shouldDo) { hrShould = JOB_E_FILEEXCLUDED; } } else if (S_FALSE == hr) { pRuleStack = 0; WsbAffirmHr(m_pEnumStacks->Next(IID_IHsmRuleStack, (void**) &pRuleStack)); } else { // Something totally unexpected happened so we'd better quit WsbThrow(hr); } } } WsbCatchAndDo(hr, if (WSB_E_NOTFOUND == hr) { hrShould = JOB_E_DOESNTMATCH; hr = S_OK; } else { hrShould = hr; } ); // Just Do It!! if (SUCCEEDED(hr) && shouldDo) { hrDo = pRuleStack->Do(pScanItem); // Tell the session if we ended up skipping the file or not. m_pSession->ProcessItem(HSM_JOB_PHASE_SCAN, HSM_JOB_ACTION_SCAN, pScanItem, hrDo); } else { // Tell the session if we decided to skip the file. m_pSession->ProcessItem(HSM_JOB_PHASE_SCAN, HSM_JOB_ACTION_SCAN, pScanItem, hrShould); } WsbTraceOut(OLESTR("CFsaScanner::DoIfMatches"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return(hr); } #pragma optimize("g", off) HRESULT CHsmScanner::FinalConstruct( void ) /*++ Implements: CComObjectRoot::FinalConstruct(). --*/ { HRESULT hr = S_OK; try { WsbAffirmHr(CComObjectRoot::FinalConstruct()); m_state = HSM_JOB_STATE_IDLE; m_priority = HSM_JOB_PRIORITY_NORMAL; m_threadHandle = 0; m_threadId = 0; m_threadHr = S_OK; m_eventCookie = 0; m_skipHiddenItems = TRUE; m_skipSystemItems = TRUE; m_useRPIndex = FALSE; m_useDbIndex = FALSE; m_event = 0; // Create a collection for the rule stacks, and store an enumerator to it. WsbAffirmHr(CoCreateInstance(CLSID_CWsbOrderedCollection, NULL, CLSCTX_ALL, IID_IWsbCollection, (void**) &m_pRuleStacks)); WsbAffirmHr(m_pRuleStacks->Enum(&m_pEnumStacks)); } WsbCatch(hr); return(hr); } #pragma optimize("", on) void CHsmScanner::FinalRelease( void ) /*++ Implements: CComObjectRoot::FinalRelease(). --*/ { HRESULT hr = S_OK; // Cleanup the thread we were using. if (m_threadHandle != 0) { m_state = HSM_JOB_STATE_DONE; if (0 != m_event) { SetEvent(m_event); } // Should we wait for the thread to end? CloseHandle(m_threadHandle); m_threadHandle = 0; } if (m_event) { CloseHandle(m_event); m_event = 0; } CComObjectRoot::FinalRelease(); } HRESULT CHsmScanner::LowerPriority( void ) /*++ --*/ { HRESULT hr = S_OK; try { WsbAssert(0 != m_threadHandle, E_UNEXPECTED); WsbAssert(m_pSession != 0, E_UNEXPECTED); switch(m_priority) { case HSM_JOB_PRIORITY_IDLE: WsbAffirm(FALSE, E_UNEXPECTED); break; case HSM_JOB_PRIORITY_LOWEST: WsbAffirmStatus(SetThreadPriority(m_threadHandle, THREAD_PRIORITY_IDLE)); m_priority = HSM_JOB_PRIORITY_IDLE; break; case HSM_JOB_PRIORITY_LOW: WsbAffirmStatus(SetThreadPriority(m_threadHandle, THREAD_PRIORITY_LOWEST)); m_priority = HSM_JOB_PRIORITY_LOWEST; break; case HSM_JOB_PRIORITY_NORMAL: WsbAffirmStatus(SetThreadPriority(m_threadHandle, THREAD_PRIORITY_BELOW_NORMAL)); m_priority = HSM_JOB_PRIORITY_LOW; break; case HSM_JOB_PRIORITY_HIGH: WsbAffirmStatus(SetThreadPriority(m_threadHandle, THREAD_PRIORITY_NORMAL)); m_priority = HSM_JOB_PRIORITY_NORMAL; break; case HSM_JOB_PRIORITY_HIGHEST: WsbAffirmStatus(SetThreadPriority(m_threadHandle, THREAD_PRIORITY_ABOVE_NORMAL)); m_priority = HSM_JOB_PRIORITY_HIGH; break; default: case HSM_JOB_PRIORITY_CRITICAL: WsbAffirmStatus(SetThreadPriority(m_threadHandle, THREAD_PRIORITY_HIGHEST)); m_priority = HSM_JOB_PRIORITY_HIGHEST; break; } WsbAffirmHr(m_pSession->ProcessPriority(HSM_JOB_PHASE_SCAN, m_priority)); } WsbCatch(hr); return(hr); } HRESULT CHsmScanner::Pause( void ) /*++ Implements: IHsmScanner::Pause(). --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CFsaScanner::Pause"), OLESTR("")); // Lock(); try { // If we are running, then suspend the thread. WsbAssert((HSM_JOB_STATE_STARTING == m_state) || (HSM_JOB_STATE_ACTIVE == m_state) || (HSM_JOB_STATE_RESUMING == m_state), E_UNEXPECTED); // Set state to pausing -- the thread will pause itself when it // sees the state WsbAffirmHr(SetState(HSM_JOB_STATE_PAUSING)); } WsbCatch(hr); // Unlock(); WsbTraceOut(OLESTR("CFsaScanner::Pause"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CHsmScanner::PopRules( IN OLECHAR* path ) /*++ --*/ { HRESULT hr = S_OK; CComPtr pRuleStack; try { // Each policy has it's own rule stack, and each of them will need to have rules removed // from it for this directory (if any rules were added). for (hr = m_pEnumStacks->First(IID_IHsmRuleStack, (void**) &pRuleStack); SUCCEEDED(hr); hr = m_pEnumStacks->Next(IID_IHsmRuleStack, (void**) &pRuleStack)) { WsbAffirmHr(pRuleStack->Pop(path)); pRuleStack = 0; } if (WSB_E_NOTFOUND == hr) { hr = S_OK; } } WsbCatch(hr); return(hr); } HRESULT CHsmScanner::ProcessSessionEvent( IN IHsmSession* pSession, IN HSM_JOB_PHASE phase, IN HSM_JOB_EVENT event ) /*++ --*/ { HRESULT hr = S_OK; try { WsbAssert(0 != pSession, E_POINTER); // If the phase applies to use (SCAN or ALL), then do any work required by the // event. if ((HSM_JOB_PHASE_ALL == phase) || (HSM_JOB_PHASE_SCAN == phase)) { switch(event) { case HSM_JOB_EVENT_SUSPEND: case HSM_JOB_EVENT_CANCEL: case HSM_JOB_EVENT_FAIL: WsbAffirmHr(Cancel(event)); break; case HSM_JOB_EVENT_PAUSE: WsbAffirmHr(Pause()); break; case HSM_JOB_EVENT_RESUME: WsbAffirmHr(Resume()); break; case HSM_JOB_EVENT_RAISE_PRIORITY: WsbAffirmHr(RaisePriority()); break; case HSM_JOB_EVENT_LOWER_PRIORITY: WsbAffirmHr(LowerPriority()); break; default: case HSM_JOB_EVENT_START: WsbAssert(FALSE, E_UNEXPECTED); break; } } } WsbCatch(hr); return(S_OK); } HRESULT CHsmScanner::PushRules( IN OLECHAR* path ) /*++ --*/ { HRESULT hr = S_OK; CComPtr pRuleStack; try { // Save an indicator to where we are in the scan, so we can use it if we are interrupted // or need to give an indication to the session. m_currentPath = path; // Each policy has it's own rule stack, and each of them will need to have rules added // for this directory (if any rules exist). for (hr = m_pEnumStacks->First(IID_IHsmRuleStack, (void**) &pRuleStack); SUCCEEDED(hr); hr = m_pEnumStacks->Next(IID_IHsmRuleStack, (void**) &pRuleStack)) { WsbAffirmHr(pRuleStack->Push(path)); pRuleStack = 0; } if (WSB_E_NOTFOUND == hr) { hr = S_OK; } } WsbCatch(hr); return(hr); } HRESULT CHsmScanner::RaisePriority( void ) /*++ --*/ { HRESULT hr = S_OK; try { WsbAssert(0 != m_threadHandle, E_UNEXPECTED); WsbAssert(m_pSession != 0, E_UNEXPECTED); switch(m_priority) { case HSM_JOB_PRIORITY_IDLE: WsbAffirmStatus(SetThreadPriority(m_threadHandle, THREAD_PRIORITY_LOWEST)); m_priority = HSM_JOB_PRIORITY_LOWEST; break; case HSM_JOB_PRIORITY_LOWEST: WsbAffirmStatus(SetThreadPriority(m_threadHandle, THREAD_PRIORITY_BELOW_NORMAL)); m_priority = HSM_JOB_PRIORITY_LOW; break; case HSM_JOB_PRIORITY_LOW: WsbAffirmStatus(SetThreadPriority(m_threadHandle, THREAD_PRIORITY_NORMAL)); m_priority = HSM_JOB_PRIORITY_NORMAL; break; case HSM_JOB_PRIORITY_NORMAL: WsbAffirmStatus(SetThreadPriority(m_threadHandle, THREAD_PRIORITY_ABOVE_NORMAL)); m_priority = HSM_JOB_PRIORITY_HIGH; break; case HSM_JOB_PRIORITY_HIGH: WsbAffirmStatus(SetThreadPriority(m_threadHandle, THREAD_PRIORITY_HIGHEST)); m_priority = HSM_JOB_PRIORITY_HIGHEST; break; case HSM_JOB_PRIORITY_HIGHEST: WsbAffirmStatus(SetThreadPriority(m_threadHandle, THREAD_PRIORITY_TIME_CRITICAL)); m_priority = HSM_JOB_PRIORITY_CRITICAL; break; default: case HSM_JOB_PRIORITY_CRITICAL: WsbAffirm(FALSE, E_UNEXPECTED); break; } WsbAffirmHr(m_pSession->ProcessPriority(HSM_JOB_PHASE_SCAN, m_priority)); } WsbCatch(hr); return(hr); } HRESULT CHsmScanner::Resume( void ) /*++ Implements: IHsmScanner::Resume(). --*/ { HRESULT hr = S_OK; HSM_JOB_STATE oldState; WsbTraceIn(OLESTR("CFsaScanner::Resume"), OLESTR("")); // Lock(); try { // If we are paused, then suspend the thread. WsbAffirm((HSM_JOB_STATE_PAUSING == m_state) || (HSM_JOB_STATE_PAUSED == m_state), E_UNEXPECTED); oldState = m_state; WsbAffirmHr(SetState(HSM_JOB_STATE_RESUMING)); // If we are unable to resume, then return to the former state. try { WsbAffirm(SetEvent(m_event), HRESULT_FROM_WIN32(GetLastError())); } WsbCatchAndDo(hr, SetState(oldState);); } WsbCatch(hr); // Unlock(); WsbTraceOut(OLESTR("CFsaScanner::Resume"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CHsmScanner::ScanPath( IN OLECHAR* dirPath ) /*++ --*/ { HRESULT hr = S_OK; CComPtr pScanItem; CWsbStringPtr searchPath; WsbTraceIn(OLESTR("CFsaScanner::ScanPath"), OLESTR("%ls"), WsbAbbreviatePath(dirPath, WSB_TRACE_BUFF_SIZE)); try { WsbAssert(0 != dirPath, E_POINTER); WsbAssert(0 != dirPath[0], E_INVALIDARG); // Pop the rules for this files. This sets the context for the scan to follow. WsbAffirmHr(PushRules(dirPath)); try { // Iterate over all the files and directories in the specified path. searchPath = dirPath; if (searchPath[(int) (wcslen(searchPath) - 1)] == L'\\') { WsbAffirmHr(searchPath.Append("*")); } else { WsbAffirmHr(searchPath.Append("\\*")); } if (m_useDbIndex) { hr = m_pResource->FindFirstInDbIndex(m_pSession, &pScanItem); } else if (m_useRPIndex) { hr = m_pResource->FindFirstInRPIndex(m_pSession, &pScanItem); } else { hr = m_pResource->FindFirst(searchPath, m_pSession, &pScanItem); } while (SUCCEEDED(hr) && ((HSM_JOB_STATE_ACTIVE == m_state) || (HSM_JOB_STATE_RESUMING == m_state) || (HSM_JOB_STATE_PAUSING == m_state))) { // Check for a pause request // Lock(); if (HSM_JOB_STATE_PAUSING == m_state) { hr = SetState(HSM_JOB_STATE_PAUSED); // Unlock(); WsbAffirmHr(hr); // Suspend the thread here & wait for resume signal WsbTrace(OLESTR("CHsmScanner::ScanPath: pausing\n")); WaitForSingleObject(m_event, 0xffffffff); WsbTrace(OLESTR("CHsmScanner::ScanPath: woke up, state = %d\n"), (int)m_state); // Lock(); if (HSM_JOB_STATE_RESUMING != m_state) { // Unlock(); break; } hr = SetState(HSM_JOB_STATE_ACTIVE); if (S_OK != hr) { // Unlock(); WsbThrow(hr); } } // Unlock(); // Skip hidden and/or system items if so configured. if (!((m_skipHiddenItems && (pScanItem->IsHidden() == S_OK)) || (m_skipSystemItems && (pScanItem->IsSystem() == S_OK)))) { // Ignore ".", "..", symbolic links and mount points. if ((pScanItem->IsARelativeParent() == S_FALSE) && (pScanItem->IsALink() == S_FALSE)) { // Recursively scan subdirectories. if (pScanItem->IsAParent() == S_OK) { WsbAffirmHr(pScanItem->GetPathAndName(OLESTR(""), &searchPath, 0)); WsbAffirmHr(ScanPath(searchPath)); } // If this file matches a policy then perform the action. else { WsbAffirmHr(DoIfMatches(pScanItem)); } } else { WsbTrace(OLESTR("CHsmScanner::ScanPath skipping - symbolic link, '.', or '..'\n")); } } else { WsbTrace(OLESTR("CHsmScanner::ScanPath skipping - hidden/system\n")); } if (m_useDbIndex) { hr = m_pResource->FindNextInDbIndex(pScanItem); } else if (m_useRPIndex) { hr = m_pResource->FindNextInRPIndex(pScanItem); } else { hr = m_pResource->FindNext(pScanItem); } } // If we broke out as a result of end of scan or some other error ... if (hr != S_OK) { WsbAssert(hr == WSB_E_NOTFOUND, hr); hr = S_OK; } } WsbCatch(hr); // Pop the rules for this directory. This restores the context as we pop back up the directory // structure. WsbAffirmHr(PopRules(dirPath)); } WsbCatchAndDo(hr, if (JOB_E_DIREXCLUDED == hr) {hr = S_OK;}); WsbTraceOut(OLESTR("CFsaScanner::ScanPath"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CHsmScanner::SetState( IN HSM_JOB_STATE state ) /*++ --*/ { HRESULT hr = S_OK; BOOL bLog = TRUE; WsbTraceIn(OLESTR("CFsaScanner::SetState"), OLESTR("old state = %d, new state = %d"), (int)m_state, (int)state); // Lock(); try { // Change the state and report the change to the session. m_state = state; WsbAffirmHr(m_pSession->ProcessState(HSM_JOB_PHASE_SCAN, m_state, m_currentPath, bLog)); } WsbCatch(hr); // Unlock(); WsbTraceOut(OLESTR("CFsaScanner::SetState"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CHsmScanner::Start( IN IHsmSession* pSession, IN OLECHAR* path ) /*++ Implements: IHsmScanner::Start(). --*/ { HRESULT hr = S_OK; CComPtr pDef; CComPtr pPolicy; CComPtr pRuleStack; CComPtr pEnumPolicies; CComPtr pCPC; CComPtr pCP; CComPtr pSink; DWORD cookie; try { // Make sure that we were given a session, and that we haven't started already. WsbAssert(0 != pSession, E_POINTER); WsbAssert(HSM_JOB_STATE_IDLE == m_state, E_UNEXPECTED); // Store off the session. m_pSession = pSession; // If no directory was specified, then start in the root of the resource. if ((0 != path) && (0 != *path)) { m_startingPath = path; } else { m_startingPath = OLESTR("\\"); } m_currentPath = m_startingPath; // Tell them we are starting. WsbAffirmHr(SetState(HSM_JOB_STATE_STARTING)); // Create an event to control pause/resume for the scan. if (0 == m_event) { CWsbStringPtr nameString; GUID id; WsbAffirmHr(m_pSession->GetIdentifier(&id)); nameString = id; nameString.Prepend(OLESTR("Scanner Pause and Resume Event for session ")); m_event = CreateEvent(NULL, FALSE, FALSE, nameString); } // Ask the session to advise of every event. WsbAffirmHr(pSession->QueryInterface(IID_IConnectionPointContainer, (void**) &pCPC)); WsbAffirmHr(pCPC->FindConnectionPoint(IID_IHsmSessionSinkEveryEvent, &pCP)); WsbAffirmHr(((IUnknown*) (IHsmScanner*) this)->QueryInterface(IID_IHsmSessionSinkEveryEvent, (void**) &pSink)); WsbAffirmHr(pCP->Advise(pSink, &cookie)); // Store off the information needed to latter unadvise. m_eventCookie = cookie; try { // Locate the resource that is being scanned. WsbAffirmHr(m_pSession->GetResource(&m_pResource)); // Create and initialize a rule stack for each policy. WsbAffirmHr(pSession->GetJob(&m_pJob)); WsbAffirmHr(m_pJob->GetDef(&pDef)); WsbAffirmHr(pDef->EnumPolicies(&pEnumPolicies)); for (hr = pEnumPolicies->First(IID_IHsmPolicy, (void**) &pPolicy); SUCCEEDED(hr); hr = pEnumPolicies->Next(IID_IHsmPolicy, (void**) &pPolicy)) { WsbAffirmHr(CoCreateInstance(CLSID_CHsmRuleStack, NULL, CLSCTX_ALL, IID_IHsmRuleStack, (void**) &pRuleStack)); WsbAffirmHr(pRuleStack->Init(pPolicy, m_pResource)); WsbAffirmHr(m_pRuleStacks->Add(pRuleStack)); pRuleStack = 0; pPolicy = 0; } if (WSB_E_NOTFOUND == hr) { hr = S_OK; } // Determine whether hidden and system items should be skipped? if (pDef->SkipHiddenItems() == S_FALSE) { m_skipHiddenItems = FALSE; } if (pDef->SkipSystemItems() == S_FALSE) { m_skipSystemItems = FALSE; } // Determine whether to use the Reparse Point Index for the scan? if (pDef->UseRPIndex() == S_OK) { m_useRPIndex = TRUE; } // Determine whether to use the Database Index for the scan? if (pDef->UseDbIndex() == S_OK) { m_useDbIndex = TRUE; } try { // Now that we have prepared, create the thread that will do the scanning! WsbAffirm((m_threadHandle = CreateThread(0, 0, HsmStartScanner, (void*) this, 0, &m_threadId)) != 0, HRESULT_FROM_WIN32(GetLastError())); } WsbCatchAndDo(hr, SetState(HSM_JOB_STATE_FAILED);); if (FAILED(hr)) { WsbThrow(hr); } } WsbCatchAndDo(hr, pCP->Unadvise(m_eventCookie); m_eventCookie = 0; ); } WsbCatch(hr); return(hr); } HRESULT CHsmScanner::StartScan( void ) /*++ --*/ { HRESULT hr = S_OK; HRESULT hr2 = S_OK; CComPtr pCPC; CComPtr pCP; WsbTraceIn(OLESTR("CFsaScanner::StartScan"), OLESTR("")); try { CComPtr pTruncator; CComPtr pTruncatorSession; CComPtr pDef; CComPtr pActionPreScan; // The thread is running. WsbAffirmHr(SetState(HSM_JOB_STATE_ACTIVE)); // To avoid having the RP Index order changed by the truncator, // we pause the truncator if (m_useRPIndex) { WsbAffirmHr(m_pResource->GetTruncator(&pTruncator)); if (pTruncator) { WsbAffirmHr(pTruncator->GetSession(&pTruncatorSession)); if (pTruncatorSession) { WsbAffirmHr(pTruncatorSession->ProcessEvent(HSM_JOB_PHASE_ALL, HSM_JOB_EVENT_PAUSE)); } } } // Get the pre-scan action and do it (if exists) WsbAffirmHr(m_pJob->GetDef(&pDef)); WsbAffirmHr(pDef->GetPreScanActionOnResource(&pActionPreScan)); if (pActionPreScan) { WsbTrace(OLESTR("CHsmScanner::StartScan: doing pre-scan action\n")); //Don't throw hr - we need the cleanup code that is done after the scanning hr = pActionPreScan->Do(m_pResource, m_pSession); } // Start with the first path and scan the resource (only if pre-scan succeeded) if (SUCCEEDED(hr)) { m_threadHr = ScanPath(m_startingPath); } // Resume the truncator if we paused it if (pTruncatorSession) { pTruncatorSession->ProcessEvent(HSM_JOB_PHASE_ALL, HSM_JOB_EVENT_RESUME); } // Clear out the information about the thread; WsbAffirmStatus(CloseHandle(m_threadHandle)); m_threadId = 0; m_threadHandle = 0; } WsbCatch(hr); // The thread is exiting, so record if (FAILED(hr) || FAILED(m_threadHr)) { hr2 = SetState(HSM_JOB_STATE_FAILED); if (FAILED(hr2)) { m_pSession->ProcessHr(HSM_JOB_PHASE_ALL, __FILE__, __LINE__, hr2); } } else { hr2 = SetState(HSM_JOB_STATE_DONE); if (FAILED(hr2)) { m_pSession->ProcessHr(HSM_JOB_PHASE_ALL, __FILE__, __LINE__, hr2); } } // Regardless of how this thread is exiting, we need to unadvise from the session. // Indicate that we no longer want to be advised of events. if ((m_pSession != 0) && (m_eventCookie != 0)) { try { WsbAffirmHr(m_pSession->QueryInterface(IID_IConnectionPointContainer, (void**) &pCPC)); WsbAffirmHr(pCPC->FindConnectionPoint(IID_IHsmSessionSinkEveryEvent, &pCP)); pCP->Unadvise(m_eventCookie); } WsbCatch(hr); } WsbTraceOut(OLESTR("CFsaScanner::StartScan"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return(hr); }