566 lines
14 KiB
C++
566 lines
14 KiB
C++
//***************************************************************************
|
|
//
|
|
// Copyright (c) 2000-2001 Microsoft Corporation
|
|
//
|
|
// WMIOPN.CPP
|
|
//
|
|
// alanbos 02-Nov-00 Created.
|
|
//
|
|
// WMI operation implementation.
|
|
//
|
|
//***************************************************************************
|
|
|
|
#include "precomp.h"
|
|
|
|
static char *pStrSOAPPreamble =
|
|
"<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">"
|
|
"<SOAP-ENV:Body>";
|
|
|
|
static char *pStrSOAPPostamble =
|
|
"</SOAP-ENV:Body>"
|
|
"</SOAP-ENV:Envelope>";
|
|
|
|
static char *pStrClassStart = "<Class>";
|
|
static char *pStrClassEnd = "</Class>";
|
|
|
|
static char *pStrInstanceStart = "<Instance>";
|
|
static char *pStrInstanceEnd = "</Instance>";
|
|
|
|
static char *pStrObjectStart = "<Object>";
|
|
static char *pStrObjectEnd = "</Object>";
|
|
|
|
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<IUnknown*>(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<IWbemServices> 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 =
|
|
"<Envelope xmlns=\"http://schemas.xmlsoap.org/soap/envelope/\">"
|
|
"<Body>"
|
|
"<Fault>"
|
|
"<faultcode>Client</faultcode>"
|
|
"<faultstring>";
|
|
|
|
char faultMsg2 [10];
|
|
sprintf (faultMsg2, "%x", hr);
|
|
|
|
char *pFaultMsg3 =
|
|
"</faultstring>"
|
|
"</Fault>"
|
|
"</Body>"
|
|
"</Envelope>";
|
|
|
|
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<IWbemClassObject> & 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<IWbemClassObject> & 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;
|
|
}
|
|
|