|
|
/*++
Copyright (C) 1996-2001 Microsoft Corporation
Module Name:
MOFDATA.CPP
Abstract:
Entry points for the WBEM MOF compiler.
History:
a-davj 12-April-97 Added WMI support.
--*/
#include "precomp.h"
#include <cominit.h>
#include "mofout.h"
#include "mofdata.h"
#include "typehelp.h"
#include "bmof.h"
#include "cbmofout.h"
#include "trace.h"
#include "strings.h"
#include "arrtempl.h"
#include <genutils.h>
#define TEMP_BUF 128
WCHAR * Macro_CloneStr(LPCWSTR pFr) { if(pFr == NULL) return NULL; DWORD dwLen = wcslen(pFr) + 1; WCHAR * pTo = new WCHAR[dwLen]; if(pTo) { StringCchCopyW(pTo, dwLen, pFr); return pTo; } return NULL; }
HRESULT MofdSetInterfaceSecurity(IUnknown * pInterface, LPWSTR pAuthority, LPWSTR pUser, LPWSTR pPassword) { SCODE sc; BOOL bUseAuthInfo = FALSE;
DWORD dwQueryAuthnLevel, dwQueryImpLevel, dwQueryCapabilities; DWORD dwAuthnSvc = RPC_C_AUTHN_GSS_NEGOTIATE; WCHAR * pwCSPBPrincipal = NULL;
HRESULT hr = CoQueryProxyBlanket( pInterface, //Location for the proxy to query
&dwAuthnSvc, //Location for the current authentication service
NULL, //Location for the current authorization service
NULL, //Location for the current principal name
&dwQueryAuthnLevel, //Location for the current authentication level
&dwQueryImpLevel, //Location for the current impersonation level
NULL, &dwQueryCapabilities //Location for flags indicating further capabilities of the proxy
); if(SUCCEEDED(hr) && dwAuthnSvc != RPC_C_AUTHN_WINNT) { pwCSPBPrincipal = COLE_DEFAULT_PRINCIPAL; } else { dwAuthnSvc = RPC_C_AUTHN_WINNT; pwCSPBPrincipal = NULL; }
// If we are doing trivial case, just pass in a null authenication structure which is used
// if the current logged in user's credentials are OK.
if((pAuthority == NULL || wcslen(pAuthority) < 1) && (pUser == NULL || wcslen(pUser) < 1) && (pPassword == NULL || wcslen(pPassword) < 1)) { return WbemSetProxyBlanket(pInterface, dwAuthnSvc, RPC_C_AUTHZ_NONE, pwCSPBPrincipal, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_STATIC_CLOAKING); }
// If user, or Authority was passed in, the we need to create an authority argument for the login
COAUTHIDENTITY authident; BSTR AuthArg = NULL, UserArg = NULL, PrincipalArg = NULL; sc = DetermineLoginTypeEx(AuthArg, UserArg, PrincipalArg, pAuthority, pUser); if(sc != S_OK) return sc; CSysFreeMe fm1(UserArg), fm2(AuthArg), fm3(PrincipalArg); memset((void *)&authident,0,sizeof(COAUTHIDENTITY)); if(UserArg) { authident.UserLength = wcslen(UserArg); authident.User = (LPWSTR)UserArg; bUseAuthInfo = TRUE; } if(AuthArg) { authident.DomainLength = wcslen(AuthArg); authident.Domain = (LPWSTR)AuthArg; bUseAuthInfo = TRUE; } if(pPassword) { authident.PasswordLength = wcslen(pPassword); authident.Password = (LPWSTR)pPassword; bUseAuthInfo = TRUE; } authident.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
sc = WbemSetProxyBlanket(pInterface, (PrincipalArg) ? RPC_C_AUTHN_GSS_KERBEROS : dwAuthnSvc, RPC_C_AUTHZ_NONE, (PrincipalArg) ? PrincipalArg : pwCSPBPrincipal, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, (bUseAuthInfo) ? &authident : NULL, (bUseAuthInfo) ? 0 : EOAC_STATIC_CLOAKING ); return sc; }
CNamespaceCache::CNamespaceRecord::CNamespaceRecord( COPY LPCWSTR wszName, ADDREF IWbemServices* pNamespace) { m_wszName = Macro_CloneStr(wszName); m_pNamespace = pNamespace; m_pNamespace->AddRef(); }
CNamespaceCache::CNamespaceRecord::~CNamespaceRecord() { delete [] m_wszName; if(m_pNamespace) m_pNamespace->Release(); }
//*****************************************************************************
CNamespaceCache::CNamespaceCache(ADDREF IWbemLocator* pLocator) { if(pLocator) pLocator->AddRef(); m_pLocator = pLocator; }
CNamespaceCache::~CNamespaceCache() { if(m_pLocator) m_pLocator->Release(); for(int i = 0; i < m_aRecords.GetSize(); i++) { delete (CNamespaceRecord*)m_aRecords[i]; } }
RELEASE_ME IWbemServices* CNamespaceCache::GetNamespace(COPY LPCWSTR wszName, SCODE & scRet, WCHAR * pUserName, WCHAR * pPassword , WCHAR * pAuthority, IWbemContext * pCtx, GUID LocatorGUID, LONG fConnectFlags) { // Check if it is the cache
// ========================
scRet = S_OK;
for(int i = 0; i < m_aRecords.GetSize(); i++) { CNamespaceRecord* pRecord = (CNamespaceRecord*)m_aRecords[i]; if(!wbem_wcsicmp(pRecord->m_wszName, wszName)) { // Found it
// ========
pRecord->m_pNamespace->AddRef(); return pRecord->m_pNamespace; } }
// Not found --- open it
// =====================
IWbemServices* pNamespace;
if(wszName == NULL) return NULL;
LPOLESTR pwszName; pwszName = SysAllocString(wszName); if(pwszName == NULL) return NULL; CSysFreeMe fm0(pwszName); LPOLESTR bstrPassword = NULL; LPOLESTR bstrUserName = NULL; LPOLESTR bstrAuthority = NULL; if(pUserName && wcslen(pUserName) > 0) { bstrUserName = SysAllocString(pUserName); if(bstrUserName == NULL) return NULL; } CSysFreeMe fm1(bstrUserName); if(pPassword) { bstrPassword = SysAllocString(pPassword); if(bstrPassword == NULL) return NULL; } CSysFreeMe fm2(bstrPassword); if(pAuthority && wcslen(pAuthority) > 0) { bstrAuthority = SysAllocString(pAuthority); if(bstrAuthority == NULL) return NULL; } CSysFreeMe fm3(bstrAuthority);
// Determine if the connection is to the regular locator, or to one of the special inproc ones
// used for autocompile. If it is inproc, then remote connections are not valid.
bool bInProc = false; if(LocatorGUID != CLSID_WbemLocator) bInProc = true;
if(bInProc) { WCHAR * pMachine = ExtractMachineName(pwszName); if(pMachine) { BOOL bLocal = bAreWeLocal(pMachine); delete pMachine; if(!bLocal) { scRet = WBEM_E_INVALID_NAMESPACE; ERRORTRACE((LOG_MOFCOMP,"Error, tried to do a remote connect during autocomp\n")); } } }
// Connect up to namespace. //TODO, PASS AUTHORITY IN THE CONTEXT
if(scRet == S_OK) scRet = m_pLocator->ConnectServer((LPWSTR)pwszName, bstrUserName, bstrPassword, NULL, fConnectFlags, pAuthority, pCtx, &pNamespace); if(scRet == S_OK && !bInProc) {
// Set the impersonation level up so that puts to providers can be done
DWORD dwAuthLevel, dwImpLevel; SCODE sc = GetAuthImp( pNamespace, &dwAuthLevel, &dwImpLevel); if(sc != S_OK || dwAuthLevel != RPC_C_AUTHN_LEVEL_NONE) sc = MofdSetInterfaceSecurity(pNamespace, bstrAuthority, bstrUserName, bstrPassword);
}
if(FAILED(scRet)) return NULL;
// Add it to the cache
// ===================
CNamespaceRecord * pNew = new CNamespaceRecord(wszName, pNamespace); if(pNew) m_aRecords.Add(pNew); // AddRef'ed
return pNamespace; }
//*****************************************************************************
//*****************************************************************************
void CMofData::SetQualifierDefault(ACQUIRE CMoQualifier* pDefault) { // Search for this qualifier in the defaults list
// ==============================================
for(int i = 0; i < m_aQualDefaults.GetSize(); i++) { CMoQualifier* pOrig = (CMoQualifier*)m_aQualDefaults[i];
if(wbem_wcsicmp(pOrig->GetName(), pDefault->GetName()) == 0) { // Found it. Replace
// =================
delete pOrig; m_aQualDefaults[i] = (void*)pDefault; return; } } // Not found. Add
// ==============
m_aQualDefaults.Add((void*)pDefault); }
HRESULT CMofData::SetDefaultFlavor(MODIFY CMoQualifier& Qual, bool bTopLevel, QUALSCOPE qs, PARSESTATE ps) { HRESULT hr;
// Search for this qualifier in the defaults list
// ==============================================
for(int i = 0; i < m_aQualDefaults.GetSize(); i++) { CMoQualifier* pOrig = (CMoQualifier*)m_aQualDefaults[i];
if(wbem_wcsicmp(pOrig->GetName(), Qual.GetName()) == 0) { // Found it. SetFlavor
// ===================
if(pOrig->IsCimDefault()) { // dont bother if the parse state is the initial scan
if(ps == INITIAL) continue; if(Qual.IsUsingDefaultValue()) {
// see if the scope matches what we have here
DWORD dwScope = pOrig->GetScope(); bool bInScope = false; if((dwScope & SCOPE_CLASS) || (dwScope & SCOPE_INSTANCE)) if(qs == CLASSINST_SCOPE) bInScope = true; if(dwScope & SCOPE_PROPERTY) if(qs == PROPMETH_SCOPE) bInScope = true;
if(bInScope) { CMoValue& Src = pOrig->AccessValue(); CMoValue& Dest = Qual.AccessValue(); Dest.SetType(Src.GetType()); VARIANT & varSrc = Src.AccessVariant(); VARIANT & varDest = Dest.AccessVariant(); hr = VariantCopy(&varDest, &varSrc); if(FAILED(hr)) return hr; Qual.SetFlavor(pOrig->GetFlavor()); Qual.SetAmended(pOrig->IsAmended()); } } } else { Qual.SetFlavor(pOrig->GetFlavor()); Qual.SetAmended(pOrig->IsAmended()); } return S_OK; } } return S_OK; }
BOOL CMofData::IsAliasInUse(READ_ONLY LPWSTR wszAlias) { for(int i = 0; i < m_aObjects.GetSize(); i++) { CMObject* pObject = (CMObject*)m_aObjects[i]; if(pObject->GetAlias() && !wbem_wcsicmp(pObject->GetAlias(), wszAlias)) { return TRUE; } }
return FALSE; }
BOOL IsGuid(LPWSTR pTest) { int i; int iSoFar = 0;
#define HEXCHECK(n) \
for (i = 0; i < n; i++) \ if (!iswxdigit(*pTest++)) \ return FALSE;
#define HYPHENCHECK() \
if (*pTest++ != L'-') \ return FALSE;
if(*pTest++ != L'{') return FALSE;
HEXCHECK(8); HYPHENCHECK(); HEXCHECK(4); HYPHENCHECK(); HEXCHECK(4); HYPHENCHECK(); HEXCHECK(4); HYPHENCHECK(); HEXCHECK(12);
if(*pTest++ != L'}') return FALSE;
return TRUE;
}
INTERNAL LPCWSTR CMofData::FindAliasee(READ_ONLY LPWSTR wszAlias) { for(int i = 0; i < m_aObjects.GetSize(); i++) { CMObject* pObject = (CMObject*)m_aObjects[i]; if(pObject->GetAlias() && !wbem_wcsicmp(pObject->GetAlias(), wszAlias)) { IWbemClassObject * pTemp; pTemp = pObject->GetWbemObject();
// check for unresolved aliases in keys
if(pTemp && pObject->IsDone() == FALSE) {
SCODE sc = pTemp->BeginEnumeration(WBEM_FLAG_KEYS_ONLY | WBEM_FLAG_REFS_ONLY); if(sc != S_OK) return NULL; VARIANT var; VariantInit(&var); while ((sc = pTemp->Next(0, NULL, &var, NULL, NULL)) == S_OK) { if(var.vt == VT_BSTR && IsGuid(var.bstrVal)) { VariantClear(&var); return NULL; } VariantClear(&var); } } return pObject->GetFullPath(); } }
return NULL; }
HRESULT CMofData::Store(CMofParser & Parser, OLE_MODIFY IWbemLocator* pLocator,IWbemServices *pOverride,BOOL bRollbackable, WCHAR * pUserName, WCHAR * pPassword, WCHAR * pAuthority, IWbemContext * pCtx, GUID LocatorGUID, WBEM_COMPILE_STATUS_INFO *pInfo, BOOL bClassOwnerUpdate, BOOL bInstanceOwnerUpdate, LONG fConnectFlags) { HRESULT hres = WBEM_E_FAILED; int i; CNamespaceCache Cache(pLocator); BOOL bMakingProgress = TRUE; long lClassFlags = 0; long lInstanceFlags = 0;
while(bMakingProgress) { bMakingProgress = FALSE; for(i = 0; i< m_aObjects.GetSize(); i++) { CMObject* pObject = (CMObject*)m_aObjects[i]; if(pObject->IsDone()) continue; lClassFlags = pObject->GetClassFlags(); lInstanceFlags = pObject->GetInstanceFlags(); if(bClassOwnerUpdate) { lClassFlags |= WBEM_FLAG_OWNER_UPDATE; } if(bInstanceOwnerUpdate) { lInstanceFlags |= WBEM_FLAG_OWNER_UPDATE; } // Get a namespace pointer for this object.
SCODE scRet; IWbemServices* pNamespace = NULL; if(pOverride && !wbem_wcsicmp(L"root\\default", pObject->GetNamespace())) { // AddRef() the namespace pointer, since we will be Releasing
// it below
pOverride->AddRef(); pNamespace = pOverride; } else { // This will return an AddRef'd pointer
pNamespace = Cache.GetNamespace(pObject->GetNamespace(), scRet, pUserName, pPassword ,pAuthority, pCtx, LocatorGUID, fConnectFlags); }
if(pNamespace == NULL) { int iMsg = (GotLineNumber(i)) ? ERROR_OPENING : ERROR_OPENING_NO_LINES; PrintError(i, iMsg, scRet, pInfo); return scRet; }
// Ensures we release the namespace pointer when we go out of scope
CReleaseMe rmns( pNamespace );
// If there isnt a wbem object, try to get one. This will fail if this is a
// instance for which the class hasn't been saved just yet.
if(pObject->GetWbemObject() == NULL) {
IWbemClassObject* pWbemObject = NULL; hres = pObject->CreateWbemObject(pNamespace, &pWbemObject,pCtx); if(hres != S_OK) if(pObject->IsInstance()) continue; else { PrintError(i, (GotLineNumber(i)) ? ERROR_CREATING : ERROR_CREATING_NO_LINES, hres, pInfo); return WBEM_E_FAILED; } bMakingProgress = TRUE; pObject->Reflate(Parser); pObject->SetWbemObject(pWbemObject);
if(!pObject->ApplyToWbemObject(pWbemObject, pNamespace,pCtx)) { hres = m_pDbg->hresError; PrintError(i, (GotLineNumber(i)) ? ERROR_CREATING : ERROR_CREATING_NO_LINES, hres, pInfo); return WBEM_E_FAILED; }
} // If there are no unresolved aliases, save it!
if(pObject->GetNumAliasedValues() == 0 || S_OK == pObject->ResolveAliasesInWbemObject(pObject->GetWbemObject(), (CMofAliasCollection*)this)) {
// Save this into WinMgmt
// ==================
hres = pObject->StoreWbemObject(pObject->GetWbemObject(), lClassFlags, lInstanceFlags, pNamespace, pCtx, pUserName, pPassword ,pAuthority); if(hres != S_OK) { PrintError(i, (GotLineNumber(i)) ? ERROR_STORING : ERROR_STORING_NO_LINES, hres, pInfo); return WBEM_E_FAILED; } pObject->FreeWbemObjectIfPossible(); pObject->Deflate(false); pObject->SetDone(); bMakingProgress = TRUE; }
} }
// If there is one or more objects that cant be resolved, print and bail
for(i = 0; i < m_aObjects.GetSize(); i++) { CMObject* pObject = (CMObject*)m_aObjects[i]; if(pObject && !pObject->IsDone()) { PrintError(i, (GotLineNumber(i)) ? ERROR_RESOLVING : ERROR_RESOLVING_NO_LINES, hres, pInfo); return WBEM_E_FAILED; } } return S_OK; }
HRESULT CMofData::RollBack(int nObjects) { return WBEM_E_FAILED; }
BOOL CMofData::GotLineNumber(int nIndex) { CMObject* pObject = (CMObject*)m_aObjects[nIndex]; if(pObject == NULL || (pObject->GetFirstLine() == 0 && pObject->GetLastLine() == 0)) return FALSE; else return TRUE; } void CMofData::PrintError(int nIndex, long lMsgNum, HRESULT hres, WBEM_COMPILE_STATUS_INFO *pInfo) { CMObject* pObject = (CMObject*)m_aObjects[nIndex]; TCHAR szMsg[500]; bool bErrorFound = false;
if(pInfo) pInfo->ObjectNum = nIndex+1; if(!GotLineNumber(nIndex)) Trace(true, m_pDbg, lMsgNum, nIndex+1); else { Trace(true, m_pDbg, lMsgNum, nIndex+1, pObject->GetFirstLine(), pObject->GetLastLine(), pObject->GetFileName()); if(pInfo) { pInfo->FirstLine = pObject->GetFirstLine(); pInfo->LastLine = pObject->GetLastLine(); } } if(hres) {
// A few error messages are retrived from the local resources. This is so that the name can be
// injected into the name.
if(hres == WBEM_E_NOT_FOUND || hres == WBEM_E_TYPE_MISMATCH || hres == WBEM_E_OVERRIDE_NOT_ALLOWED || hres == WBEM_E_PROPAGATED_QUALIFIER || hres == WBEM_E_VALUE_OUT_OF_RANGE) { Trace(true, m_pDbg, ERROR_FORMAT, hres); Trace(true, m_pDbg, hres, m_pDbg->GetString()); bErrorFound = true; } else { // Get the error from the standard error facility
IWbemStatusCodeText * pStatus = NULL; SCODE sc = CoCreateInstance(CLSID_WbemStatusCodeText, 0, CLSCTX_INPROC_SERVER, IID_IWbemStatusCodeText, (LPVOID *) &pStatus); if(sc == S_OK) { BSTR bstrError = 0; BSTR bstrFacility = 0; sc = pStatus->GetErrorCodeText(hres, 0, 0, &bstrError); if(sc == S_OK) { sc = pStatus->GetFacilityCodeText(hres, 0, 0, &bstrFacility); if(sc == S_OK) { IntString is(ERROR_FORMAT_LONG); StringCchPrintfW(szMsg, 500, is, hres, bstrFacility, bstrError); bErrorFound = true; SysFreeString(bstrFacility); } SysFreeString(bstrError); } pStatus->Release(); }
// if all else fails, just use the generic error message
if(!bErrorFound) { IntString is(ERROR_FORMATEX); StringCchPrintfW(szMsg, 500 ,is, hres); }
// Print the error message
if(m_pDbg->m_bPrint) printf("%S", szMsg); ERRORTRACE((LOG_MOFCOMP,"%S", szMsg));
} // ELSE get error from standard facility
} // IF hres
}
//***************************************************************************
//
// GetFileNames
//
// DESCRIPTION:
//
// The amendment local, the localized and neutral file names are passed
// in using the BMOF string. These values are separated by commas and
// a single letter which indicates what follows. An example string
// would be ",aMS_409,nNEUTRAL.MOF,lLocalMof" Notice that the amendment
// substring starts with an 'a', the neutral starts with 'n', and the
// locale starts with 'l'.
//
// While the neutral name is required, the locale version isnt. If not
// supplied, it will be created. The two character inputs are ASSUMED to
// point to preallocated buffers of MAX_PATH size!
//
//***************************************************************************
HRESULT GetFileNames(TCHAR * pcNeutral, TCHAR * pcLocale, LPWSTR pwszBMOF) { WCHAR * pNeutral=NULL; WCHAR * pLocale=NULL; if(pwszBMOF == NULL) return WBEM_E_INVALID_PARAMETER;
// make a copy of the string
DWORD dwLen = wcslen(pwszBMOF)+1; WCHAR *pTemp = new WCHAR[dwLen]; if(pTemp == NULL) return WBEM_E_OUT_OF_MEMORY;
CDeleteMe<WCHAR> dm1(pTemp); StringCchCopyW(pTemp, dwLen, pwszBMOF);
// use wcstok to do a seach
WCHAR * token = wcstok( pTemp, L"," ); while( token != NULL ) { if(token[0] == L'n') { pNeutral = token+1; CopyOrConvert(pcNeutral, pNeutral, MAX_PATH); } else if(token[0] == L'l') { pLocale = token+1; CopyOrConvert(pcLocale, pLocale, MAX_PATH); } token = wcstok( NULL, L"," ); }
// If the neutral name was not specified, that is an error
if(pNeutral == NULL) return WBEM_E_INVALID_PARAMETER;
// If the local name was not specified, create it and make it the
// same as the neutral name except for changing the mfl extension
if(pLocale == NULL) { TCHAR * pFr = pcNeutral,* pTo = pcLocale; for(; *pFr && *pFr != '.'; pTo++, pFr++) *pTo = *pFr; *pTo=0; StringCchCatW(pcLocale, MAX_PATH, TEXT(".mfl")); }
// make sure that the locale and neutral names are not the same
if(!lstrcmpi(pcLocale, pcNeutral)) return WBEM_E_INVALID_PARAMETER;
return S_OK; }
//***************************************************************************
//
// GetLocale
//
// DESCRIPTION:
//
// Converts the amendment string to a local number. An example string
// would be "MS_409"
//
//***************************************************************************
HRESULT GetLocale(long * plLocale, WCHAR * pwszAmendment) { if(pwszAmendment == NULL || wcslen(pwszAmendment) != 6) return WBEM_E_INVALID_PARAMETER; *plLocale = 0; swscanf(pwszAmendment+3,L"%x", plLocale); return (*plLocale != 0) ? S_OK : WBEM_E_INVALID_PARAMETER; }
//***************************************************************************
//
// RecursiveSetAmended
//
// DESCRIPTION:
//
// Sets the boolean indicating that an object is to be amended and all of
// its parents
//
//***************************************************************************
void CMofData::RecursiveSetAmended(CMObject * pObj) {
// If the object is already amended, then its parents are already set.
// In that case, our job is done here!
if(pObj->IsAmended()) return;
// If the object hasnt been set yet, set it and also set its parents
pObj->SetAmended(true); // Look for the parent and do the same
if(pObj->IsInstance() || pObj->IsDelete()) return; // run away now if this is a instance!
CMoClass * pClass = (CMoClass *)pObj; const WCHAR *pClassName = pClass->GetParentName(); if(pClassName == NULL) return;
// Find the parent and recursively set it!
for(int i = 0; i< m_aObjects.GetSize(); i++) { CMObject* pObject = (CMObject*)m_aObjects[i]; if(pObject && pObject->GetClassName() && !wbem_wcsicmp(pClassName, pObject->GetClassName())) { RecursiveSetAmended(pObject); } }
}
//***************************************************************************
//
// CMofData::Split
//
// DESCRIPTION:
//
// Creates a neutral and locale specific mof.
//
// Parameters:
// pwszBMOF See the GetFileNames() comments
// pInfo usual error info
// bUnicode if true, then the orignal file was unicode and so the
// new files will also be unicode
// bAutoRecovery Need to add this pragma if true
// pwszAmendment See the GetLocale() comments
//
//***************************************************************************
HRESULT CMofData::Split(CMofParser & Parser, LPWSTR pwszBMOF, WBEM_COMPILE_STATUS_INFO *pInfo, BOOL bUnicode, BOOL bAutoRecovery, LPWSTR pwszAmendment) { int i; TCHAR cNeutral[MAX_PATH]; TCHAR cLocale[MAX_PATH]; // Determine the file names and locale
HRESULT hRes = GetFileNames(cNeutral, cLocale, pwszBMOF); if(hRes != S_OK) return S_OK;
long lLocale; hRes = GetLocale(&lLocale, pwszAmendment); if(hRes != S_OK) return S_OK;
// Create the output objects
COutput Neutral(cNeutral, NEUTRAL, bUnicode, bAutoRecovery, lLocale); COutput Local(cLocale, LOCALIZED, bUnicode, bAutoRecovery, lLocale); if(!Neutral.IsOK() || !Local.IsOK()) return WBEM_E_INVALID_PARAMETER;
// Start by determining what is amended
for(i = 0; i< m_aObjects.GetSize(); i++) { CMObject* pObject = (CMObject*)m_aObjects[i]; pObject->Reflate(Parser); if(pObject->CheckIfAmended()) { RecursiveSetAmended(pObject); } }
// Create the neutral output and the localized output.
// These two loops could have been combined, but are
// separate for debugging purposes
for(i = 0; i< m_aObjects.GetSize(); i++) { CMObject* pObject = (CMObject*)m_aObjects[i]; pObject->Split(Neutral); } for(i = 0; i< m_aObjects.GetSize(); i++) { CMObject* pObject = (CMObject*)m_aObjects[i]; pObject->Split(Local); }
return S_OK; }
|