//***************************************************************************
//
// Copyright (c) 2000-2001 Microsoft Corporation
//
// WMIOPN.CPP
//
// alanbos 02-Nov-00 Created.
//
// WMI operation implementation.
//
//***************************************************************************
#include "precomp.h"
static char *pStrSOAPPreamble =
""
"";
static char *pStrSOAPPostamble =
""
"";
static char *pStrClassStart = "";
static char *pStrClassEnd = "";
static char *pStrInstanceStart = "";
static char *pStrInstanceEnd = "";
static char *pStrObjectStart = "";
static char *pStrStartOpenTag = "<";
static char *pStrStartCloseTag = " xmlns=\""
WMI_SOAP_NS
"\">";
static char *pStartEmptyCloseTag = " xmlns=\""
WMI_SOAP_NS
"\"/>";
static char *pStrEndOpenTag = "";
static char *pStrEndCloseTag = ">";
WMIOperation::WMIOperation (SOAPActor *pActor) :
m_pWMIConnection (NULL),
m_elementNest (0),
m_parseState (Other),
m_pActor (pActor),
m_cRef (0)
{
if (m_pActor)
m_pActor->GetResponseStream (m_pIResponseStream);
}
STDMETHODIMP WMIOperation::QueryInterface (
IN REFIID riid,
OUT LPVOID *ppv
)
{
*ppv=NULL;
if (IID_IUnknown==riid)
*ppv = reinterpret_cast(this);
if (NULL!=*ppv)
{
((LPUNKNOWN)*ppv)->AddRef();
return NOERROR;
}
return ResultFromScode(E_NOINTERFACE);
}
STDMETHODIMP_(ULONG) WMIOperation::AddRef(void)
{
InterlockedIncrement(&m_cRef);
return m_cRef;
}
STDMETHODIMP_(ULONG) WMIOperation::Release(void)
{
LONG cRef = InterlockedDecrement(&m_cRef);
if (0L!=cRef)
return cRef;
delete this;
return 0;
}
WMIOperation *WMIOperation::GetOperationHandler (
SOAPActor *pActor,
const wchar_t *pwchOperationName,
bool & bIsSupported
)
{
bIsSupported = false;
WMIOperation *pWmiOperation = NULL;
if (pwchOperationName)
{
if (0 == wcscmp (WMI_OPERATION_GET_OBJECT, pwchOperationName))
{
bIsSupported = true;
pWmiOperation = new WMIGetObjectOperation (pActor);
}
else if (0 == wcscmp (WMI_OPERATION_EXEC_QUERY, pwchOperationName))
{
bIsSupported = true;
pWmiOperation = new WMIExecQueryOperation (pActor);
}
else if (0 == wcscmp (WMI_OPERATION_GET_CLASSES, pwchOperationName))
{
bIsSupported = true;
pWmiOperation = new WMIGetClassesOperation (pActor);
}
else if (0 == wcscmp (WMI_OPERATION_GET_INSTANCES, pwchOperationName))
{
bIsSupported = true;
pWmiOperation = new WMIGetInstancesOperation (pActor);
}
else if (0 == wcscmp (WMI_OPERATION_DELETE_CLASS, pwchOperationName))
{
bIsSupported = true;
pWmiOperation = new WMIDeleteClassOperation (pActor);
}
else if (0 == wcscmp (WMI_OPERATION_DELETE_INSTANCE, pwchOperationName))
{
bIsSupported = true;
pWmiOperation = new WMIDeleteInstanceOperation (pActor);
}
}
if (pWmiOperation)
pWmiOperation->AddRef ();
return pWmiOperation;
}
void WMIOperation::Execute ()
{
if (m_pIResponseStream)
{
CComPtr pIWbemServices;
GetIWbemServices(pIWbemServices);
// This is set if we hit an error in mid-response
bool bOperationErrorInProgress = false;
if (pIWbemServices)
{
HRESULT hr = PrepareRequest ();
if (SUCCEEDED(hr))
{
HRESULT hr = BeginRequest (pIWbemServices);
/*
* At this point we have not yet sent anything
* back to the client. The next call will
* be the first to stream information back to the client.
*/
if (PrepareResponse (hr))
{
if (SUCCEEDED (hr))
{
if (ResponseHasContent ())
{
if (SendOperationStartTag ())
{
if (SUCCEEDED(ProcessRequest ()))
{
if (!SendOperationEndTag ())
{
// Failure mid-response
bOperationErrorInProgress = true;
}
}
else
{
// Failure mid-response
bOperationErrorInProgress = true;
}
}
else
{
// Failure mid-response
bOperationErrorInProgress = true;
}
}
else
{
if (!SendOperationEmptyTag ())
{
// Failure mid-response
bOperationErrorInProgress = true;
}
}
}
else
{
// Nothing else to do except complete the response (below)
}
}
else
{
// Initial PrepareResponse failed
bOperationErrorInProgress = true;
}
}
else
{
// Signal to the client that the operation failed (very early on)
if (!PrepareResponse (hr))
{
// Failure mid-response
bOperationErrorInProgress = true;
}
}
}
else
{
if (!PrepareResponse (GetConnectionStatus()))
{
// Failure mid-response
bOperationErrorInProgress = true;
}
}
// If no hitches thus far, complete the response to the client
if (!bOperationErrorInProgress)
bOperationErrorInProgress = !CompleteResponse ();
if (bOperationErrorInProgress)
{
// Something went awry - log the error and try to signal this to the client
if (m_pActor)
{
// TODO - log the error
if (!m_pActor->AbortResponse ())
{
// Oh lummee we are in deep do-do. Try and log it then
// TODO - log the error
}
}
}
}
else
{
// Can't even write back - nothing to do!
// TODO - log the error
}
}
bool WMIOperation::SendOperationStartTag ()
{
bool result = false;
LPCSTR pStrOperation = GetOperationResponseName ();
if (pStrOperation)
{
if (SUCCEEDED(m_pIResponseStream->Write (pStrStartOpenTag, strlen(pStrStartOpenTag), NULL)) &&
SUCCEEDED(m_pIResponseStream->Write (pStrOperation, strlen(pStrOperation), NULL)) &&
SUCCEEDED(m_pIResponseStream->Write (pStrStartCloseTag, strlen(pStrStartCloseTag), NULL)))
result = true;
}
return result;
}
bool WMIOperation::SendOperationEmptyTag ()
{
bool result = false;
LPCSTR pStrOperation = GetOperationResponseName ();
if (pStrOperation)
{
if (SUCCEEDED(m_pIResponseStream->Write (pStrStartOpenTag, strlen(pStrStartOpenTag), NULL)) &&
SUCCEEDED(m_pIResponseStream->Write (pStrOperation, strlen(pStrOperation), NULL)) &&
SUCCEEDED(m_pIResponseStream->Write (pStartEmptyCloseTag, strlen(pStartEmptyCloseTag), NULL)))
result = true;
}
return result;
}
bool WMIOperation::SendOperationEndTag ()
{
bool result = false;
LPCSTR pStrOperation = GetOperationResponseName ();
if (pStrOperation)
{
if (SUCCEEDED(m_pIResponseStream->Write (pStrEndOpenTag, strlen(pStrEndOpenTag), NULL)) &&
SUCCEEDED(m_pIResponseStream->Write (pStrOperation, strlen(pStrOperation), NULL)) &&
SUCCEEDED(m_pIResponseStream->Write (pStrEndCloseTag, strlen(pStrEndCloseTag), NULL)))
result = true;
}
return result;
}
bool WMIOperation::PrepareResponse (HRESULT hr)
{
bool bSentOK = false;
if (m_pActor)
{
// NB: The assigment is intended here
if (bSentOK = m_pActor->SendServerStatus (SUCCEEDED(hr)))
{
// Send the preamble
if (SUCCEEDED(m_pIResponseStream->Write (pStrSOAPPreamble, strlen (pStrSOAPPreamble), NULL)))
{
if (FAILED(hr))
{
// Send the fault
// TODO - just fake it for now
char *pFaultMsg1 =
""
""
""
"Client"
"";
char faultMsg2 [10];
sprintf (faultMsg2, "%x", hr);
char *pFaultMsg3 =
""
""
""
"";
if (FAILED(m_pIResponseStream->Write (pFaultMsg1, strlen(pFaultMsg1), NULL)) ||
FAILED(m_pIResponseStream->Write (faultMsg2, strlen(faultMsg2), NULL)) ||
FAILED(m_pIResponseStream->Write (pFaultMsg3, strlen(pFaultMsg3), NULL)))
bSentOK = false;
}
}
else
bSentOK = false;
}
}
return bSentOK;
}
bool WMIOperation::CompleteResponse ()
{
// Send the postamble
return (SUCCEEDED(m_pIResponseStream->Write (pStrSOAPPostamble, strlen (pStrSOAPPostamble), NULL)));
}
HRESULT STDMETHODCALLTYPE WMIOperation::startElement(
const wchar_t __RPC_FAR *pwchNamespaceUri,
int cchNamespaceUri,
const wchar_t __RPC_FAR *pwchLocalName,
int cchLocalName,
const wchar_t __RPC_FAR *pwchRawName,
int cchRawName,
ISAXAttributes __RPC_FAR *pAttributes)
{
HRESULT result = E_FAIL;
m_elementNest++;
// We are only interested in second-level elements (i.e. the
// parameter names) where level 1 == operation name header
if (2 == m_elementNest)
{
// Handle the "standard parameters" here
if (0 == wcscmp(WMI_PARAMETER_NAMESPACE, pwchLocalName))
{
// following content will be the value of the namespace
m_parseState = Namespace;
result = S_OK;
}
else if (0 == wcscmp(WMI_PARAMETER_CONTEXT, pwchLocalName))
{
// following content will be the value of the context
m_parseState = Context;
}
else if (0 == wcscmp(WMI_PARAMETER_LOCALE, pwchLocalName))
{
// following content will be the value of the locale
m_parseState = Locale;
}
else if (ProcessElement (pwchNamespaceUri, cchNamespaceUri, pwchLocalName,
cchLocalName, pwchRawName, cchRawName, pAttributes))
{
// Recognized and handled by the operation-specific subclass
result = S_OK;
}
else
{
m_parseState = Other;
// For anything else, all we care about is whether
// the SOAP:mustUnderstand attribute is present or not
if (!SOAPActor::MustUnderstand (pAttributes))
result = S_OK;
}
}
else
{
// Ignore subcontent
result = S_OK;
}
return result;
}
HRESULT STDMETHODCALLTYPE WMIOperation::characters (
const unsigned short * pwchChars,
int cchChars )
{
HRESULT result = S_OK;
// We are only interested in second-level elements (i.e. the
// parameter names) where level 1 == operation name header
if (2 == m_elementNest)
{
if (Namespace == m_parseState)
{
CComBSTR bsNamespace = SysAllocStringLen (pwchChars, cchChars);
if (!m_pWMIConnection)
m_pWMIConnection = new WMIConnection (bsNamespace, NULL);
else
m_pWMIConnection->SetNamespace (bsNamespace);
}
else if (Locale == m_parseState)
{
CComBSTR bsLocale = SysAllocStringLen (pwchChars, cchChars);
if (!m_pWMIConnection)
m_pWMIConnection = new WMIConnection (NULL, bsLocale);
else
m_pWMIConnection->SetLocale (bsLocale);
}
else if (Context == m_parseState)
{
// TODO
}
else
result = (ProcessContent (pwchChars, cchChars)) ? S_OK : E_FAIL;
}
return result;
}
HRESULT STDMETHODCALLTYPE WMIOperation::endElement (
const wchar_t * pwchNamespaceUri,
int cchNamespaceUri,
const wchar_t * pwchLocalName,
int cchLocalName,
const wchar_t * pwchQName,
int cchQName )
{
HRESULT hr = S_OK;
// If we have popped the stack, return control to the parent handler
if (0 == --m_elementNest)
{
if (m_pActor)
hr = m_pActor->RestoreContentHandler ();
else
hr = E_FAIL;
}
return hr;
}
HRESULT WMIEncodingOperation::PrepareRequest (void)
{
HRESULT hr = WBEM_E_FAILED;
CComBSTR bsRootXMLNamespace;
// Build up the root URL for all schema's
if (SUCCEEDED(hr = GetRootXMLNamespace (bsRootXMLNamespace)))
{
CComBSTR bsWmiNamespace;
if (GetWMINamespace (bsWmiNamespace))
{
m_bsRootSchemaURI.Set (bsRootXMLNamespace, bsWmiNamespace);
if (m_bsRootSchemaURI.GetURIForNamespace (m_bsXMLNamespace))
{
// Set the default targetNamespace for every schema we might return
hr = m_pIWMIXMLConverter->SetXMLNamespace (
m_bsXMLNamespace,
NULL);
}
}
}
return hr;
}
HRESULT WMIEncodingOperation::EncodeAndSendClass (
CComPtr & pIWbemClassObject
)
{
HRESULT hr = WBEM_E_FAILED;
if (m_pIResponseStream && m_pIWMIXMLConverter)
{
m_pIResponseStream->Write (pStrClassStart, strlen (pStrClassStart), NULL);
CComVariant varValue;
// NB: We let the WMI standard target namespace default
// Clear any existing schemaLocation
hr = m_pIWMIXMLConverter->SetSchemaLocations (0, NULL);
// Set schemaLocation values for include of SUPERCLASS
if (SUCCEEDED(pIWbemClassObject->Get (L"__SUPERCLASS", 0, &varValue, NULL, NULL)) &&
(VT_BSTR == varValue.vt) && (NULL != varValue.bstrVal))
{
CComBSTR bsXMLNamespace;
BSTR strSchemaLoc[1];
if (m_bsRootSchemaURI.GetURIForClass (varValue.bstrVal, bsXMLNamespace))
{
// Note this string will be freed by the destructor of CComBSTR
strSchemaLoc[0] = bsXMLNamespace.m_str;
if (SUCCEEDED(hr = m_pIWMIXMLConverter->SetSchemaLocations (1, strSchemaLoc)))
hr = m_pIWMIXMLConverter->GetXMLForObject (pIWbemClassObject, 0, m_pIResponseStream);
}
}
m_pIResponseStream->Write (pStrClassEnd, strlen (pStrClassEnd), NULL);
}
return hr;
}
HRESULT WMIEncodingOperation::EncodeAndSendObject (
CComPtr & pIWbemClassObject
)
{
HRESULT hr = WBEM_E_FAILED;
// Is this a class or an instance?
CComVariant varValue;
if (SUCCEEDED(pIWbemClassObject->Get (L"__GENUS", 0, &varValue, NULL, NULL)))
{
if (WBEM_GENUS_CLASS == varValue.lVal)
hr = EncodeAndSendClass (pIWbemClassObject);
else
hr = EncodeAndSendInstance (pIWbemClassObject);
}
else
{
// No idea - take a wild guess!
// TODO
}
return hr;
}