1119 lines
32 KiB
C++
1119 lines
32 KiB
C++
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <initguid.h>
|
|
#include <objbase.h>
|
|
#include <objsafe.h>
|
|
#include <wbemcli.h>
|
|
#include "wmiconv.h"
|
|
#include "xmltrnsf.h"
|
|
#include "errors.h"
|
|
#include "ui.h"
|
|
#include "opns.h"
|
|
#include "resource.h"
|
|
|
|
static HRESULT FilterOutputFromSet(ISWbemXMLDocumentSet *pOutput, CXmlCompUI *pUI );
|
|
static HRESULT FilterOutputForSingleObject(IXMLDOMDocument *pOutput, CXmlCompUI *pUI );
|
|
static HRESULT CreateXMLTranslator(IWbemXMLConvertor **pConvertor);
|
|
|
|
// Creates the Transformer control
|
|
static HRESULT CreateControl(IWmiXMLTransformer **ppControl)
|
|
{
|
|
return CoCreateInstance (CLSID_WmiXMLTransformer, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_IWmiXMLTransformer, (LPVOID *)ppControl);
|
|
}
|
|
|
|
// Sets some properties that control the behaviour of the transformer control
|
|
HRESULT SetCommonControlProperties(IWmiXMLTransformer *pControl, CXmlCompUI *pUI)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
// The type of encoding required
|
|
if(SUCCEEDED(hr) && SUCCEEDED(hr = pControl->put_XMLEncodingType(pUI->m_iEncodingType)))
|
|
{
|
|
}
|
|
|
|
// Qualifier Filter
|
|
if(SUCCEEDED(hr) && SUCCEEDED(hr = pControl->put_QualifierFilter((pUI->m_bQualifierLevel)? VARIANT_TRUE : VARIANT_FALSE)))
|
|
{
|
|
}
|
|
|
|
// Class Origin Filter
|
|
if(SUCCEEDED(hr) && SUCCEEDED(hr = pControl->put_ClassOriginFilter((pUI->m_bClassOrigin)? VARIANT_TRUE : VARIANT_FALSE)))
|
|
{
|
|
}
|
|
|
|
// Local Only
|
|
if(SUCCEEDED(hr) && SUCCEEDED(hr = pControl->put_LocalOnly((pUI->m_bLocalOnly)? VARIANT_TRUE : VARIANT_FALSE)))
|
|
{
|
|
}
|
|
|
|
// User name
|
|
if(SUCCEEDED(hr) && pUI->m_pszUser)
|
|
{
|
|
BSTR strUser = NULL;
|
|
if(strUser = SysAllocString(pUI->m_pszUser))
|
|
{
|
|
if(SUCCEEDED(hr = pControl->put_User(strUser)))
|
|
{
|
|
}
|
|
SysFreeString(strUser);
|
|
}
|
|
else
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
// Password
|
|
if(SUCCEEDED(hr) && pUI->m_pszPassword)
|
|
{
|
|
BSTR strPasswd = NULL;
|
|
if(strPasswd = SysAllocString(pUI->m_pszPassword))
|
|
{
|
|
if(SUCCEEDED(hr = pControl->put_Password(strPasswd)))
|
|
{
|
|
}
|
|
SysFreeString(strPasswd);
|
|
}
|
|
else
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
// Impersonation Level
|
|
if(SUCCEEDED(hr) && SUCCEEDED(hr = pControl->put_ImpersonationLevel(pUI->m_dwImpersonationLevel)))
|
|
{
|
|
}
|
|
|
|
// Authentication Level
|
|
if(SUCCEEDED(hr) && SUCCEEDED(hr = pControl->put_AuthenticationLevel(pUI->m_dwAuthenticationLevel)))
|
|
{
|
|
}
|
|
|
|
// Locale
|
|
if(SUCCEEDED(hr) && pUI->m_pszLocale)
|
|
{
|
|
BSTR strLocale = NULL;
|
|
if(strLocale = SysAllocString(pUI->m_pszLocale))
|
|
{
|
|
if(SUCCEEDED(hr = pControl->put_Locale(strLocale)))
|
|
{
|
|
}
|
|
SysFreeString(strLocale);
|
|
}
|
|
else
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT DoGetObject(CXmlCompUI *pUI)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
IWmiXMLTransformer *pControl = NULL;
|
|
|
|
// Create the Backend Control
|
|
if(SUCCEEDED(hr = CreateControl(&pControl)))
|
|
{
|
|
// Set most of the operation independent flags
|
|
if(SUCCEEDED(hr = SetCommonControlProperties(pControl, pUI)))
|
|
{
|
|
// Set Object Path, Host Name and Namespace Path
|
|
BSTR strObjectPath = NULL;
|
|
if(strObjectPath = SysAllocString(pUI->m_pszObjectPath))
|
|
{
|
|
// Do the operation
|
|
IXMLDOMDocument *pOutput = NULL;
|
|
if(SUCCEEDED(hr = pControl->GetObject(strObjectPath, NULL, &pOutput)))
|
|
{
|
|
hr = FilterOutputForSingleObject(pOutput, pUI);
|
|
pOutput->Release();
|
|
}
|
|
}
|
|
else
|
|
hr = E_OUTOFMEMORY;
|
|
SysFreeString(strObjectPath);
|
|
}
|
|
pControl->Release();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT DoQuery(CXmlCompUI *pUI)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
IWmiXMLTransformer *pControl = NULL;
|
|
|
|
// Create the Backend Control
|
|
if(SUCCEEDED(hr = CreateControl(&pControl)))
|
|
{
|
|
// Set most of the operation independent flags
|
|
if(SUCCEEDED(hr = SetCommonControlProperties(pControl, pUI)))
|
|
{
|
|
// Set Object Path, Host Name and Namespace Path
|
|
BSTR strQuery = NULL;
|
|
if(strQuery = SysAllocString(pUI->m_pszQuery))
|
|
{
|
|
BSTR strNamespacePath = NULL;
|
|
if(strNamespacePath = SysAllocString(pUI->m_pszNamespacePath))
|
|
{
|
|
// Do the operation
|
|
ISWbemXMLDocumentSet *pOutput = NULL;
|
|
BSTR strQueryLanguage = NULL;
|
|
if(strQueryLanguage = SysAllocString(L"WQL"))
|
|
{
|
|
if(SUCCEEDED(hr = pControl->ExecQuery(strNamespacePath, strQuery, strQueryLanguage, NULL, &pOutput)))
|
|
{
|
|
hr = FilterOutputFromSet(pOutput, pUI );
|
|
pOutput->Release();
|
|
}
|
|
SysFreeString(strQueryLanguage);
|
|
}
|
|
}
|
|
else
|
|
hr = E_OUTOFMEMORY;
|
|
SysFreeString(strNamespacePath);
|
|
}
|
|
else
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
pControl->Release();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT DoEnumInstance(CXmlCompUI *pUI)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
IWmiXMLTransformer *pControl = NULL;
|
|
|
|
// Create the Backend Control
|
|
if(SUCCEEDED(hr = CreateControl(&pControl)))
|
|
{
|
|
// Set most of the operation independent flags
|
|
if(SUCCEEDED(hr = SetCommonControlProperties(pControl, pUI)))
|
|
{
|
|
// Set Object Path, Host Name and Namespace Path
|
|
BSTR strObjectPath = NULL;
|
|
if(strObjectPath = SysAllocString(pUI->m_pszObjectPath))
|
|
{
|
|
// Do the operation
|
|
ISWbemXMLDocumentSet *pOutput = NULL;
|
|
if(SUCCEEDED(hr = pControl->EnumInstances(strObjectPath,
|
|
(pUI->m_bDeep)? VARIANT_TRUE : VARIANT_FALSE, NULL,
|
|
&pOutput)))
|
|
{
|
|
hr = FilterOutputFromSet(pOutput, pUI );
|
|
pOutput->Release();
|
|
}
|
|
SysFreeString(strObjectPath);
|
|
}
|
|
else
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
pControl->Release();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT DoEnumClass(CXmlCompUI *pUI)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
IWmiXMLTransformer *pControl = NULL;
|
|
|
|
// Create the Backend Control
|
|
if(SUCCEEDED(hr = CreateControl(&pControl)))
|
|
{
|
|
// Set most of the operation independent flags
|
|
if(SUCCEEDED(hr = SetCommonControlProperties(pControl, pUI)))
|
|
{
|
|
// Set Object Path, Host Name and Namespace Path
|
|
BSTR strObjectPath = NULL;
|
|
if(strObjectPath = SysAllocString(pUI->m_pszObjectPath))
|
|
{
|
|
// Do the operation
|
|
ISWbemXMLDocumentSet *pOutput = NULL;
|
|
if(SUCCEEDED(hr = pControl->EnumClasses(strObjectPath,
|
|
(pUI->m_bDeep)? VARIANT_TRUE : VARIANT_FALSE,
|
|
NULL,
|
|
&pOutput)))
|
|
{
|
|
hr = FilterOutputFromSet(pOutput, pUI );
|
|
pOutput->Release();
|
|
}
|
|
}
|
|
else
|
|
hr = E_OUTOFMEMORY;
|
|
SysFreeString(strObjectPath);
|
|
}
|
|
pControl->Release();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT DoEnumInstNames(CXmlCompUI *pUI)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
IWmiXMLTransformer *pControl = NULL;
|
|
|
|
// Create the Backend Control
|
|
if(SUCCEEDED(hr = CreateControl(&pControl)))
|
|
{
|
|
// Set most of the operation independent flags
|
|
if(SUCCEEDED(hr = SetCommonControlProperties(pControl, pUI)))
|
|
{
|
|
// Set Object Path, Host Name and Namespace Path
|
|
BSTR strObjectPath = NULL;
|
|
if(strObjectPath = SysAllocString(pUI->m_pszObjectPath))
|
|
{
|
|
// Do the operation
|
|
ISWbemXMLDocumentSet *pOutput = NULL;
|
|
if(SUCCEEDED(hr = pControl->EnumInstanceNames(strObjectPath, NULL, &pOutput)))
|
|
{
|
|
hr = FilterOutputFromSet(pOutput, pUI );
|
|
pOutput->Release();
|
|
}
|
|
SysFreeString(strObjectPath);
|
|
}
|
|
else
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
pControl->Release();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT DoEnumClassNames(CXmlCompUI *pUI)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
IWmiXMLTransformer *pControl = NULL;
|
|
|
|
// Create the Backend Control
|
|
if(SUCCEEDED(hr = CreateControl(&pControl)))
|
|
{
|
|
// Set most of the operation independent flags
|
|
if(SUCCEEDED(hr = SetCommonControlProperties(pControl, pUI)))
|
|
{
|
|
// Set Object Path, Host Name and Namespace Path
|
|
BSTR strObjectPath = NULL;
|
|
if(strObjectPath = SysAllocString(pUI->m_pszObjectPath))
|
|
{
|
|
// Do the operation
|
|
ISWbemXMLDocumentSet *pOutput = NULL;
|
|
if(SUCCEEDED(hr = pControl->EnumClassNames(strObjectPath,
|
|
(pUI->m_bDeep)? VARIANT_TRUE : VARIANT_FALSE, NULL,
|
|
&pOutput)))
|
|
{
|
|
hr = FilterOutputFromSet(pOutput, pUI );
|
|
pOutput->Release();
|
|
}
|
|
SysFreeString(strObjectPath);
|
|
}
|
|
else
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
pControl->Release();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP MapCommonHeaders (FILE *fp, CXmlCompUI *pUI)
|
|
{
|
|
// WRITESIG
|
|
WriteOutputString(fp, pUI->m_bIsUTF8, L"<?xml version=\"1.0\" ?>");
|
|
if (pUI->m_pszDTDURL)
|
|
{
|
|
WriteOutputString(fp, pUI->m_bIsUTF8, L"<!DOCTYPE CIM SYSTEM \"");
|
|
WriteOutputString(fp, pUI->m_bIsUTF8, pUI->m_pszDTDURL);
|
|
WriteOutputString(fp, pUI->m_bIsUTF8, L"\">");
|
|
|
|
}
|
|
|
|
WriteOutputString(fp, pUI->m_bIsUTF8, L"<CIM CIMVERSION=\"2.0\" DTDVERSION=\"2.0\" >");
|
|
WriteOutputString(fp, pUI->m_bIsUTF8, L"<DECLARATION>");
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP MapCommonTrailers (FILE *fp, CXmlCompUI *pUI)
|
|
{
|
|
WriteOutputString(fp, pUI->m_bIsUTF8, L"</DECLARATION>");
|
|
WriteOutputString(fp, pUI->m_bIsUTF8, L"</CIM>");
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP MapDeclGroupHeaders (FILE *fp, CXmlCompUI *pUI )
|
|
{
|
|
switch(pUI->m_iDeclGroupType)
|
|
{
|
|
case wmiXMLDeclGroup:
|
|
WriteOutputString(fp, pUI->m_bIsUTF8, L"<DECLGROUP>");
|
|
break;
|
|
case wmiXMLDeclGroupWithName:
|
|
WriteOutputString(fp, pUI->m_bIsUTF8, L"<DECLGROUP.WITHNAME>");
|
|
break;
|
|
case wmiXMLDeclGroupWithPath:
|
|
WriteOutputString(fp, pUI->m_bIsUTF8, L"<DECLGROUP.WITHPATH>");
|
|
break;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP MapDeclGroupTrailers (FILE *fp, CXmlCompUI *pUI)
|
|
{
|
|
switch(pUI->m_iDeclGroupType)
|
|
{
|
|
case wmiXMLDeclGroup:
|
|
WriteOutputString(fp, pUI->m_bIsUTF8, L"</DECLGROUP>");
|
|
break;
|
|
case wmiXMLDeclGroupWithName:
|
|
WriteOutputString(fp, pUI->m_bIsUTF8, L"</DECLGROUP.WITHNAME>");
|
|
break;
|
|
case wmiXMLDeclGroupWithPath:
|
|
WriteOutputString(fp, pUI->m_bIsUTF8, L"</DECLGROUP.WITHNAME>");
|
|
break;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT FilterOutputFromSet(ISWbemXMLDocumentSet *pOutput, CXmlCompUI *pUI )
|
|
{
|
|
// Get the output file handle
|
|
FILE *fp = NULL;
|
|
if(pUI->m_pszOutputFileName)
|
|
fp = _wfopen(pUI->m_pszOutputFileName, L"w");
|
|
else
|
|
fp = stdout;
|
|
|
|
if(!fp)
|
|
{
|
|
CreateMessage(XML_COMP_ERR_UNABLE_TO_OPEN_OUTPUT);
|
|
return E_FAIL;
|
|
}
|
|
|
|
// Go thru each element in the set
|
|
HRESULT hr = S_OK;
|
|
|
|
if(SUCCEEDED(hr = MapCommonHeaders(fp, pUI)))
|
|
{
|
|
if(SUCCEEDED(hr = MapDeclGroupHeaders(fp, pUI)))
|
|
{
|
|
IXMLDOMDocument *pDoc = NULL;
|
|
bool bError = false;
|
|
while(!bError && SUCCEEDED(hr = pOutput->NextDocument(&pDoc)) && hr != S_FALSE)
|
|
{
|
|
if(SUCCEEDED(hr = WriteOneDeclGroupDocument(fp, pDoc, pUI)))
|
|
{
|
|
}
|
|
else
|
|
bError = true;
|
|
pDoc->Release();
|
|
pDoc = NULL;
|
|
}
|
|
if(!bError && SUCCEEDED(hr = MapDeclGroupTrailers(fp, pUI)))
|
|
{
|
|
hr = MapCommonTrailers(fp, pUI);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Close any file that we opened
|
|
if(fp != stdout)
|
|
fclose(fp);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT FilterOutputForSingleObject(IXMLDOMDocument *pOutput, CXmlCompUI *pUI )
|
|
{
|
|
// Get the output file handle
|
|
FILE *fp = NULL;
|
|
if(pUI->m_pszOutputFileName)
|
|
fp = _wfopen(pUI->m_pszOutputFileName, L"w");
|
|
else
|
|
fp = stdout;
|
|
|
|
if(!fp)
|
|
{
|
|
CreateMessage(XML_COMP_ERR_UNABLE_TO_OPEN_OUTPUT);
|
|
return E_FAIL;
|
|
}
|
|
|
|
// Map the object to XML
|
|
HRESULT hr = S_OK;
|
|
|
|
if(SUCCEEDED(hr = MapCommonHeaders(fp, pUI)))
|
|
{
|
|
if(SUCCEEDED(hr = MapDeclGroupHeaders(fp, pUI)))
|
|
{
|
|
// We get a document with a CLASS or INSTANCE at the top level
|
|
IXMLDOMElement *pTopElement = NULL;
|
|
if(SUCCEEDED(hr = pOutput->get_documentElement(&pTopElement)))
|
|
{
|
|
if(SUCCEEDED(hr = WriteOneDeclGroupNode(fp, pTopElement, pUI)))
|
|
{
|
|
if(SUCCEEDED(hr = MapDeclGroupTrailers(fp, pUI)))
|
|
{
|
|
hr = MapCommonTrailers(fp, pUI);
|
|
}
|
|
}
|
|
pTopElement->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Close any file that we opened
|
|
if(fp != stdout)
|
|
fclose(fp);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT WriteOneDeclGroupNode(FILE *fp, IXMLDOMNode *pTopElement, CXmlCompUI *pUI )
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
BSTR strTopName = NULL;
|
|
if(SUCCEEDED(hr = pTopElement->get_nodeName(&strTopName)))
|
|
{
|
|
switch(pUI->m_iDeclGroupType)
|
|
{
|
|
// In this case you have to extract a CLASS or an INSTANCE from
|
|
// 1. CLASS or INSTANCE for GetObject and ENumClass
|
|
// 2. VALUE.NAMEDINSTANCE for EnumInstance
|
|
// 3. VALUE.OBJECTWITHPATH for ExecQuery
|
|
case wmiXMLDeclGroup:
|
|
if(_wcsicmp(strTopName, L"CLASS") == 0 ||
|
|
_wcsicmp(strTopName, L"INSTANCE") == 0 )
|
|
{
|
|
WriteOutputString(fp, pUI->m_bIsUTF8, L"<VALUE.OBJECT>");
|
|
hr = WriteNode(fp, pTopElement, pUI);
|
|
WriteOutputString(fp, pUI->m_bIsUTF8, L"</VALUE.OBJECT>");
|
|
}
|
|
else if(_wcsicmp(strTopName, L"VALUE.NAMEDINSTANCE") == 0 )
|
|
{
|
|
IXMLDOMElement *pInstance = NULL;
|
|
if(SUCCEEDED(hr = GetFirstImmediateElement(pTopElement, &pInstance, L"INSTANCE")))
|
|
{
|
|
WriteOutputString(fp, pUI->m_bIsUTF8, L"<VALUE.OBJECT>");
|
|
hr = WriteNode(fp, pInstance, pUI);
|
|
WriteOutputString(fp, pUI->m_bIsUTF8, L"</VALUE.OBJECT>");
|
|
pInstance->Release();
|
|
}
|
|
}
|
|
else if(_wcsicmp(strTopName, L"VALUE.OBJECTWITHPATH") == 0 )
|
|
{
|
|
IXMLDOMElement *pObject = NULL;
|
|
if(SUCCEEDED(hr = GetFirstImmediateElement(pTopElement, &pObject, L"INSTANCE")))
|
|
{
|
|
WriteOutputString(fp, pUI->m_bIsUTF8, L"<VALUE.OBJECT>");
|
|
hr = WriteNode(fp, pObject, pUI);
|
|
WriteOutputString(fp, pUI->m_bIsUTF8, L"</VALUE.OBJECT>");
|
|
pObject->Release();
|
|
}
|
|
else if(SUCCEEDED(hr = GetFirstImmediateElement(pTopElement, &pObject, L"CLASS")))
|
|
{
|
|
WriteOutputString(fp, pUI->m_bIsUTF8, L"<VALUE.OBJECT>");
|
|
hr = WriteNode(fp, pObject, pUI);
|
|
WriteOutputString(fp, pUI->m_bIsUTF8, L"</VALUE.OBJECT>");
|
|
pObject->Release();
|
|
}
|
|
}
|
|
else
|
|
hr = E_FAIL;
|
|
break;
|
|
// In this case you have to create a VALUE.NAMEDOBJECT from
|
|
// 1. CLASS or INSTANCE for GetObject and ENumClass - For this we need the name of the class/instance
|
|
// 2. VALUE.NAMEDINSTANCE for EnumInstance - Pretty Straightforward
|
|
// 3. VALUE.OBJECTWITHPATH for ExecQuery - Pretty Straightforward
|
|
case wmiXMLDeclGroupWithName:
|
|
if(_wcsicmp(strTopName, L"CLASS") == 0 ||
|
|
_wcsicmp(strTopName, L"INSTANCE") == 0 )
|
|
{
|
|
hr = ConvertObjectToNamedObject(fp, pTopElement, pUI);
|
|
}
|
|
else if(_wcsicmp(strTopName, L"VALUE.NAMEDINSTANCE") == 0 )
|
|
{
|
|
hr = ConvertNamedInstanceToNamedObject(fp, pTopElement, pUI);
|
|
}
|
|
else if(_wcsicmp(strTopName, L"VALUE.OBJECTWITHPATH") == 0 )
|
|
{
|
|
hr = ConvertObjectWithPathToNamedObject(fp, pTopElement, pUI);
|
|
}
|
|
else
|
|
hr = E_FAIL;
|
|
break;
|
|
// In this case you have to create a VALUE.OBJECTWITHPATH from
|
|
// 1. CLASS or INSTANCE for GetObject and ENumClass - For this we need the full path of the class/instance
|
|
// 2. VALUE.NAMEDINSTANCE for EnumInstance - For this we need the host and namespace of the class/instance
|
|
// 3. VALUE.OBJECTWITHPATH for ExecQuery - Pretty Straightforward
|
|
case wmiXMLDeclGroupWithPath:
|
|
if(_wcsicmp(strTopName, L"CLASS") == 0 ||
|
|
_wcsicmp(strTopName, L"INSTANCE") == 0 )
|
|
{
|
|
hr = ConvertObjectToObjectWithPath(fp, pTopElement, pUI);
|
|
}
|
|
else if(_wcsicmp(strTopName, L"VALUE.NAMEDINSTANCE") == 0 )
|
|
{
|
|
// Get the CLASS or INSTANCE in it
|
|
IXMLDOMElement *pObject = NULL;
|
|
if(FAILED(hr = GetFirstImmediateElement(pTopElement, &pObject, L"INSTANCE")))
|
|
hr = GetFirstImmediateElement(pTopElement, &pObject, L"CLASS");
|
|
// Convert the CLASS or INSTANCE to VALUE.OBJECTWITHPATH
|
|
if(SUCCEEDED(hr))
|
|
hr = ConvertObjectToObjectWithPath(fp, pTopElement, pUI);
|
|
}
|
|
else if(_wcsicmp(strTopName, L"VALUE.OBJECTWITHPATH") == 0 )
|
|
{
|
|
hr = WriteNode(fp, pTopElement, pUI);
|
|
}
|
|
else
|
|
hr = E_FAIL;
|
|
break;
|
|
}
|
|
|
|
SysFreeString(strTopName);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT WriteOneDeclGroupDocument(FILE *fp, IXMLDOMDocument *pDocument, CXmlCompUI *pUI )
|
|
{
|
|
// Check the top level document - it can be CLASS, INSTANCE, VALUE.NAMEDINSTANCE or VALUE.OBJECTWITHPATH
|
|
// Or it can be CLASSNAME or INSTANCENAME for an EnumClassName or EnumInstanceName operation
|
|
IXMLDOMElement *pTopElement = NULL;
|
|
HRESULT hr = E_FAIL;
|
|
if(SUCCEEDED(hr = pDocument->get_documentElement(&pTopElement)))
|
|
{
|
|
hr = WriteOneDeclGroupNode(fp, pTopElement, pUI);
|
|
pTopElement->Release();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT DoCompilation(IStream *pInputFile, CXmlCompUI *pUI)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
IWmiXMLTransformer *pControl = NULL;
|
|
|
|
// Create the Backend Control
|
|
if(SUCCEEDED(hr = CreateControl(&pControl)))
|
|
{
|
|
// Set most of the operation independent flags
|
|
if(SUCCEEDED(hr = SetCommonControlProperties(pControl, pUI)))
|
|
{
|
|
// Wrap the inptu stream in a variant
|
|
VARIANT vInput;
|
|
if(SUCCEEDED(hr = SaveStreamToUnkVariant(pInputFile, &vInput)))
|
|
{
|
|
// Set Host Name and Namespace Path
|
|
BSTR strNamespacePath = NULL;
|
|
if(strNamespacePath = SysAllocString(pUI->m_pszNamespacePath))
|
|
{
|
|
VARIANT_BOOL bStatus = VARIANT_FALSE;
|
|
BSTR strErrors = NULL;
|
|
// Do the operation
|
|
if(SUCCEEDED(hr = pControl->Compile(&vInput, strNamespacePath,
|
|
pUI->m_dwClassFlags,
|
|
pUI->m_dwInstanceFlags,
|
|
(pUI->m_iCommand == XML_COMP_WELL_FORM_CHECK)? WmiXMLCompilationWellFormCheck : ((pUI->m_iCommand == XML_COMP_VALIDITY_CHECK)? WmiXMLCompilationValidityCheck : WmiXMLCompilationFullCompileAndLoad),
|
|
NULL,
|
|
&bStatus)))
|
|
{
|
|
if(bStatus == VARIANT_FALSE)
|
|
{
|
|
hr = E_FAIL;
|
|
if(SUCCEEDED(pControl->get_CompilationErrors(&strErrors)))
|
|
{
|
|
if(strErrors)
|
|
fwprintf(stderr, strErrors);
|
|
SysFreeString(strErrors);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
hr = E_OUTOFMEMORY;
|
|
SysFreeString(strNamespacePath);
|
|
VariantClear(&vInput);
|
|
}
|
|
}
|
|
pControl->Release();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT SaveStreamToBstrVariant (IStream *pStream, VARIANT *pVariant)
|
|
{
|
|
HRESULT result = E_FAIL;
|
|
|
|
LARGE_INTEGER offset;
|
|
offset.LowPart = offset.HighPart = 0;
|
|
// Seek to the beginning of the stream
|
|
if(SUCCEEDED(result = pStream->Seek (offset, STREAM_SEEK_SET, NULL)))
|
|
{
|
|
// Get the size of the stream
|
|
STATSTG statstg;
|
|
if (SUCCEEDED(result = pStream->Stat(&statstg, STATFLAG_NONAME)))
|
|
{
|
|
ULONG cbSize = (statstg.cbSize).LowPart;
|
|
CHAR *pText = NULL;
|
|
|
|
if(cbSize && (pText = new CHAR [cbSize]))
|
|
{
|
|
// Read the Ascii data
|
|
ULONG cbActualRead = 0;
|
|
if (SUCCEEDED(result = pStream->Read(pText, cbSize, &cbActualRead)))
|
|
{
|
|
// Convert to Unicode
|
|
//=======================
|
|
|
|
// Calculate size of the resulting Wide char string
|
|
DWORD dwSizeOfBstr = MultiByteToWideChar(
|
|
CP_ACP, /* codepage */
|
|
0, /* character-type options */
|
|
pText, /* address of string to map */
|
|
cbActualRead, /* number of characters in string */
|
|
NULL, /* address of wide-character buffer */
|
|
0); /* size of wide-character buffer */
|
|
|
|
|
|
if(dwSizeOfBstr > 0 )
|
|
{
|
|
// ALllocate the wide char string
|
|
LPWSTR theWcharString = NULL;
|
|
if(theWcharString = new WCHAR [dwSizeOfBstr])
|
|
{
|
|
//Convert the Ansi string to Bstr
|
|
dwSizeOfBstr = MultiByteToWideChar(
|
|
CP_ACP, /* codepage */
|
|
0, /* character-type options */
|
|
pText, /* address of string to map */
|
|
cbActualRead, /* number of characters in string */
|
|
theWcharString, /* address of wide-character buffer */
|
|
dwSizeOfBstr); /* size of wide-character buffer */
|
|
|
|
BSTR strVal = NULL;
|
|
if(strVal = SysAllocStringLen(theWcharString, dwSizeOfBstr))
|
|
{
|
|
VariantInit(pVariant);
|
|
pVariant->vt = VT_BSTR;
|
|
pVariant->bstrVal = strVal;
|
|
result = S_OK;
|
|
}
|
|
else
|
|
result = E_OUTOFMEMORY;
|
|
delete [] theWcharString;
|
|
}
|
|
else
|
|
result = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
delete [] pText;
|
|
}
|
|
else
|
|
result = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
HRESULT GetFirstImmediateElement(IXMLDOMNode *pParent, IXMLDOMElement **ppChildElement, LPCWSTR pszName)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
// Now cycle thru the children
|
|
IXMLDOMNodeList *pNodeList = NULL;
|
|
BOOL bFound = FALSE;
|
|
if (SUCCEEDED(hr = pParent->get_childNodes (&pNodeList)))
|
|
{
|
|
IXMLDOMNode *pNode = NULL;
|
|
while (!bFound && SUCCEEDED(pNodeList->nextNode (&pNode)) && pNode)
|
|
{
|
|
// Get the name of the child
|
|
BSTR strNodeName = NULL;
|
|
if (SUCCEEDED(hr = pNode->get_nodeName (&strNodeName)))
|
|
{
|
|
// We're interested only in PROPERTIES at this point
|
|
if(_wcsicmp(strNodeName, pszName) == 0)
|
|
{
|
|
*ppChildElement = NULL;
|
|
hr = pNode->QueryInterface(IID_IXMLDOMElement, (LPVOID *)ppChildElement);
|
|
bFound = TRUE;
|
|
}
|
|
SysFreeString(strNodeName);
|
|
}
|
|
pNode->Release();
|
|
pNode = NULL;
|
|
}
|
|
pNodeList->Release();
|
|
}
|
|
if(bFound)
|
|
return hr;
|
|
return E_FAIL;
|
|
}
|
|
|
|
HRESULT WriteNode(FILE *fp, IXMLDOMNode *pOutputNode, CXmlCompUI *pUI)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
if(pOutputNode)
|
|
{
|
|
BSTR strXML = NULL;
|
|
if(SUCCEEDED(hr = pOutputNode->get_xml(&strXML)))
|
|
{
|
|
WriteOutputString(fp, pUI->m_bIsUTF8, strXML, SysStringLen(strXML));
|
|
SysFreeString(strXML);
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT ConvertNamedInstanceToNamedObject(FILE *fp, IXMLDOMNode *pTopElement, CXmlCompUI *pUI)
|
|
{
|
|
// Write the beginning tag
|
|
WriteOutputString(fp, pUI->m_bIsUTF8, L"<VALUE.NAMEDOBJECT>");
|
|
|
|
// Write the INSTANCENAME tag and its contents
|
|
IXMLDOMElement *pInstanceName = NULL;
|
|
if(SUCCEEDED(GetFirstImmediateElement(pTopElement, &pInstanceName, L"INSTANCENAME")))
|
|
{
|
|
WriteNode(fp, pInstanceName, pUI);
|
|
pInstanceName->Release();
|
|
}
|
|
// Write the INSTANCE tag and its contents
|
|
IXMLDOMElement *pInstance = NULL;
|
|
if(SUCCEEDED(GetFirstImmediateElement(pTopElement, &pInstance, L"INSTANCE")))
|
|
{
|
|
WriteNode(fp, pInstance, pUI);
|
|
pInstance->Release();
|
|
}
|
|
|
|
// Write the terminating tag
|
|
WriteOutputString(fp, pUI->m_bIsUTF8, L"</VALUE.NAMEDOBJECT>");
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT ConvertObjectWithPathToNamedObject(FILE *fp, IXMLDOMNode *pTopElement, CXmlCompUI *pUI)
|
|
{
|
|
// Write the beginning tag
|
|
WriteOutputString(fp, pUI->m_bIsUTF8, L"<VALUE.NAMEDOBJECT>");
|
|
|
|
// This could be a class or an instance
|
|
IXMLDOMElement *pClass = NULL;
|
|
IXMLDOMElement *pInstancePath = NULL;
|
|
|
|
// Get the INSTANCEPATH tag
|
|
if(SUCCEEDED(GetFirstImmediateElement(pTopElement, &pInstancePath, L"INSTANCEPATH")))
|
|
{
|
|
// Get the INSTANCENAME below the INSTANCEPATH
|
|
IXMLDOMElement *pInstanceName = NULL;
|
|
if(SUCCEEDED(GetFirstImmediateElement(pInstancePath, &pInstanceName, L"INSTANCENAME")))
|
|
{
|
|
WriteNode(fp, pInstanceName, pUI);
|
|
pInstanceName->Release();
|
|
}
|
|
|
|
// Write the INSTANCE tag and its contents
|
|
IXMLDOMElement *pInstance = NULL;
|
|
if(SUCCEEDED(GetFirstImmediateElement(pTopElement, &pInstance, L"INSTANCE")))
|
|
{
|
|
WriteNode(fp, pInstance, pUI);
|
|
pInstanceName->Release();
|
|
}
|
|
pInstancePath->Release();
|
|
}
|
|
// Get the CLASS tag
|
|
else if(SUCCEEDED(GetFirstImmediateElement(pTopElement, &pClass, L"CLASS")))
|
|
{
|
|
WriteNode(fp, pClass, pUI);
|
|
pClass->Release();
|
|
}
|
|
|
|
// Write the terminating tag
|
|
WriteOutputString(fp, pUI->m_bIsUTF8, L"</VALUE.NAMEDOBJECT>");
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT ConvertObjectToNamedObject(FILE *fp, IXMLDOMNode *pTopElement, CXmlCompUI *pUI )
|
|
{
|
|
// From the UI, we get the path to the object
|
|
// From the path, we get the name of the object (INSTANCENAME for instance, nothing for a CLASS)
|
|
// From that and the CLASS or INSTANCE, we get a VALUE.NAMEDOBJECT
|
|
BSTR strName = NULL;
|
|
HRESULT hr = E_FAIL;
|
|
if(SUCCEEDED(hr = pTopElement->get_nodeName(&strName)))
|
|
{
|
|
// Nothing much to be done for a class
|
|
if(_wcsicmp(strName, L"CLASS") == 0)
|
|
{
|
|
// Write the beginning tag
|
|
WriteOutputString(fp, pUI->m_bIsUTF8, L"<VALUE.NAMEDOBJECT>");
|
|
// Write the Class
|
|
hr = WriteNode(fp, pTopElement, pUI);
|
|
// Write the terminating tag
|
|
WriteOutputString(fp, pUI->m_bIsUTF8, L"</VALUE.NAMEDOBJECT>");
|
|
}
|
|
// For the instance, we need to use the UI to get the instance name
|
|
else if(_wcsicmp(strName, L"INSTANCE") == 0)
|
|
{
|
|
// Create a stream
|
|
IStream *pStream = NULL;
|
|
if (SUCCEEDED(hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream)))
|
|
{
|
|
// Create the convertor
|
|
IWbemXMLConvertor *pConvertor = NULL;
|
|
if(SUCCEEDED(hr = CreateXMLTranslator(&pConvertor)))
|
|
{
|
|
// Get the XML representation in a Stream
|
|
BSTR strInstanceName = NULL;
|
|
if(strInstanceName = SysAllocString(pUI->m_pszObjectPath))
|
|
{
|
|
if(SUCCEEDED(hr = pConvertor->MapInstanceNameToXML(strInstanceName, NULL, pStream)))
|
|
{
|
|
// Convert the stream to a DOM Element
|
|
IXMLDOMElement *pInstanceName = NULL;
|
|
if(SUCCEEDED(hr = ConvertStreamToDOM(pStream, &pInstanceName)))
|
|
{
|
|
// Write the beginning tag
|
|
WriteOutputString(fp, pUI->m_bIsUTF8, L"<VALUE.NAMEDOBJECT>");
|
|
// Write the InstanceName
|
|
WriteNode(fp, pInstanceName, pUI);
|
|
// Write the Instance
|
|
WriteNode(fp, pTopElement, pUI);
|
|
// Write the terminating tag
|
|
WriteOutputString(fp, pUI->m_bIsUTF8, L"</VALUE.NAMEDOBJECT>");
|
|
pInstanceName->Release();
|
|
}
|
|
|
|
}
|
|
SysFreeString(strInstanceName);
|
|
}
|
|
pConvertor->Release();
|
|
}
|
|
pStream->Release();
|
|
}
|
|
}
|
|
SysFreeString(strName);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT ConvertObjectToObjectWithPath(FILE *fp, IXMLDOMNode *pTopElement, CXmlCompUI *pUI )
|
|
{
|
|
// From the UI, we get the path to the object
|
|
// From the path, we get an INSTANCEPATH or CLASSPATH
|
|
// From that and the CLASS or INSTANCE, we get a VALUE.OBJECTWITHPATH
|
|
BSTR strName = NULL;
|
|
HRESULT hr = E_FAIL;
|
|
if(SUCCEEDED(hr = pTopElement->get_nodeName(&strName)))
|
|
{
|
|
// Create a stream
|
|
IStream *pStream = NULL;
|
|
if (SUCCEEDED(hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream)))
|
|
{
|
|
// Create the convertor
|
|
IWbemXMLConvertor *pConvertor = NULL;
|
|
if(SUCCEEDED(hr = CreateXMLTranslator(&pConvertor)))
|
|
{
|
|
// Get the XML representation in a Stream
|
|
BSTR strObjectPath = NULL;
|
|
if(strObjectPath = SysAllocString(pUI->m_pszObjectPath))
|
|
{
|
|
// Get the Object Path
|
|
if(_wcsicmp(strName, L"INSTANCE") == 0)
|
|
hr = pConvertor->MapInstancePathToXML(strObjectPath, NULL, pStream);
|
|
else if(_wcsicmp(strName, L"CLASS") == 0)
|
|
hr = pConvertor->MapClassPathToXML(strObjectPath, NULL, pStream);
|
|
else
|
|
hr = E_FAIL;
|
|
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
// Convert the stream to a DOM Element
|
|
IXMLDOMElement *pObjectPath = NULL;
|
|
if(SUCCEEDED(hr = ConvertStreamToDOM(pStream, &pObjectPath)))
|
|
{
|
|
// Write the beginning tag
|
|
WriteOutputString(fp, pUI->m_bIsUTF8, L"<VALUE.OBJECTWITHPATH>");
|
|
// Write the INSTANCEPATH/CLASSPATH
|
|
WriteNode(fp, pObjectPath, pUI);
|
|
// Write the INSTANCE/CLASS
|
|
WriteNode(fp, pTopElement, pUI);
|
|
// Write the terminating tag
|
|
WriteOutputString(fp, pUI->m_bIsUTF8, L"</VALUE.OBJECTWITHPATH>");
|
|
pObjectPath->Release();
|
|
}
|
|
}
|
|
SysFreeString(strObjectPath);
|
|
}
|
|
pConvertor->Release();
|
|
}
|
|
pStream->Release();
|
|
}
|
|
SysFreeString(strName);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
// RAJESHR - Remove this to read the GUID frm the registry on startup
|
|
DEFINE_GUID(CLSID_WbemXMLConvertor,
|
|
0x610037ec, 0xce06, 0x11d3, 0x93, 0xfc, 0x0, 0x80, 0x5f, 0x85, 0x37, 0x71);
|
|
HRESULT CreateXMLTranslator(IWbemXMLConvertor **pConvertor)
|
|
{
|
|
|
|
HRESULT result = E_FAIL;
|
|
|
|
// Create the XMLAdaptor object
|
|
//******************************************************
|
|
*pConvertor = NULL;
|
|
if(SUCCEEDED(result = CoCreateInstance(CLSID_WbemXMLConvertor,
|
|
0,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IWbemXMLConvertor, (LPVOID *) pConvertor)))
|
|
{
|
|
}
|
|
return result;
|
|
}
|
|
|
|
HRESULT ConvertStreamToDOM(IStream *pStream, IXMLDOMElement **pInstanceName)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
VARIANT vInput;
|
|
VariantInit(&vInput);
|
|
vInput.vt = VT_UNKNOWN;
|
|
vInput.punkVal = pStream;
|
|
|
|
// Seek to the beginning of the stream
|
|
//========================================
|
|
LARGE_INTEGER offset;
|
|
offset.LowPart = offset.HighPart = 0;
|
|
if(SUCCEEDED(hr = pStream->Seek (offset, STREAM_SEEK_SET, NULL)))
|
|
{
|
|
// Create an XML document for the stream
|
|
//==============================
|
|
IXMLDOMDocument *pDocument = NULL;
|
|
if(SUCCEEDED(hr = CoCreateInstance(CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_IXMLDOMDocument, (LPVOID *)&pDocument)))
|
|
{
|
|
// Load the Variant into the DOC
|
|
VARIANT_BOOL bResult = VARIANT_TRUE;
|
|
if(SUCCEEDED(hr = pDocument->put_async(VARIANT_FALSE)) &&
|
|
SUCCEEDED(hr = pDocument->put_validateOnParse(VARIANT_FALSE)) &&
|
|
SUCCEEDED(hr = pDocument->put_resolveExternals(VARIANT_FALSE)) )
|
|
{
|
|
if(SUCCEEDED(hr = pDocument->load(vInput, &bResult)))
|
|
{
|
|
if(bResult == VARIANT_TRUE)
|
|
{
|
|
hr = pDocument->get_documentElement(pInstanceName);
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
|
|
// This code is for debugging only
|
|
IXMLDOMParseError *pError = NULL;
|
|
if(SUCCEEDED(pDocument->get_parseError(&pError)))
|
|
{
|
|
LONG errorCode = 0;
|
|
pError->get_errorCode(&errorCode);
|
|
LONG line=0, linepos=0;
|
|
BSTR reason=NULL, srcText = NULL;
|
|
if(SUCCEEDED(pError->get_line(&line)) &&
|
|
SUCCEEDED(pError->get_linepos(&linepos)) &&
|
|
SUCCEEDED(pError->get_reason(&reason)) &&
|
|
SUCCEEDED(pError->get_srcText(&srcText)))
|
|
{
|
|
}
|
|
pError->Release();
|
|
if(reason)
|
|
SysFreeString(reason);
|
|
if(srcText)
|
|
SysFreeString(srcText);
|
|
|
|
pError->Release();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
pDocument->Release();
|
|
}
|
|
// No need to clear the variant since we didnt AddRef() the pStream
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT SaveStreamToUnkVariant (IStream *pStream, VARIANT *pVariant)
|
|
{
|
|
VariantInit(pVariant);
|
|
pVariant->vt = VT_UNKNOWN;
|
|
pVariant->punkVal = pStream;
|
|
pStream->AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
// Converts LPWSTR to its UTF-8 encoding
|
|
// Returns 0 if it fails
|
|
//
|
|
static DWORD ConvertWideStringToUTF8(LPCWSTR theWcharString,
|
|
ULONG lNumberOfWideChars,
|
|
LPSTR * lppszRetValue)
|
|
{
|
|
// Find the length of the Ansi string required
|
|
DWORD dwBytesToWrite = WideCharToMultiByte( CP_UTF8, // UTF-8 code page
|
|
0, // performance and mapping flags
|
|
theWcharString, // address of wide-character string
|
|
lNumberOfWideChars, // number of characters in string
|
|
NULL, // address of buffer for new string
|
|
0, // size of buffer
|
|
NULL, // address of default for unmappable
|
|
// characters
|
|
NULL); // address of flag set when default char. used
|
|
|
|
if(dwBytesToWrite == 0 )
|
|
return dwBytesToWrite;
|
|
|
|
// Allocate the required length for the Ansi string
|
|
*lppszRetValue = NULL;
|
|
if(!(*lppszRetValue = new char[dwBytesToWrite]))
|
|
return 0;
|
|
|
|
// Convert BSTR to ANSI
|
|
dwBytesToWrite = WideCharToMultiByte( CP_UTF8, // code page
|
|
0, // performance and mapping flags
|
|
theWcharString, // address of wide-character string
|
|
lNumberOfWideChars, // number of characters in string
|
|
*lppszRetValue, // address of buffer for new string
|
|
dwBytesToWrite, // size of buffer
|
|
NULL, // address of default for unmappable
|
|
// characters
|
|
NULL // address of flag set when default
|
|
// char. used
|
|
);
|
|
|
|
return dwBytesToWrite;
|
|
}
|
|
|
|
void WriteOutputString(FILE *fp, BOOL bIsUTF8, LPCWSTR pszData, DWORD dwLen)
|
|
{
|
|
// If we're not being asked to write UTF-8, then no conversion needs to be done
|
|
// Otherwise, we first need to convert the string to UTF8 and then write it
|
|
|
|
if(bIsUTF8)
|
|
{
|
|
// Convert the unicode string to UTF8
|
|
DWORD dwBytesToWrite = 0;
|
|
LPSTR pszUTF8 = NULL;
|
|
if(dwBytesToWrite = ConvertWideStringToUTF8(pszData, (dwLen)? dwLen : wcslen(pszData), &pszUTF8))
|
|
{
|
|
// Write the binary UTF8 bytes
|
|
fwrite((LPVOID)pszUTF8, sizeof(char), dwBytesToWrite, fp);
|
|
delete [] pszUTF8;
|
|
}
|
|
}
|
|
else
|
|
// Directly write a Unicode string
|
|
fwrite((LPVOID)pszData, sizeof(WCHAR), (dwLen)? dwLen : wcslen(pszData), fp);
|
|
|
|
}
|