// XMLClientPacket.cpp: implementation of the CXMLClientPacket class. // ////////////////////////////////////////////////////////////////////// #include "XMLTransportClientHelper.h" #include "wmiconv.h" #include "wmi2xml.h" #include "XMLClientPacket.h" #include "XMLClientpacketFactory.h" LPCWSTR CXMLClientPacket::WMI_WHISTLERSTRING = L" WMI=\"WHISTLER\""; LPCWSTR CXMLClientPacket::TRUE_STRING = L"TRUE"; LPCWSTR CXMLClientPacket::FALSE_STRING = L"FALSE"; LPCWSTR CXMLClientPacket::WHISTLER_HTTP_HEADER = L"MicrosoftWMI:Whistler"; ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CXMLClientPacket::CXMLClientPacket(const WCHAR *pObjPath,const WCHAR *pwszNameSpace, const WCHAR *pwszCimOperation): m_bWMI(true), m_pwszNameSpace(NULL), m_pwszObjPath(NULL), m_pwszCimOperation(NULL), m_pwszLocale(NULL), m_dwXMLNamespaceLength(0), m_dwNumberofNamespaceparts(0), m_pwszQueryString(NULL), m_lFlags(0), m_pCtx(NULL), m_pWbemClassObject(NULL), m_ePathstyle(NOVAPATH) { /******************************************************************************** The following functions will set the m_hResult to S_OK or whatever the failure code is.. the XMLClientPacketFactory is the class that is supposed to be creating the XMLClientPacket derived classes. thats the purpose of the packet factory. the factory will create the packe class and then check this member (m_hResult) via the ClassConstructionSucceeded() member function to determine if everything went well during construction. ********************************************************************************/ m_hResult = S_OK; m_pwszQueryLanguage[0] = NULL; m_hResult = AssignString(&m_pwszNameSpace,const_cast(pwszNameSpace)); if(SUCCEEDED(m_hResult)) m_hResult = GetNamespaceLength(&m_dwXMLNamespaceLength, &m_dwNumberofNamespaceparts); //ExecQuery operation doesnt need to pass an ObjPath - will be NULL! also enums if(SUCCEEDED(m_hResult)) m_hResult = AssignString(&m_pwszObjPath,const_cast(pObjPath)); if(SUCCEEDED(m_hResult)) m_hResult = AssignString(&m_pwszCimOperation,const_cast(pwszCimOperation)); // Initialize other members that will ultimately point to static member strings m_iPostType = 2; /*1 for POST, 2 for M-POST*/ m_pwszLocalOnly = FALSE_STRING; m_pwszIncludeQualifier = TRUE_STRING; m_pwszDeepInheritance = TRUE_STRING; m_pwszIncludeClassOrigin = TRUE_STRING; }; bool CXMLClientPacket::ClassConstructionSucceeded() { return (SUCCEEDED(m_hResult)) ? true : false; } CXMLClientPacket::~CXMLClientPacket() { delete [] m_pwszNameSpace; delete [] m_pwszObjPath; delete [] m_pwszCimOperation; delete [] m_pwszLocale; delete [] m_pwszQueryString; RELEASEINTERFACE(m_pCtx); } HRESULT CXMLClientPacket::SetPostType(int iPostType/*1 for POST, 2 for M-POST*/) { // Just set the member variable to one of the static members if((iPostType<1)||(iPostType>2)) return E_INVALIDARG; m_iPostType = iPostType; return S_OK; } HRESULT CXMLClientPacket::SetOptions(const WCHAR *pwszLocale, IWbemContext *pCtx, IWbemClassObject *pWbemClassObject, bool bLocalOnly, bool bIncludeQualifier, bool bDeepInheritance,bool bIncludeClassOrigin) { HRESULT hr = S_OK; // Set the context member //=============================== RELEASE_AND_NULL_INTERFACE(m_pCtx); if(m_pCtx = pCtx) m_pCtx->AddRef(); // Set the WMI object member //================================== RELEASE_AND_NULL_INTERFACE(m_pWbemClassObject); if(m_pWbemClassObject = pWbemClassObject) m_pWbemClassObject->AddRef(); (bLocalOnly == true) ? (m_pwszLocalOnly = TRUE_STRING) : (m_pwszLocalOnly = FALSE_STRING); (bIncludeQualifier == true) ? (m_pwszIncludeQualifier = TRUE_STRING) : (m_pwszIncludeQualifier = FALSE_STRING); (bDeepInheritance == true) ? (m_pwszDeepInheritance = TRUE_STRING) : (m_pwszDeepInheritance = FALSE_STRING); (bIncludeClassOrigin == true) ? (m_pwszIncludeClassOrigin = TRUE_STRING) : (m_pwszIncludeClassOrigin = FALSE_STRING); if(NULL != pwszLocale) hr = AssignString(&m_pwszLocale,pwszLocale); return hr; } HRESULT CXMLClientPacket::SetQueryLanguage(const WCHAR *pwszQueryLanguage) { if(NULL == pwszQueryLanguage) return E_INVALIDARG; wcscpy(m_pwszQueryLanguage,pwszQueryLanguage); return S_OK; } HRESULT CXMLClientPacket::SetQueryString(const WCHAR *pwszQueryString) { if(NULL == pwszQueryString) return E_INVALIDARG; RESET(m_pwszQueryString); return AssignString(&m_pwszQueryString,pwszQueryString); } HRESULT CXMLClientPacket::SetFlags(LONG lFlags) { m_lFlags = lFlags; return S_OK; } // In this function, we need to create the HTTP headers required for // an M-POST or POST request HRESULT CXMLClientPacket::GetHeader(WCHAR **ppwszHeader) { if(NULL == m_pwszCimOperation || NULL == ppwszHeader) return E_INVALIDARG; /*1 for POST, 2 for M-POST*/ if(m_iPostType == 1) return GetPostHeader(ppwszHeader); else if(m_iPostType == 2) return GetMPostHeader(ppwszHeader); else return E_FAIL; } // In this function, we need to create the HTTP headers required for // an POST request HRESULT CXMLClientPacket::GetPostHeader(WCHAR **ppwszHeader) { static const WCHAR *pwszHeaderLine = L"Content-Type:application/xml;charset=\"utf-8\"\r\nCIMOperation:MethodCall\r\nCIMMethod:"; int iSize = wcslen(pwszHeaderLine) + wcslen(m_pwszNameSpace) + wcslen(m_pwszCimOperation) + wcslen(L"\r\nCIMObject:") + 3; // For the \r\n to be appended iSize += wcslen(WHISTLER_HTTP_HEADER) + 3; if(NULL !=m_pwszLocale) iSize += wcslen(L"Accept-Language: xx, *\r\n"); if(*ppwszHeader = new WCHAR[iSize]) { wcscpy(*ppwszHeader, pwszHeaderLine); wcscat(*ppwszHeader, m_pwszCimOperation); wcscat(*ppwszHeader, L"\r\nCIMObject:"); wcscat(*ppwszHeader, m_pwszNameSpace); wcscat(*ppwszHeader, L"\r\n"); if(NULL != m_pwszLocale) { wcscat(*ppwszHeader, L"Accept-Language: "); wcscat(*ppwszHeader, m_pwszLocale); wcscat(*ppwszHeader, L", *\r\n"); } wcscat(*ppwszHeader, WHISTLER_HTTP_HEADER); wcscat(*ppwszHeader, L"\r\n"); } else return E_OUTOFMEMORY; return S_OK; } // In this function, we need to create the HTTP headers required for // an M-POST request HRESULT CXMLClientPacket::GetMPostHeader(WCHAR **ppwszHeader) { int size = wcslen(L"Content-Type:application/xml;charset=\"utf-8\"\r\n\ Man:http://www.dmtf.org/cim/mapping/http/v1.0 ; ns=99\r\n\ 99-CIMOperation:MethodCall\r\n99-CIMMethod:") + wcslen(m_pwszNameSpace) + wcslen(L"\r\n99-CIMObject:") + wcslen(m_pwszCimOperation) + 3; //\r\n to be appended // Get a 2 digit random value that is use to designate the M-POST namespace UINT i = 0; Get2DigitRandom(&i); if(NULL !=m_pwszLocale) size += wcslen(L"99-Accept-Language: xx, *\r\n"); WCHAR *pwszSpecialHeader = NULL; int iSpecialHeaderSize = wcslen(WHISTLER_HTTP_HEADER) + wcslen(L"99-") + 3; // \r\n if(pwszSpecialHeader = new WCHAR[iSpecialHeaderSize]) { wsprintf(pwszSpecialHeader,L"%02d-%s", i, WHISTLER_HTTP_HEADER); size += iSpecialHeaderSize; } else return E_OUTOFMEMORY; *ppwszHeader = NULL; if(*ppwszHeader = new WCHAR[size]) { if(NULL != m_pwszLocale) wsprintf(*ppwszHeader,L"%s\r\n%s%02d\r\n%02d%s\r\n%02d%s%s\r\n%02d%s%s\r\n%02d%s%s%s\r\n", L"Content-Type:application/xml;charset=\"utf-8\"", L"Man:http://www.dmtf.org/cim/mapping/http/v1.0 ; ns=", i,i, L"-CIMOperation:MethodCall", i, L"-CIMMethod:",m_pwszCimOperation, i, L"-CIMObject:", m_pwszNameSpace, i, L"-Accept-Language: ", m_pwszLocale, L", *" ); else wsprintf(*ppwszHeader,L"%s\r\n%s%02d\r\n%02d%s\r\n%02d%s%s\r\n%02d%s%s\r\n", L"Content-Type:application/xml;charset=\"utf-8\"", L"Man:http://www.dmtf.org/cim/mapping/http/v1.0 ; ns=", i,i, L"-CIMOperation:MethodCall", i, L"-CIMMethod:",m_pwszCimOperation, i, L"-CIMObject:", m_pwszNameSpace); if(NULL != pwszSpecialHeader) { wcscat(*ppwszHeader, pwszSpecialHeader); wcscat(*ppwszHeader, L"\r\n"); } delete [] pwszSpecialHeader; } else { delete [] pwszSpecialHeader; return E_OUTOFMEMORY; } return S_OK; } // Gets the length of the XML text to represent a element // and also gets the number of namespaces in the m_pwszNameSpace member HRESULT CXMLClientPacket::GetNamespaceLength(DWORD *pdwTotalLength, DWORD *pdwNumberofNamespaces) { if(NULL == m_pwszNameSpace) { *pdwTotalLength = 0; *pdwNumberofNamespaces = 0; return S_OK; } int iEnd = wcslen(m_pwszNameSpace), iStart=0; //We are not interested in the trailing slash or begginning slash if any. //both frontslash and back slash are supported.. if(m_pwszNameSpace[0] == '\\') iStart++; if(m_pwszNameSpace[iEnd] == '\\') iEnd --; int iNumNamespaces = 0; for(int i = iStart; i"); return S_OK; } HRESULT CXMLClientPacket::GetXMLNamespaceInStream(IStream *pStream) { if(NULL == pStream) return E_INVALIDARG; if((0 == m_dwXMLNamespaceLength)||(0 == m_dwNumberofNamespaceparts)) return S_OK; //nothing to write in stream LPWSTR pszCurrent = m_pwszNameSpace; LPWSTR pszEnd = m_pwszNameSpace + wcslen(m_pwszNameSpace) - 1; //We are not interested in the trailing slash or begginning slash if any. //both frontslash and back slash are supported.. if(*pszCurrent == '\\') pszCurrent ++; if(*pszEnd == '\\') pszEnd --; // Go thru the namespace string and break it into the individial namespace components LPWSTR pszBeginningOfLast = pszCurrent; while(true) //scan each character. { // Are we past one component or at the end of the string if(*pszCurrent == '\\' || *pszCurrent == NULL ) { // If so, use the component that we just passed pStream->Write(L"Write(pszBeginningOfLast, (int)(((INT_PTR)(pszCurrent- pszBeginningOfLast))*sizeof(WCHAR)), NULL); pStream->Write(L"\"/>", wcslen(L"\"/>")*sizeof(WCHAR), NULL); pszBeginningOfLast = pszCurrent+1; } if(*pszCurrent == NULL ) break; pszCurrent++; } return S_OK; } HRESULT CXMLClientPacket::GetBodyTillLocalNamespacePathInStream(IStream **ppStream) { HRESULT hr = E_FAIL; if(SUCCEEDED(hr = CreateStreamOnHGlobal(NULL, TRUE, ppStream))) { UINT i = 0; Get4DigitRandom(&i); WRITETOSTREAM(*ppStream, L""); WRITETOSTREAM(*ppStream, L""); WRITETOSTREAM(*ppStream, L""); WRITETOSTREAM(*ppStream, L""); WRITETOSTREAM(*ppStream, L""); // We put Namespace information here only for Nova style paths if(m_ePathstyle == NOVAPATH) { WRITETOSTREAM(*ppStream, L""); hr = GetXMLNamespaceInStream(*ppStream); WRITETOSTREAM(*ppStream, L""); } if(SUCCEEDED(hr) && (NULL != m_pCtx)) hr = ConvertContextObjectToXMLStream(*ppStream, m_pCtx); } if(FAILED(hr) && (*ppStream)) { (*ppStream)->Release(); *ppStream = NULL; } return hr; } HRESULT CXMLClientPacket::GetBodyDirect(const WCHAR *pwszXMLObjPath,DWORD dwLengthofObjPath, WCHAR **ppwszBody, DWORD *pdwLengthofPacket) { return E_NOTIMPL; //implemented by derived classes. all of them need not implement this functionality. } DEFINE_GUID(CLSID_WbemXMLConvertor, 0x610037ec, 0xce06, 0x11d3, 0x93, 0xfc, 0x0, 0x80, 0x5f, 0x85, 0x37, 0x71); HRESULT CXMLClientPacket::ConvertWbemObjectToXMLStream(IStream *pStream) { if(NULL == m_pWbemClassObject) return E_INVALIDARG; HRESULT hres = S_OK; IWbemXMLConvertor *ppv = NULL; if(SUCCEEDED(hres = CoCreateInstance(CLSID_WbemXMLConvertor, NULL, CLSCTX_INPROC, IID_IWbemXMLConvertor,(void**)&ppv))) { IWbemContext *pCtx = NULL; bool bModifyInstance = false; // Set the correct IWbemContext required by the convertor // We have 3 global contexts and we set pCtx to the right one, // based on the operation if(_wcsicmp(m_pwszCimOperation,L"ExecMethod")==0) { //LOCALINSTANCEPATH|LOCALCLASSPATH pCtx = g_pLocalCtx; } else { if((_wcsicmp(m_pwszCimOperation, L"CreateClass")==0) || (_wcsicmp(m_pwszCimOperation, L"CreateInstance")==0)|| (_wcsicmp(m_pwszCimOperation, L"ModifyClass")==0)) { //INSTANCE|CLASS pCtx = g_pAnonymousCtx; } else { if(_wcsicmp(m_pwszCimOperation,L"ModifyInstance")==0) { bModifyInstance = true; pCtx = g_pNamedCtx; } } } if(bModifyInstance) WRITETOSTREAM(pStream,L""); hres = ppv->MapObjectToXML(m_pWbemClassObject, NULL, 0, pCtx, pStream, NULL); if(bModifyInstance) WRITETOSTREAM(pStream,L""); ppv->Release(); } return hres; } HRESULT CXMLClientPacket::GetParamsFromObjectInStream(IStream *pStream) { if(NULL == m_pWbemClassObject) return E_INVALIDARG; IWbemXMLConvertor *ppv = NULL; HRESULT hres = CoCreateInstance(CLSID_WbemXMLConvertor, NULL,CLSCTX_INPROC, IID_IWbemXMLConvertor,(void**)&ppv); if(SUCCEEDED(hres)) { SAFEARRAY *psaNames = NULL; if(SUCCEEDED(hres = m_pWbemClassObject->GetNames(NULL,WBEM_FLAG_ALWAYS| WBEM_FLAG_NONSYSTEM_ONLY,NULL,&psaNames))) { long lLower=0, lUpper=0; SafeArrayGetLBound(psaNames, 1, &lLower); SafeArrayGetUBound(psaNames, 1, &lUpper); BSTR pwszPropname = NULL; for (long i = lLower; i <= lUpper; i++) { // Get this property. if(SUCCEEDED(hres = SafeArrayGetElement(psaNames,&i,&pwszPropname))) { pStream->Write(L"Write(pwszPropname,SysStringLen(pwszPropname)*sizeof(WCHAR),NULL); pStream->Write(L"\">",wcslen(L"\">")*sizeof(WCHAR),NULL); ppv->MapPropertyToXML(m_pWbemClassObject, pwszPropname, g_pLocalCtx, pStream); pStream->Write(L"",wcslen(L"")*sizeof(WCHAR),NULL); SysFreeString(pwszPropname); } } SafeArrayDestroy(psaNames); } ppv->Release(); } return hres; } HRESULT CXMLClientPacket::SetMethod(const WCHAR *pwszMethod) { if(NULL == pwszMethod) return E_INVALIDARG; RESET(m_pwszCimOperation); return AssignString(&m_pwszCimOperation, const_cast(pwszMethod)); } HRESULT CXMLClientPacket::GetKeyBindingsInStream(IStream *pStream) { HRESULT hr = S_OK; IWbemXMLConvertor *ppv = NULL; if(SUCCEEDED(hr = CoCreateInstance(CLSID_WbemXMLConvertor, NULL,CLSCTX_INPROC, IID_IWbemXMLConvertor,(void**)&ppv))) { if(m_ePathstyle = NOVAPATH) { BSTR strInstanceName = NULL; if(strInstanceName = SysAllocString(m_pwszObjPath)) { hr = ppv->MapInstanceNameToXML(strInstanceName, NULL, pStream); SysFreeString(strInstanceName); } else hr = E_OUTOFMEMORY; } else { WRITETOSTREAM(pStream, L""); WRITETOSTREAM(pStream, m_pwszObjPath); WRITETOSTREAM(pStream, L""); } ppv->Release(); } return hr; }