2025-04-27 07:49:33 -04:00

289 lines
7.5 KiB
C++

// **************************************************************************
// 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;
}