// ************************************************************************** // Copyright (c) 1997-2001 Microsoft Corporation, All Rights Reserved // // File: OnAsync.cpp // // Description: // This file implements the ExecQueryAsync() routine and the // CAsyncQuerySink class. // // History: // // ************************************************************************** #include "stdafx.h" #include "AdvClientDlg.h" #include "OnAsync.h" // ************************************************************************** // // CAdvClientDlg::OnEnumservicesasync() // // Description: // Enumerate the services. Demonstrates ExecQueryAsync() using SQL1 and // begin/end enumeration through properties. The setup portion is the // same as OnEnumServices() but the 'enumerating' part is in the Object // Sink. // // Parameters: // None. // // Returns: // nothing. // // Globals accessed: // None. // // Globals modified: // None. // //=========================================================================== void CAdvClientDlg::OnEnumservicesasync() { HRESULT hRes; //--------------------------- // allocate the sink if its not already allocated. if(m_pQueryCallback == NULL) { m_pQueryCallback = new CAsyncQuerySink(&m_outputList); m_pQueryCallback->AddRef(); } BSTR qLang = SysAllocString(L"WQL"); BSTR query = SysAllocString(L"select * from Win32_Service"); m_outputList.ResetContent(); m_outputList.AddString(_T("working...")); //--------------------------- // execute the query. For *Async, the last parm is a sink object // that will be sent the resultset instead of returning the normal // enumerator object. if((hRes = m_pIWbemServices->ExecQueryAsync(qLang, query, 0L, NULL, m_pQueryCallback)) == S_OK) { TRACE(_T("Executed query\n")); m_outputList.ResetContent(); } else { TRACE(_T("ExecQuery() failed %s\n"), ErrorString(hRes)); } //endif ExecQuery() SysFreeString(qLang); SysFreeString(query); } // ************************************************************************** // // CAsyncQuerySink::CAsyncQuerySink() // // Description: // This is the sink that gets called as a result of ExecQueryAsync(). // It has the obligatory COM functions plus Indicate() and SetStatus() // which are documented in more detail below. //=========================================================================== CAsyncQuerySink::CAsyncQuerySink(CListBox *output) { m_pOutputList = output; m_SetStatusCalled = FALSE; } // ======================================================== CAsyncQuerySink::~CAsyncQuerySink() { if(!m_SetStatusCalled) { // NOTE: This happening is indicative of a comm error // between the server and this client such as a security // violation. CoInitializeSecurity() needs to be called to // avoid the security problem. TRACE(_T("released before SetStatus() was called\n")); } } // ======================================================== STDMETHODIMP CAsyncQuerySink::QueryInterface(REFIID riid, LPVOID* ppv) { // we're implementing the IID_IWbemObjectSink interface. if(riid == IID_IUnknown || riid == IID_IWbemObjectSink) { *ppv = this; // you're handing out a copy of yourself so account for it. AddRef(); return S_OK; } else { return E_NOINTERFACE; } } // ======================================================== ULONG CAsyncQuerySink::AddRef() { // InterlockedIncrement() helps with thread safety. return InterlockedIncrement(&m_lRef); } // ======================================================== ULONG CAsyncQuerySink::Release() { // InterlockedDecrement() helps with thread safety. int lNewRef = InterlockedDecrement(&m_lRef); // when all the copies are released... if(lNewRef == 0) { // kill thyself. delete this; } return lNewRef; } // ************************************************************************** // // CAsyncQuerySink::Indicate() // // Description: // This method is called to handle the result of the ExecQueryAsync(). // There are no assumtions about how many objects are passed on each // call or how many calls will be made. // Parameters: // lObjectCount (in) - how many objects are being passed. // ppObjArray (in) - array of objects from the query. // // Returns: // S_OK if successful, otherwise the HRESULT of the failed called. // // Globals accessed: // None. // // Globals modified: // None. // //=========================================================================== STDMETHODIMP CAsyncQuerySink::Indicate(LONG lObjectCount, IWbemClassObject **ppObjArray) { HRESULT hRes; WCHAR *pBuf; CString clMyBuff; BSTR propName = NULL, val = NULL; VARIANT varString, pVal; VariantInit(&varString); VariantInit(&pVal); TRACE(_T("Indicate() called\n")); //------------------------------ // walk though the classObjects... for (int i = 0; i < lObjectCount; i++) { // clear my output buffer. clMyBuff.Empty(); //------------------------------ // enumerate properties. if((hRes = ppObjArray[i]->BeginEnumeration(WBEM_FLAG_NONSYSTEM_ONLY)) == S_OK) { //------------------------------ // try to get the next property. while(ppObjArray[i]->Next(0, &propName, &pVal, NULL, NULL) == S_OK) { // is it one of the 'names' we want? if((wcsncmp(propName, L"Name", 4) == 0) || (wcsncmp(propName, L"DisplayName", 11) == 0) || (wcsncmp(propName, L"PathName", 8) == 0)) { // format the property=value/ clMyBuff += propName; clMyBuff += _T("="); clMyBuff += ValueToString(&pVal, &pBuf); clMyBuff += _T("/"); free(pBuf); // allocated by ValueToString() } //endif wcsncmp()... // cleanup stuff used in the Next() loop. SysFreeString(propName); VariantClear(&pVal); } //endwhile // did the while loop exit due to an error? if(hRes != S_OK) { TRACE(_T("ppObjArray[i]->Next() failed %s\n"), ErrorString(hRes)); } } else { TRACE(_T("BeginEnumeration() failed %s\n"), ErrorString(hRes)); } //endif BeginEnumeration() // output the buffer. m_pOutputList->AddString(clMyBuff); //------------------------------ // free the property iterator workspace. ppObjArray[i]->EndEnumeration(); // no need to release because the caller does the // AddRef()/Release() } // endfor TRACE(_T("walked indication list\n")); return S_OK; } // ************************************************************************** // // CAsyncQuerySink::SetStatus() // // Description: // Called after all Indication()s have been called. This signals the // completion of the query. // // Parameters: // per WMI requirements. // // Returns: // S_OK if successful, otherwise the HRESULT of the failed called. // // Globals accessed: // None. // // Globals modified: // None. // //=========================================================================== STDMETHODIMP CAsyncQuerySink::SetStatus(long lFlags, HRESULT hResult, BSTR strParam, IWbemClassObject *pObjParam) { TRACE(_T("SetStatus() called %s\n"), ErrorString(hResult)); m_SetStatusCalled = TRUE; // all the Indication()s worked fine. if(hResult == WBEM_NO_ERROR) { m_pOutputList->AddString(_T("Done Enumerating")); } else // or not. { m_pOutputList->AddString(_T("Enumeration Error!!")); } return S_OK; }