Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2200 lines
48 KiB

//---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 1997
//
// File: common.cxx
//
// Contents: Microsoft ADs IIS Common routines
//
// History: 28-Feb-97 SophiaC Created.
//
//----------------------------------------------------------------------------
#include "iis.hxx"
extern SERVER_CACHE * g_pServerCache;
extern WIN32_CRITSEC * g_pGlobalLock;
#pragma hdrstop
FILTERS Filters[] = {
{L"user", IIS_USER_ID},
{L"group", IIS_GROUP_ID},
{L"queue", IIS_PRINTER_ID},
{L"domain", IIS_DOMAIN_ID},
{L"computer", IIS_COMPUTER_ID},
{L"service", IIS_SERVICE_ID},
{L"fileservice", IIS_FILESERVICE_ID},
{L"fileshare", IIS_FILESHARE_ID},
{L"class", IIS_CLASS_ID},
{L"functionalset", IIS_FUNCTIONALSET_ID},
{L"syntax", IIS_SYNTAX_ID},
{L"property", IIS_PROPERTY_ID},
{L"tree", IIS_TREE_ID},
{L"Organizational Unit", IIS_OU_ID},
{L"Organization", IIS_O_ID},
{L"Locality", IIS_LOCALITY_ID}
};
#define MAX_FILTERS (sizeof(Filters)/sizeof(FILTERS))
#define DEFAULT_TIMEOUT_VALUE 30000
PFILTERS gpFilters = Filters;
DWORD gdwMaxFilters = MAX_FILTERS;
extern WCHAR * szProviderName;
//+------------------------------------------------------------------------
//
// Class: Common
//
// Purpose: Contains Winnt routines and properties that are common to
// all Winnt objects. Winnt objects get the routines and
// properties through C++ inheritance.
//
//-------------------------------------------------------------------------
HRESULT
BuildADsPath(
BSTR Parent,
BSTR Name,
BSTR *pADsPath
)
{
LPWSTR lpADsPath = NULL;
WCHAR ProviderName[MAX_PATH];
HRESULT hr = S_OK;
DWORD dwLen = 0;
//
// We will assert if bad parameters are passed to us.
// This is because this should never be the case. This
// is an internal call
//
ADsAssert(Parent && Name);
ADsAssert(pADsPath);
//
// Special case the Namespace object; if
// the parent is L"ADs:", then Name = ADsPath
//
if (!_wcsicmp(Parent, L"ADs:")) {
RRETURN(ADsAllocString( Name, pADsPath));
}
//
// Allocate the right side buffer
// 2 for // + a buffer of MAX_PATH
//
dwLen = (DWORD)(wcslen(Parent) + wcslen(Name)) + 2 + MAX_PATH;
lpADsPath = (LPWSTR)AllocADsMem(dwLen*sizeof(WCHAR));
if (!lpADsPath) {
RRETURN(E_OUTOFMEMORY);
}
//
// The rest of the cases we expect valid data,
// Path, Parent and Name are read-only, the end-user
// cannot modify this data
//
//
// For the first object, the domain object we do not add
// the first backslash; so we examine that the parent is
// L"WinNT:" and skip the slash otherwise we start with
// the slash
//
wsprintf(ProviderName, L"%s:", szProviderName);
wcscpy(lpADsPath, Parent);
if (_wcsicmp(lpADsPath, ProviderName)) {
wcscat(lpADsPath, L"/");
}else {
wcscat(lpADsPath, L"//");
}
wcscat(lpADsPath, Name);
hr = ADsAllocString( lpADsPath, pADsPath);
if (lpADsPath) {
FreeADsMem(lpADsPath);
}
RRETURN(hr);
}
HRESULT
BuildSchemaPath(
BSTR bstrADsPath,
BSTR bstrClass,
BSTR *pSchemaPath
)
{
WCHAR ADsSchema[MAX_PATH];
OBJECTINFO ObjectInfo;
POBJECTINFO pObjectInfo = &ObjectInfo;
CLexer Lexer(bstrADsPath);
HRESULT hr = S_OK;
memset(pObjectInfo, 0, sizeof(OBJECTINFO));
wcscpy(ADsSchema, L"");
memset(pObjectInfo, 0, sizeof(OBJECTINFO));
if (bstrClass && *bstrClass) {
hr = ADsObject(&Lexer, pObjectInfo);
BAIL_ON_FAILURE(hr);
if (pObjectInfo->TreeName) {
wsprintf(ADsSchema,L"%s://",pObjectInfo->ProviderName);
wcscat(ADsSchema, pObjectInfo->TreeName);
wcscat(ADsSchema,L"/schema/");
wcscat(ADsSchema, bstrClass);
}
}
hr = ADsAllocString( ADsSchema, pSchemaPath);
error:
if (pObjectInfo) {
FreeObjectInfo( pObjectInfo );
}
RRETURN(hr);
}
HRESULT
BuildADsGuid(
REFCLSID clsid,
BSTR *pADsClass
)
{
WCHAR ADsClass[MAX_PATH];
StringFromGUID2(clsid, ADsClass, 256);
RRETURN(ADsAllocString( ADsClass, pADsClass));
}
HRESULT
ValidateOutParameter(
BSTR * retval
)
{
if (!retval) {
RRETURN(E_ADS_BAD_PARAMETER);
}
RRETURN(S_OK);
}
HRESULT
OpenAdminBaseKey(
IN CCredentials& Credentials,
IN LPWSTR pszServerName,
IN LPWSTR pszPathName,
IN DWORD dwAccessType,
IN OUT IMSAdminBase **ppAdminBase,
OUT METADATA_HANDLE *phHandle
)
{
HRESULT hr;
IMSAdminBase *pAdminBase = *ppAdminBase;
METADATA_HANDLE RootHandle = NULL;
DWORD dwThreadId;
hr = pAdminBase->OpenKey(
METADATA_MASTER_ROOT_HANDLE,
pszPathName,
dwAccessType,
DEFAULT_TIMEOUT_VALUE,
&RootHandle
);
if (FAILED(hr)) {
if ((HRESULT_CODE(hr) == RPC_S_SERVER_UNAVAILABLE) ||
((HRESULT_CODE(hr) >= RPC_S_NO_CALL_ACTIVE) &&
(HRESULT_CODE(hr) <= RPC_S_CALL_FAILED_DNE)) ||
hr == RPC_E_DISCONNECTED) {
SERVER_CACHE_ITEM * item = NULL;
IMSAdminBase * pOldAdminBase = pAdminBase;
//
// RPC error, try to recover connection
//
hr = InitAdminBase(Credentials, pszServerName, &pAdminBase);
BAIL_ON_FAILURE(hr);
*ppAdminBase = pAdminBase;
hr = pAdminBase->OpenKey(
METADATA_MASTER_ROOT_HANDLE,
pszPathName,
dwAccessType,
DEFAULT_TIMEOUT_VALUE,
&RootHandle
);
//
// update cache item
//
dwThreadId = GetCurrentThreadId();
item = g_pServerCache->Find(pszServerName, dwThreadId);
ASSERT(item != NULL);
if (item != NULL)
{
UninitAdminBase(pOldAdminBase);
item->UpdateAdminBase(pAdminBase, dwThreadId);
}
}
}
error :
if (FAILED(hr)) {
if (pAdminBase && RootHandle) {
pAdminBase->CloseKey(RootHandle);
}
}
else {
*phHandle = RootHandle;
}
RRETURN(hr);
}
VOID
CloseAdminBaseKey(
IN IMSAdminBase *pAdminBase,
IN METADATA_HANDLE hHandle
)
{
HRESULT hr;
if (pAdminBase) {
hr = pAdminBase->CloseKey(hHandle);
}
return;
}
HRESULT
MetaBaseGetAllData(
IN IMSAdminBase *pAdminBase,
IN METADATA_HANDLE hObjHandle,
IN LPWSTR pszIISPathName,
IN DWORD dwMDAttributes,
IN DWORD dwMDUserType,
IN DWORD dwMDDataType,
OUT PDWORD pdwMDNumDataEntries,
OUT PDWORD pdwMDDataSetNumber,
OUT LPBYTE * ppBuffer
)
{
LPBYTE pBuffer = NULL;
HRESULT hr = S_OK;
DWORD dwBufferSize = 0;
DWORD dwReqdBufferSize = 0;
hr = pAdminBase->GetAllData(
hObjHandle,
pszIISPathName,
dwMDAttributes,
dwMDUserType,
dwMDDataType,
pdwMDNumDataEntries,
pdwMDDataSetNumber,
dwBufferSize,
(LPBYTE)"",
&dwReqdBufferSize
);
pBuffer = (LPBYTE) AllocADsMem(dwReqdBufferSize);
if (!pBuffer) {
hr = HRESULT_FROM_WIN32(GetLastError());
BAIL_ON_FAILURE(hr);
}
dwBufferSize = dwReqdBufferSize;
hr = pAdminBase->GetAllData(
hObjHandle,
pszIISPathName,
dwMDAttributes,
dwMDUserType,
dwMDDataType,
pdwMDNumDataEntries,
pdwMDDataSetNumber,
dwBufferSize,
pBuffer,
&dwReqdBufferSize
);
BAIL_ON_FAILURE(hr);
*ppBuffer = pBuffer;
RRETURN(hr);
error:
if (pBuffer) {
FreeADsMem(pBuffer);
}
RRETURN(hr);
}
HRESULT
MetaBaseSetAllData(
IN IMSAdminBase *pAdminBase,
IN METADATA_HANDLE hObjHandle,
IN LPWSTR pszIISPathName,
IN PMETADATA_RECORD pMetaDataArray,
IN DWORD dwNumEntries
)
{
HRESULT hr = S_OK;
PMETADATA_RECORD pTemp = NULL;
METADATA_RECORD mdrMDData;
DWORD i;
//
// Set each METADATA record one at a time
//
for (i = 0; i < dwNumEntries; i++) {
pTemp = pMetaDataArray + i;
mdrMDData.dwMDIdentifier = pTemp->dwMDIdentifier;
mdrMDData.dwMDAttributes = pTemp->dwMDAttributes;
mdrMDData.dwMDUserType = pTemp->dwMDUserType;
mdrMDData.dwMDDataType = pTemp->dwMDDataType;
mdrMDData.dwMDDataLen = pTemp->dwMDDataLen;
mdrMDData.dwMDDataTag = pTemp->dwMDDataTag;
mdrMDData.pbMDData = pTemp->pbMDData;
hr = pAdminBase->SetData(
hObjHandle,
pszIISPathName,
&mdrMDData
);
BAIL_ON_FAILURE(hr);
}
error:
RRETURN(hr);
}
HRESULT
MetaBaseDeleteObject(
IN IMSAdminBase * pAdminBase,
IN METADATA_HANDLE hObjHandle,
IN LPWSTR pszIISPathName
)
{
HRESULT hr = S_OK;
hr = pAdminBase->DeleteKey(
hObjHandle,
pszIISPathName
);
RRETURN(hr);
}
HRESULT
MetaBaseCreateObject(
IN IMSAdminBase * pAdminBase,
IN METADATA_HANDLE hObjHandle,
IN LPWSTR pszIISPathName
)
{
HRESULT hr = S_OK;
hr = pAdminBase->AddKey(
hObjHandle,
pszIISPathName
);
RRETURN(hr);
}
HRESULT
MetaBaseCopyObject(
IN IMSAdminBase * pAdminBase,
IN METADATA_HANDLE hSrcObjHandle,
IN LPWSTR pszIISSrcPathName,
IN METADATA_HANDLE hDestObjHandle,
IN LPWSTR pszIISDestPathName
)
{
HRESULT hr = S_OK;
hr = pAdminBase->CopyKey(
hSrcObjHandle,
pszIISSrcPathName,
hDestObjHandle,
pszIISDestPathName,
TRUE,
TRUE
);
RRETURN(hr);
}
HRESULT
MetaBaseMoveObject(
IN IMSAdminBase * pAdminBase,
IN METADATA_HANDLE hSrcObjHandle,
IN LPWSTR pszIISSrcPathName,
IN METADATA_HANDLE hDestObjHandle,
IN LPWSTR pszIISDestPathName
)
{
HRESULT hr = S_OK;
hr = pAdminBase->CopyKey(
hSrcObjHandle,
pszIISSrcPathName,
hDestObjHandle,
pszIISDestPathName,
FALSE,
FALSE
);
RRETURN(hr);
}
HRESULT
MetaBaseGetAdminACL(
IN IMSAdminBase * pAdminBase,
IN METADATA_HANDLE hObjHandle,
IN LPWSTR pszIISPathName,
OUT LPBYTE *ppBuffer
)
{
HRESULT hr = S_OK;
DWORD dwBufferSize = 0;
METADATA_RECORD mdrMDData;
LPBYTE pBuffer = NULL;
MD_SET_DATA_RECORD(&mdrMDData,
MD_ADMIN_ACL, // admin acl
METADATA_INHERIT,
IIS_MD_UT_FILE,
BINARY_METADATA,
dwBufferSize,
pBuffer);
hr = pAdminBase->GetData(
hObjHandle,
pszIISPathName,
&mdrMDData,
&dwBufferSize
);
pBuffer = (LPBYTE) AllocADsMem(dwBufferSize);
if (!pBuffer) {
hr = HRESULT_FROM_WIN32(GetLastError());
BAIL_ON_FAILURE(hr);
}
MD_SET_DATA_RECORD(&mdrMDData,
MD_ADMIN_ACL, // admin acl
METADATA_INHERIT,
IIS_MD_UT_FILE,
BINARY_METADATA,
dwBufferSize,
pBuffer);
hr = pAdminBase->GetData(
hObjHandle,
pszIISPathName,
&mdrMDData,
&dwBufferSize
);
BAIL_ON_FAILURE(hr);
*ppBuffer = pBuffer;
RRETURN(hr);
error:
if (pBuffer) {
FreeADsMem(pBuffer);
}
RRETURN(hr);
}
HRESULT
MetaBaseDetectKey(
IN IMSAdminBase *pAdminBase,
IN LPCWSTR pszIISPathName
)
{
HRESULT hr = S_OK;
FILETIME ft;
hr = pAdminBase->GetLastChangeTime( METADATA_MASTER_ROOT_HANDLE,
pszIISPathName,
&ft,
FALSE
);
RRETURN(hr);
}
HRESULT
MetaBaseGetADsClass(
IN IMSAdminBase *pAdminBase,
IN LPWSTR pszIISPathName,
IN IIsSchema *pSchema,
OUT LPWSTR pszDataBuffer,
IN DWORD dwBufferLen
)
/*++
Routine Description:
Get the ADsClass from the metabase path.
Arguments:
IN pAdminBase : the metabase
IN pszIISPathName : the full metabase path (may be upcased)
IN pSchema : schema against which to validate
OUT pszDataBuffer : the class name
IN dwBufferLen : number of characters allocated for class name
Return Value:
--*/
{
// CODEWORK - There are at least two other places that do essentially
// the same thing. It should be possible to replace that code with a
// call to this routine
HRESULT hr = S_OK;
METADATA_HANDLE hObjHandle = NULL;
METADATA_RECORD mdrData;
DWORD dwReqdBufferLen = 0;
hr = pAdminBase->OpenKey( METADATA_MASTER_ROOT_HANDLE,
pszIISPathName,
METADATA_PERMISSION_READ,
DEFAULT_TIMEOUT_VALUE,
&hObjHandle
);
BAIL_ON_FAILURE(hr);
//
// Find out Class Name
//
mdrData.dwMDIdentifier = MD_KEY_TYPE;
mdrData.dwMDDataType = STRING_METADATA;
mdrData.dwMDUserType = ALL_METADATA;
mdrData.dwMDAttributes = METADATA_INHERIT;
mdrData.dwMDDataLen = dwBufferLen * sizeof(WCHAR);
mdrData.pbMDData = (PBYTE)pszDataBuffer;
hr = pAdminBase->GetData(
hObjHandle,
L"",
&mdrData,
&dwReqdBufferLen
);
if (FAILED(hr))
{
if (hr == MD_ERROR_DATA_NOT_FOUND)
{
//
// If the key does not have a KeyType we will do our best
// to guess. This is pretty bogus, but there is existing code
// that depends on this behavior.
//
_wcsupr(pszIISPathName);
if (wcsstr(pszIISPathName, L"W3SVC") != NULL)
{
wcscpy( pszDataBuffer, WEBDIR_CLASS_W );
}
else if (wcsstr(pszIISPathName, L"MSFTPSVC") != NULL)
{
wcscpy( pszDataBuffer, FTPVDIR_CLASS_W );
}
else
{
wcscpy( pszDataBuffer, DEFAULT_SCHEMA_CLASS_W );
}
hr = S_FALSE;
}
else
{
BAIL_ON_FAILURE(hr);
}
}
else
{
hr = pSchema->ValidateClassName( pszDataBuffer );
if (hr == E_ADS_UNKNOWN_OBJECT)
{
wcscpy( pszDataBuffer, DEFAULT_SCHEMA_CLASS_W );
}
}
error:
//
// Close the handle now
//
if (hObjHandle)
{
CloseAdminBaseKey(pAdminBase, hObjHandle);
hObjHandle = NULL;
}
RRETURN(hr);
}
static HRESULT
GetSchema(
CCredentials& Credentials,
LPWSTR machineNameW,
IIsSchema **out
)
/*++
Routine Description:
Creates and initializes a new IIsSchema object.
Arguments:
Return Value:
Notes:
This routine should only be used internally. If it is necessary
to get a reference to the schema for the current machine, use
InitServerInfo().
--*/
{
IIsSchema *schema=NULL;
HRESULT hr = S_OK;
schema = new IIsSchema();
if (schema) {
hr = schema->InitSchema(machineNameW, Credentials);
if (FAILED(hr)) {
delete schema;
schema = 0;
*out = 0;
return hr;
}
}
else {
return E_OUTOFMEMORY;
}
*out = schema;
return hr;
}
HRESULT
FreeMetaDataRecordArray(
PMETADATA_RECORD pMetaDataArray,
DWORD dwNumEntries
)
{
DWORD i;
DWORD dwIISType;
PMETADATA_RECORD pMetaData;
for (i = 0; i < dwNumEntries; i++ ) {
pMetaData = pMetaDataArray + i;
dwIISType = pMetaData->dwMDDataType;
switch(dwIISType) {
case DWORD_METADATA:
break;
case STRING_METADATA:
case EXPANDSZ_METADATA:
FreeADsStr((LPWSTR)pMetaData->pbMDData);
break;
case MULTISZ_METADATA:
case BINARY_METADATA:
FreeADsMem(pMetaData->pbMDData);
break;
default:
break;
}
}
FreeADsMem(pMetaDataArray);
RRETURN(S_OK);
}
HRESULT
InitAdminBase(
IN CCredentials& Credentials,
IN LPWSTR pszServerName,
OUT IMSAdminBase **ppAdminBase
)
{
HRESULT hr = S_OK;
COSERVERINFO csiName;
COSERVERINFO *pcsiParam = &csiName;
IClassFactory * pcsfFactory = NULL;
IMSAdminBase * pAdminBase = NULL;
IMSAdminBase * pAdminBaseT = NULL;
LPWSTR pszUserName = NULL;
LPWSTR pszPassword = NULL;
hr = Credentials.GetUserName(&pszUserName);
if (FAILED(hr))
{
return hr;
}
hr = Credentials.GetPassword(&pszPassword);
if (FAILED(hr))
{
return hr;
}
CComAuthInfo localAuthInfo(pszServerName,
pszUserName,
pszPassword);
memset(pcsiParam, 0, sizeof(COSERVERINFO));
pcsiParam = localAuthInfo.CreateServerInfoStruct();
hr = CoGetClassObject(
CLSID_MSAdminBase,
CLSCTX_SERVER,
pcsiParam,
IID_IClassFactory,
(void**) &pcsfFactory
);
BAIL_ON_FAILURE(hr);
hr = localAuthInfo.ApplyProxyBlanket(pcsfFactory);
BAIL_ON_FAILURE(hr);
hr = pcsfFactory->CreateInstance(
NULL,
IID_IMSAdminBase,
(void **) &pAdminBaseT
);
BAIL_ON_FAILURE(hr);
hr = localAuthInfo.ApplyProxyBlanket(pAdminBaseT);
BAIL_ON_FAILURE(hr);
hr = pAdminBaseT->UnmarshalInterface((IMSAdminBaseW **)&pAdminBase);
pAdminBaseT->Release();
pAdminBaseT = NULL;
BAIL_ON_FAILURE(hr);
hr = localAuthInfo.ApplyProxyBlanket(pAdminBase);
BAIL_ON_FAILURE(hr);
*ppAdminBase = pAdminBase;
localAuthInfo.FreeServerInfoStruct(pcsiParam);
error:
if (pcsfFactory) {
pcsfFactory->Release();
}
RRETURN(hr);
}
VOID
UninitAdminBase(
IN IMSAdminBase * pAdminBase
)
{
if (pAdminBase != NULL) {
pAdminBase->Release();
}
}
HRESULT
InitServerInfo(
IN CCredentials& Credentials,
IN LPWSTR pszServerName,
OUT IMSAdminBase ** ppObject,
OUT IIsSchema **ppSchema
)
{
HRESULT hr = S_OK;
IMSAdminBase * pAdminBase = NULL;
IIsSchema * pSchema = NULL;
SERVER_CACHE_ITEM * item;
BOOL Success;
DWORD dwThreadId;
ASSERT(g_pServerCache != NULL);
//
// We'll return the localhost machine config to the users if
// pszServerName == NULL, e.g. IIS:
//
if (pszServerName == NULL) {
pszServerName = L"Localhost";
}
dwThreadId = GetCurrentThreadId();
if ((item = g_pServerCache->Find(pszServerName, dwThreadId)) == NULL) {
//
// get pAdminBase and pSchema
//
hr = InitAdminBase(Credentials, pszServerName, &pAdminBase);
BAIL_ON_FAILURE(hr);
hr = GetSchema(Credentials, pszServerName, &pSchema);
if( ERROR_PATH_NOT_FOUND == HRESULT_CODE(hr) ||
MD_ERROR_DATA_NOT_FOUND == hr
)
{
// Return custom error.
hr = MD_ERROR_IISAO_INVALID_SCHEMA;
}
BAIL_ON_FAILURE(hr);
item = new SERVER_CACHE_ITEM(pszServerName,
pAdminBase,
pSchema,
dwThreadId,
Success);
if (item == NULL || !Success) {
if (item != NULL) {
delete pSchema;
UninitAdminBase(pAdminBase);
delete item;
}
RRETURN(E_OUTOFMEMORY); // OUT_OF_MEMORY;
}
if (g_pServerCache->Insert(item) == FALSE) {
delete pSchema;
UninitAdminBase(pAdminBase);
delete item;
RRETURN(E_OUTOFMEMORY); // OUT_OF_MEMORY;
}
}
*ppSchema = item->pSchema;
*ppObject = item->pAdminBase;
error :
RRETURN(hr);
}
HRESULT
MetaBaseGetDataPaths(
IN IMSAdminBase *pAdminBase,
IN METADATA_HANDLE hObjHandle,
IN DWORD dwMDMetaID,
OUT LPBYTE * ppBuffer
)
{
LPBYTE pBuffer = NULL;
HRESULT hr = S_OK;
DWORD dwBufferSize = 0;
DWORD dwReqdBufferSize = 0;
hr = pAdminBase->GetDataPaths(
hObjHandle,
(LPWSTR)L"",
dwMDMetaID,
ALL_METADATA,
dwBufferSize,
(LPWSTR)L"",
&dwReqdBufferSize
);
pBuffer = (LPBYTE) AllocADsMem(dwReqdBufferSize*sizeof(WCHAR));
if (!pBuffer) {
hr = HRESULT_FROM_WIN32(GetLastError());
BAIL_ON_FAILURE(hr);
}
dwBufferSize = dwReqdBufferSize;
hr = pAdminBase->GetDataPaths(
hObjHandle,
(LPWSTR)L"",
dwMDMetaID,
ALL_METADATA,
dwBufferSize,
(LPWSTR)pBuffer,
&dwReqdBufferSize
);
BAIL_ON_FAILURE(hr);
*ppBuffer = pBuffer;
RRETURN(hr);
error:
if (pBuffer) {
FreeADsMem(pBuffer);
}
RRETURN(hr);
}
HRESULT
MakeVariantFromStringArray(
LPWSTR pszStr,
LPWSTR pszList,
VARIANT *pvVariant
)
{
HRESULT hr = S_OK;
SAFEARRAY *aList = NULL;
SAFEARRAYBOUND aBound;
LPWSTR pszStrList;
WCHAR wchPath[MAX_PATH];
if (pszList != NULL)
{
long nCount = 0;
long i = 0;
pszStrList = pszList;
if (*pszStrList == L'\0') {
nCount = 1;
pszStrList++;
}
while (*pszStrList != L'\0') {
while (*pszStrList != L'\0') {
pszStrList++;
}
nCount++;
pszStrList++;
}
aBound.lLbound = 0;
aBound.cElements = nCount;
aList = SafeArrayCreate( VT_VARIANT, 1, &aBound );
if ( aList == NULL )
{
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
pszStrList = pszList;
for (i = 0; i < nCount; i++ )
{
VARIANT v;
VariantInit(&v);
V_VT(&v) = VT_BSTR;
if (pszStr) {
wcscpy((LPWSTR)wchPath, pszStr);
wcscat((LPWSTR)wchPath, pszStrList);
hr = ADsAllocString((LPWSTR)wchPath, &(V_BSTR(&v)));
}
else {
hr = ADsAllocString( pszStrList, &(V_BSTR(&v)));
}
BAIL_ON_FAILURE(hr);
hr = SafeArrayPutElement( aList, &i, &v );
VariantClear(&v);
BAIL_ON_FAILURE(hr);
pszStrList += wcslen(pszStrList) + 1;
}
VariantInit( pvVariant );
V_VT(pvVariant) = VT_ARRAY | VT_VARIANT;
V_ARRAY(pvVariant) = aList;
}
else
{
aBound.lLbound = 0;
aBound.cElements = 0;
aList = SafeArrayCreate( VT_VARIANT, 1, &aBound );
if ( aList == NULL )
{
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
VariantInit( pvVariant );
V_VT(pvVariant) = VT_ARRAY | VT_VARIANT;
V_ARRAY(pvVariant) = aList;
}
return S_OK;
error:
if ( aList )
SafeArrayDestroy( aList );
return hr;
}
HRESULT
MakeVariantFromPathArray(
LPWSTR pszStr,
LPWSTR pszList,
VARIANT *pvVariant
)
{
HRESULT hr = S_OK;
SAFEARRAY *aList = NULL;
SAFEARRAYBOUND aBound;
LPWSTR pszStrList;
LPWSTR pszConcatBuffer = NULL;
DWORD cbConcatBuffer = 0;
DWORD cbRequiredConcatBuffer = 0;
DWORD nStrLen = 0;
DWORD nPathStrLen = 0;
if (pszList != NULL)
{
//
// Count strings in pszList
//
long nCount = 0;
long i = 0;
pszStrList = pszList;
while (*pszStrList != L'\0') {
while (*pszStrList != L'\0') {
pszStrList++;
}
nCount++;
pszStrList++;
}
//
// Allocate output array
//
aBound.lLbound = 0;
aBound.cElements = nCount;
aList = SafeArrayCreate( VT_VARIANT, 1, &aBound );
if ( aList == NULL )
{
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
//
// Prepare to copy our values from pszList to aList
//
if( pszStr )
{
nStrLen = (DWORD)wcslen( pszStr );
}
pszStrList = pszList;
while ( *pszStrList != L'\0' )
{
VARIANT v;
VariantInit(&v);
V_VT(&v) = VT_BSTR;
if (pszStr)
{
//
// Reallocate our string buffer. Since the strings are
// generally increasing in size, we'll allocate more space
// than we need so we don't have to reallocate every time.
//
nPathStrLen = (DWORD)wcslen(pszStrList);
cbRequiredConcatBuffer = ( nStrLen + nPathStrLen + 1 )
* sizeof(WCHAR);
if( cbRequiredConcatBuffer > cbConcatBuffer )
{
pszConcatBuffer = (LPWSTR)ReallocADsMem(
pszConcatBuffer,
cbConcatBuffer,
2 * cbRequiredConcatBuffer
);
if( pszConcatBuffer == NULL )
{
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
if( cbConcatBuffer == 0 )
{
// This is our first time through.
wcscpy(pszConcatBuffer, pszStr);
}
cbConcatBuffer = 2 * cbRequiredConcatBuffer;
}
//
// Copy the returned value into the buffer.
//
wcscpy(pszConcatBuffer + nStrLen, pszStrList);
if (pszConcatBuffer[nStrLen + nPathStrLen - 1] == L'/')
{
pszConcatBuffer[nStrLen + nPathStrLen - 1] = L'\0';
}
hr = ADsAllocString(pszConcatBuffer, &(V_BSTR(&v)));
}
else {
hr = ADsAllocString( pszStrList, &(V_BSTR(&v)));
}
BAIL_ON_FAILURE(hr);
hr = SafeArrayPutElement( aList, &i, &v );
VariantClear(&v);
BAIL_ON_FAILURE(hr);
pszStrList += wcslen(pszStrList) + 1;
i++;
}
VariantInit( pvVariant );
V_VT(pvVariant) = VT_ARRAY | VT_VARIANT;
V_ARRAY(pvVariant) = aList;
}
else
{
aBound.lLbound = 0;
aBound.cElements = 0;
aList = SafeArrayCreate( VT_VARIANT, 1, &aBound );
if ( aList == NULL )
{
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
VariantInit( pvVariant );
V_VT(pvVariant) = VT_ARRAY | VT_VARIANT;
V_ARRAY(pvVariant) = aList;
}
if( pszConcatBuffer )
{
FreeADsMem( pszConcatBuffer );
}
return S_OK;
error:
if( pszConcatBuffer )
{
FreeADsMem( pszConcatBuffer );
}
if ( aList )
SafeArrayDestroy( aList );
return hr;
}
HRESULT
InitWamAdmin(
IN LPWSTR pszServerName,
OUT IWamAdmin2 **ppWamAdmin
)
{
HRESULT hr = S_OK;
COSERVERINFO csiName;
COSERVERINFO *pcsiParam = &csiName;
IClassFactory * pcsfFactory = NULL;
IWamAdmin2 * pWamAdmin = NULL;
memset(pcsiParam, 0, sizeof(COSERVERINFO));
//
// special case to handle "localhost" to work-around ole32 bug
//
if (pszServerName == NULL || _wcsicmp(pszServerName,L"localhost") == 0) {
pcsiParam->pwszName = NULL;
}
else {
pcsiParam->pwszName = pszServerName;
}
csiName.pAuthInfo = NULL;
pcsiParam = &csiName;
hr = CoGetClassObject(
CLSID_WamAdmin,
CLSCTX_SERVER,
pcsiParam,
IID_IClassFactory,
(void**) &pcsfFactory
);
BAIL_ON_FAILURE(hr);
hr = pcsfFactory->CreateInstance(
NULL,
IID_IWamAdmin2,
(void **) &pWamAdmin
);
BAIL_ON_FAILURE(hr);
*ppWamAdmin = pWamAdmin;
error:
if (pcsfFactory) {
pcsfFactory->Release();
}
RRETURN(hr);
}
VOID
UninitWamAdmin(
IN IWamAdmin2 *pWamAdmin
)
{
if (pWamAdmin != NULL) {
pWamAdmin->Release();
}
}
HRESULT
ConvertDispatchToVariantArray(
VARIANT varDispatch,
PVARIANT * ppVarArray,
PDWORD pdwNumVariants
)
{
HRESULT hr = S_OK;
VARIANT vVar;
WCHAR* wComma = NULL;
WCHAR* wHolder = NULL;
DWORD dwNumVariants = 0;
VARIANT * pVarArray = NULL;
VariantInit(&vVar);
hr = VariantCopyInd(&vVar, &varDispatch);
BAIL_ON_FAILURE(hr);
// Output here is VT_BSTR, of format: "str_1,str_2,str_3, ... str_n\0"
hr = VariantChangeType( &vVar, &vVar, 0, VT_BSTR );
BAIL_ON_FAILURE(hr);
// count the number of comma separated entries
wHolder = wComma = vVar.bstrVal;
while (wComma) {
wComma = wcsstr(wHolder, L",");
dwNumVariants++;
if (wComma) {
wComma++;
wHolder = wComma;
}
}
if (!dwNumVariants)
{
hr = E_FAIL;
BAIL_ON_FAILURE(hr);
}
pVarArray = (PVARIANT)AllocADsMem(
sizeof(VARIANT)*dwNumVariants
);
if (!pVarArray) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
DWORD i = 0;
wHolder = wComma = vVar.bstrVal;
while (wHolder) {
wComma = wcsstr(wHolder, L",");
if (wComma) {
*wComma = 0; // change the comma to null char
wComma++;
}
if (*wHolder) {
// use wHolder here
VariantInit(pVarArray + i);
V_VT(pVarArray + i) = VT_BSTR;
hr = ADsAllocString(wHolder, &(V_BSTR(pVarArray + i)));
BAIL_ON_FAILURE(hr);
i++;
}
else {
dwNumVariants--;
}
wHolder = wComma;
}
*ppVarArray = pVarArray;
*pdwNumVariants = dwNumVariants;
error:
VariantClear(&vVar);
RRETURN(hr);
}
HRESULT
ConvertArrayToVariantArray(
VARIANT varSafeArray,
PVARIANT * ppVarArray,
PDWORD pdwNumVariants
)
{
HRESULT hr = S_OK;
DWORD dwSLBound = 0;
DWORD dwSUBound = 0;
DWORD dwNumVariants = 0;
DWORD i = 0;
VARIANT * pVarArray = NULL;
SAFEARRAY * pArray = NULL;
*pdwNumVariants = 0;
*ppVarArray = 0;
if(!(V_ISARRAY(&varSafeArray)))
RRETURN(E_FAIL);
//
// This handles by-ref and regular SafeArrays.
//
if (V_VT(&varSafeArray) & VT_BYREF)
pArray = *(V_ARRAYREF(&varSafeArray));
else
pArray = V_ARRAY(&varSafeArray);
//
// Check that there is only one dimension in this array
//
if (pArray && pArray->cDims != 1) {
hr = E_FAIL;
BAIL_ON_FAILURE(hr);
}
//
// Check that there is at least one element in this array
//
if (!pArray ||
( pArray->rgsabound[0].cElements == 0) ) {
dwNumVariants = 1;
pVarArray = (PVARIANT)AllocADsMem(
sizeof(VARIANT)*dwNumVariants
);
if (!pVarArray) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
VariantInit(pVarArray);
pVarArray->vt = VT_BSTR;
pVarArray->bstrVal = NULL;
}
else {
//
// We know that this is a valid single dimension array
//
hr = SafeArrayGetLBound(pArray,
1,
(long FAR *)&dwSLBound
);
BAIL_ON_FAILURE(hr);
hr = SafeArrayGetUBound(pArray,
1,
(long FAR *)&dwSUBound
);
BAIL_ON_FAILURE(hr);
dwNumVariants = dwSUBound - dwSLBound + 1;
pVarArray = (PVARIANT)AllocADsMem(
sizeof(VARIANT)*dwNumVariants
);
if (!pVarArray) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
for (i = dwSLBound; i <= dwSUBound; i++) {
VariantInit(pVarArray + i);
hr = SafeArrayGetElement(pArray,
(long FAR *)&i,
(pVarArray + i)
);
CONTINUE_ON_FAILURE(hr);
}
}
*ppVarArray = pVarArray;
*pdwNumVariants = dwNumVariants;
error:
RRETURN(hr);
}
//
// Property helper functions
//
//
#define VALIDATE_PTR(pPtr) \
if (!pPtr) { \
hr = E_ADS_BAD_PARAMETER;\
}\
BAIL_ON_FAILURE(hr);
HRESULT
put_BSTR_Property(
IADs * pADsObject,
BSTR bstrPropertyName,
BSTR pSrcStringProperty
)
{
HRESULT hr = S_OK;
VARIANT varInputData;
hr = PackStringinVariant(
pSrcStringProperty,
&varInputData
);
BAIL_ON_FAILURE(hr);
hr = pADsObject->Put(
bstrPropertyName,
varInputData
);
BAIL_ON_FAILURE(hr);
error:
VariantClear( &varInputData );
RRETURN(hr);
}
HRESULT
get_BSTR_Property(
IADs * pADsObject,
BSTR bstrPropertyName,
BSTR *ppDestStringProperty
)
{
HRESULT hr = S_OK;
VARIANT varOutputData;
VALIDATE_PTR( ppDestStringProperty );
VariantInit( &varOutputData );
hr = pADsObject->Get(
bstrPropertyName,
&varOutputData
);
BAIL_ON_FAILURE(hr);
hr = UnpackStringfromVariant(
varOutputData,
ppDestStringProperty
);
BAIL_ON_FAILURE(hr);
error:
VariantClear( &varOutputData );
RRETURN(hr);
}
HRESULT
put_LONG_Property(
IADs * pADsObject,
BSTR bstrPropertyName,
LONG lSrcProperty
)
{
HRESULT hr = S_OK;
VARIANT varInputData;
hr = PackLONGinVariant(
lSrcProperty,
&varInputData
);
BAIL_ON_FAILURE(hr);
hr = pADsObject->Put(
bstrPropertyName,
varInputData
);
BAIL_ON_FAILURE(hr);
error:
VariantClear( &varInputData );
RRETURN(hr);
}
HRESULT
get_LONG_Property(
IADs * pADsObject,
BSTR bstrPropertyName,
PLONG plDestProperty
)
{
HRESULT hr = S_OK;
VARIANT varOutputData;
VALIDATE_PTR( plDestProperty );
VariantInit( &varOutputData );
hr = pADsObject->Get(
bstrPropertyName,
&varOutputData
);
BAIL_ON_FAILURE(hr);
hr = UnpackLONGfromVariant(
varOutputData,
plDestProperty
);
BAIL_ON_FAILURE(hr);
error:
VariantClear( &varOutputData );
RRETURN(hr);
}
HRESULT
put_DATE_Property(
IADs * pADsObject,
BSTR bstrPropertyName,
DATE daSrcProperty
)
{
HRESULT hr = S_OK;
VARIANT varInputData;
hr = PackDATEinVariant(
daSrcProperty,
&varInputData
);
BAIL_ON_FAILURE(hr);
hr = pADsObject->Put(
bstrPropertyName,
varInputData
);
BAIL_ON_FAILURE(hr);
error:
VariantClear( &varInputData );
RRETURN(hr);
}
HRESULT
put_VARIANT_BOOL_Property(
IADs * pADsObject,
BSTR bstrPropertyName,
VARIANT_BOOL fSrcProperty
)
{
HRESULT hr = S_OK;
VARIANT varInputData;
hr = PackVARIANT_BOOLinVariant(
fSrcProperty,
&varInputData
);
BAIL_ON_FAILURE(hr);
hr = pADsObject->Put(
bstrPropertyName,
varInputData
);
BAIL_ON_FAILURE(hr);
error:
VariantClear( &varInputData );
RRETURN(hr);
}
HRESULT
get_VARIANT_BOOL_Property(
IADs * pADsObject,
BSTR bstrPropertyName,
PVARIANT_BOOL pfDestProperty
)
{
HRESULT hr = S_OK;
VARIANT varOutputData;
VALIDATE_PTR( pfDestProperty );
VariantInit( &varOutputData );
hr = pADsObject->Get(
bstrPropertyName,
&varOutputData
);
BAIL_ON_FAILURE(hr);
hr = UnpackVARIANT_BOOLfromVariant(
varOutputData,
pfDestProperty
);
BAIL_ON_FAILURE(hr);
error:
VariantClear( &varOutputData );
RRETURN(hr);
}
HRESULT
put_VARIANT_Property(
IADs * pADsObject,
BSTR bstrPropertyName,
VARIANT vSrcProperty
)
{
HRESULT hr = S_OK;
VARIANT varInputData;
hr = PackVARIANTinVariant(
vSrcProperty,
&varInputData
);
BAIL_ON_FAILURE(hr);
hr = pADsObject->Put(
bstrPropertyName,
varInputData
);
BAIL_ON_FAILURE(hr);
error:
VariantClear( &varInputData );
RRETURN(hr);
}
HRESULT
get_VARIANT_Property(
IADs * pADsObject,
BSTR bstrPropertyName,
PVARIANT pvDestProperty
)
{
HRESULT hr = S_OK;
VARIANT varOutputData;
VALIDATE_PTR( pvDestProperty );
VariantInit( &varOutputData );
hr = pADsObject->Get(
bstrPropertyName,
&varOutputData
);
BAIL_ON_FAILURE(hr);
hr = UnpackVARIANTfromVariant(
varOutputData,
pvDestProperty
);
BAIL_ON_FAILURE(hr);
error:
VariantClear( &varOutputData );
RRETURN(hr);
}
HRESULT
MetaBaseGetStringData(
IN IMSAdminBase * pAdminBase,
IN METADATA_HANDLE hObjHandle,
IN LPWSTR pszIISPathName,
IN DWORD dwMetaId,
OUT LPBYTE *ppBuffer
)
{
HRESULT hr = S_OK;
DWORD dwBufferSize = 0;
METADATA_RECORD mdrMDData;
LPBYTE pBuffer = NULL;
MD_SET_DATA_RECORD(&mdrMDData,
dwMetaId,
METADATA_NO_ATTRIBUTES,
ALL_METADATA,
STRING_METADATA,
dwBufferSize,
pBuffer);
hr = pAdminBase->GetData(
hObjHandle,
pszIISPathName,
&mdrMDData,
&dwBufferSize
);
pBuffer = (LPBYTE) AllocADsMem(dwBufferSize);
if (!pBuffer) {
hr = HRESULT_FROM_WIN32(GetLastError());
BAIL_ON_FAILURE(hr);
}
MD_SET_DATA_RECORD(&mdrMDData,
dwMetaId,
METADATA_NO_ATTRIBUTES,
ALL_METADATA,
STRING_METADATA,
dwBufferSize,
pBuffer);
hr = pAdminBase->GetData(
hObjHandle,
pszIISPathName,
&mdrMDData,
&dwBufferSize
);
BAIL_ON_FAILURE(hr);
*ppBuffer = pBuffer;
RRETURN(hr);
error:
if (pBuffer) {
FreeADsMem(pBuffer);
}
RRETURN(hr);
}
HRESULT
MetaBaseGetDwordData(
IN IMSAdminBase * pAdminBase,
IN METADATA_HANDLE hObjHandle,
IN LPWSTR pszIISPathName,
IN DWORD dwMetaId,
OUT PDWORD pdwData
)
{
HRESULT hr = S_OK;
DWORD dwBufferSize = sizeof(DWORD);
METADATA_RECORD mdrMDData;
LPBYTE pBuffer = (LPBYTE)pdwData;
MD_SET_DATA_RECORD(&mdrMDData,
dwMetaId,
METADATA_NO_ATTRIBUTES,
IIS_MD_UT_SERVER,
DWORD_METADATA,
dwBufferSize,
pBuffer);
hr = pAdminBase->GetData(
hObjHandle,
pszIISPathName,
&mdrMDData,
&dwBufferSize
);
RRETURN(hr);
}
HRESULT
MakeStringFromVariantArray(
VARIANT *pvVariant,
LPBYTE* ppBuffer
)
{
HRESULT hr = S_OK;
DWORD i;
DWORD dwLen = 0;
VARIANT *pVar;
LPBYTE pBuffer = NULL;
DWORD dwNumVars = 0;
VARIANT * pVarArray = NULL;
pVar = pvVariant;
if (pVar->vt == VT_EMPTY) {
RRETURN(S_OK);
}
hr = ConvertArrayToVariantArray(
*pVar,
&pVarArray,
&dwNumVars
);
BAIL_ON_FAILURE(hr);
if (dwNumVars == 0) {
RRETURN(S_OK);
}
//
// find out total length
//
pVar = pVarArray;
for (i = 0; i < dwNumVars; i++ ) {
//
// add 1 for comma
//
if (pVar->vt == VT_BSTR || pVar->vt == VT_EMPTY) {
if (pVar->bstrVal && *(pVar->bstrVal)) {
//
// validate parameter; check for ','
//
if (wcschr(pVar->bstrVal, L',')) {
hr = E_ADS_BAD_PARAMETER;
BAIL_ON_FAILURE(hr);
}
dwLen += ((DWORD)wcslen(pVar->bstrVal) + 1);
}
}
else {
hr = E_ADS_CANT_CONVERT_DATATYPE;
BAIL_ON_FAILURE(hr);
}
pVar++;
}
//
// if there are non-empty entries found in the array, copy them to buffer
//
if (dwLen != 0) {
pBuffer = (LPBYTE) AllocADsMem(dwLen*sizeof(WCHAR));
if (!pBuffer) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
*ppBuffer = pBuffer;
pVar = pVarArray;
for (i = 0; i < dwNumVars; i++, pVar++ ) {
if (pVar->bstrVal && *(pVar->bstrVal)) {
memcpy(pBuffer, pVar->bstrVal,
wcslen(pVar->bstrVal)*sizeof(WCHAR));
pBuffer = pBuffer + wcslen(pVar->bstrVal)*sizeof(WCHAR);
if (i != dwNumVars -1) {
memcpy(pBuffer, L",", sizeof(WCHAR));
pBuffer = pBuffer + sizeof(WCHAR);
}
}
}
if (*ppBuffer == pBuffer - dwLen*sizeof(WCHAR)) {
pBuffer -= sizeof(WCHAR);
*pBuffer = L'\0';
}
else {
*pBuffer = L'\0';
}
}
error:
if (pVarArray) {
for (i = 0; i < dwNumVars; i++) {
VariantClear(pVarArray + i);
}
FreeADsMem(pVarArray);
}
if (FAILED(hr) && pBuffer) {
FreeADsMem(pBuffer);
}
RRETURN(hr);
}
HRESULT
CheckVariantDataType(
PVARIANT pVar,
VARTYPE vt
)
{
HRESULT hr;
hr = VariantChangeType(pVar,
pVar,
0,
vt);
if (FAILED(hr)) {
if (hr == E_OUTOFMEMORY) {
RRETURN(hr);
}
RRETURN(hr = E_ADS_CANT_CONVERT_DATATYPE);
}
RRETURN(hr);
}
HRESULT
MakeMultiStringFromVariantArray(
VARIANT *pvVariant,
LPBYTE* ppBuffer
)
{
HRESULT hr = S_OK;
DWORD i;
DWORD dwLen = 0;
VARIANT *pVar;
LPBYTE pBuffer = NULL;
DWORD dwNumVars = 0;
VARIANT * pVarArray = NULL;
pVar = pvVariant;
if (pVar->vt == VT_EMPTY) {
RRETURN(S_OK);
}
hr = ConvertArrayToVariantArray(
*pVar,
&pVarArray,
&dwNumVars
);
BAIL_ON_FAILURE(hr);
if (dwNumVars == 0) {
RRETURN(S_OK);
}
//
// find out total length
//
pVar = pVarArray;
for (i = 0; i < dwNumVars; i++ ) {
if (pVar->vt == VT_BSTR) {
if (pVar->bstrVal && *(pVar->bstrVal)) {
dwLen += ((DWORD)wcslen(pVar->bstrVal) + 1);
}
else {
//
// add 1 for \0
//
dwLen++;
}
}
else {
hr = E_ADS_CANT_CONVERT_DATATYPE;
BAIL_ON_FAILURE(hr);
}
pVar++;
}
//
// +1 for extra \0
//
dwLen++;
//
// copy entries to buffer
//
if (dwLen != 0) {
pBuffer = (LPBYTE) AllocADsMem(dwLen*sizeof(WCHAR));
if (!pBuffer) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
*ppBuffer = pBuffer;
pVar = pVarArray;
for (i = 0; i < dwNumVars; i++, pVar++ ) {
if (pVar->bstrVal && *(pVar->bstrVal)) {
memcpy(pBuffer, pVar->bstrVal,
wcslen(pVar->bstrVal)*sizeof(WCHAR));
pBuffer = pBuffer + wcslen(pVar->bstrVal)*sizeof(WCHAR);
}
memcpy(pBuffer, L"\0", sizeof(WCHAR));
pBuffer = pBuffer + sizeof(WCHAR);
}
*pBuffer = L'\0';
}
error:
if (pVarArray) {
for (i = 0; i < dwNumVars; i++) {
VariantClear(pVarArray + i);
}
FreeADsMem(pVarArray);
}
if (FAILED(hr) && pBuffer) {
FreeADsMem(pBuffer);
}
RRETURN(hr);
}