windows-nt/Source/XPSP1/NT/net/ias/sdo/sdoias/sdodictionary.cpp
2020-09-26 16:20:57 +08:00

682 lines
16 KiB
C++

///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 1999, Microsoft Corp. All rights reserved.
//
// FILE
//
// sdodictionary.cpp
//
// SYNOPSIS
//
// Defines the class SdoDictionary.
//
// MODIFICATION HISTORY
//
// 03/01/1999 Original version.
// 01/27/2000 Add support for proxy policies.
// 04/17/2000 Port to new dictionary API.
//
///////////////////////////////////////////////////////////////////////////////
#include <stdafx.h>
#include <vector>
#include <iastlb.h>
#include <iastlutl.h>
#include <iasutil.h>
#include <iasuuid.h>
#include <attrdef.h>
#include <sdoattribute.h>
#include <sdodictionary.h>
#include "resource.h"
using namespace std;
// Function type used with bsearch and qsort.
typedef int (__cdecl *CompFn)(const void*, const void*);
inline SdoDictionary::SdoDictionary() throw ()
: refCount(0),
dnaryLoc(NULL),
size(0),
byId(NULL),
byName(NULL),
byLdapName(NULL)
{
}
inline SdoDictionary::~SdoDictionary() throw ()
{
for (ULONG i = 0; i < size; ++i)
{
if (byId[i]) { byId[i]->Release(); }
}
delete[] byId;
delete[] byName;
delete[] byLdapName;
delete dnaryLoc;
}
HRESULT SdoDictionary::createInstance(
PCWSTR path,
bool local,
SdoDictionary** newDnary
) throw ()
{
// Check the arguments.
if (path == NULL || newDnary == NULL) { return E_INVALIDARG; }
// Initialize the out parameter.
*newDnary = NULL;
// Create a new dictionary.
SdoDictionary* dnary = new (std::nothrow) SdoDictionary;
if (!dnary) { return E_OUTOFMEMORY; }
// Build the DSN.
PWCHAR dsn = (PWCHAR)_alloca((wcslen(path) + 11) * sizeof(WCHAR));
wcscat(wcscpy(dsn, path), L"\\dnary.mdb");
// Initialize the dictionary.
HRESULT hr = dnary->initialize(dsn, local);
if (FAILED(hr))
{
delete dnary;
return hr;
}
// Set the refCount & return.
dnary->refCount = 1;
*newDnary = dnary;
return S_OK;
}
const AttributeDefinition* SdoDictionary::findById(
ULONG id
) const throw ()
{
const AttributeDefinition* const* match;
match = (const AttributeDefinition* const*)
bsearch(
&id,
byId,
size,
sizeof(AttributeDefinition*),
(CompFn)AttributeDefinition::searchById
);
return match ? *match : NULL;
}
const AttributeDefinition* SdoDictionary::findByName(
PCWSTR name
) const throw ()
{
const AttributeDefinition* const* match;
match = (const AttributeDefinition* const*)
bsearch(
name,
byName,
size,
sizeof(AttributeDefinition*),
(CompFn)AttributeDefinition::searchByName
);
return match ? *match : NULL;
}
const AttributeDefinition* SdoDictionary::findByLdapName(
PCWSTR name
) const throw ()
{
const AttributeDefinition* const* match;
match = (const AttributeDefinition* const*)
bsearch(
name,
byLdapName,
size,
sizeof(AttributeDefinition*),
(CompFn)AttributeDefinition::searchByLdapName
);
return match ? *match : NULL;
}
STDMETHODIMP_(ULONG) SdoDictionary::AddRef()
{
return InterlockedIncrement(&refCount);
}
STDMETHODIMP_(ULONG) SdoDictionary::Release()
{
ULONG l = InterlockedDecrement(&refCount);
if (l == 0) { delete this; }
return l;
}
STDMETHODIMP SdoDictionary::QueryInterface(REFIID iid, void ** ppvObject)
{
if (ppvObject == NULL) { return E_POINTER; }
if (iid == __uuidof(ISdoDictionaryOld) ||
iid == __uuidof(IUnknown) ||
iid == __uuidof(IDispatch))
{
*ppvObject = this;
}
else if (iid == __uuidof(ISdo))
{
*ppvObject = static_cast<ISdo*>(this);
}
else
{
return E_NOINTERFACE;
}
InterlockedIncrement(&refCount);
return S_OK;
}
STDMETHODIMP SdoDictionary::EnumAttributes(
VARIANT* Id,
VARIANT* pValues
)
{
// Check the arguments.
if (Id == NULL || pValues == NULL) { return E_INVALIDARG; }
// Initialize the out parameters.
VariantInit(Id);
VariantInit(pValues);
// Find out what the caller's asking for.
const AttributeDefinition* single;
const AttributeDefinition* const* src;
ULONG numAttrs;
if (V_VT(Id) == VT_EMPTY)
{
// He wants all the attributes.
src = byId;
numAttrs = size;
}
else if (V_VT(Id) == VT_I4)
{
// He wants a single attribute.
single = findById(V_VT(Id));
if (!single) { return DISP_E_MEMBERNOTFOUND; }
src = &single;
numAttrs = 1;
}
else
{
// Invalid VARIANT type.
return E_INVALIDARG;
}
HRESULT hr = S_OK;
do
{
//////////
// Allocate SAFEARRAYs to hold the return values.
//////////
V_ARRAY(Id) = SafeArrayCreateVector(VT_I4, 0, numAttrs);
V_VT(Id) = VT_ARRAY | VT_I4;
V_ARRAY(pValues) = SafeArrayCreateVector(VT_VARIANT, 0, numAttrs);
V_VT(pValues) = VT_ARRAY | VT_VARIANT;
if (!V_ARRAY(Id) || !V_ARRAY(pValues))
{
hr = E_OUTOFMEMORY;
break;
}
//////////
// Populate the arrays.
//////////
const AttributeDefinition* const* end = src + numAttrs;
PULONG dstId = (PULONG)V_ARRAY(Id)->pvData;
LPVARIANT dstName = (LPVARIANT)V_ARRAY(pValues)->pvData;
for ( ; src != end; ++src, ++dstId, ++dstName)
{
*dstId = (*src)->id;
V_BSTR(dstName) = SysAllocString((*src)->name);
if (!V_BSTR(dstName))
{
hr = E_OUTOFMEMORY;
break;
}
V_VT(dstName) = VT_BSTR;
}
} while (false);
// If anything went wrong, clean up.
if (FAILED(hr))
{
VariantClear(Id);
VariantClear(pValues);
}
return hr;
}
STDMETHODIMP SdoDictionary::GetAttributeInfo(
ATTRIBUTEID Id,
VARIANT* pInfoIDs,
VARIANT* pInfoValues
)
{
// Check the arguments.
if (pInfoValues == NULL ||
pInfoIDs == NULL ||
// V_VT(pInfoIDs) != (VT_ARRAY | VT_I4) ||
V_ARRAY(pInfoIDs) == NULL ||
V_ARRAY(pInfoIDs)->cDims != 1)
{
return E_INVALIDARG;
}
// Initialize the out parameter.
VariantInit(pInfoValues);
// Find the attribute of interest.
const AttributeDefinition* def = findById(Id);
if (!def) { return DISP_E_MEMBERNOTFOUND; }
// Allocate the outbound array.
ULONG num = V_ARRAY(pInfoIDs)->rgsabound[0].cElements;
V_ARRAY(pInfoValues) = SafeArrayCreateVector(VT_VARIANT, 0, num);
if (!V_ARRAY(pInfoValues)) { return E_OUTOFMEMORY; }
V_VT(pInfoValues) = VT_ARRAY | VT_VARIANT;
// Fill in the information.
PULONG src = (PULONG)V_ARRAY(pInfoIDs)->pvData;
LPVARIANT dst = (LPVARIANT)V_ARRAY(pInfoValues)->pvData;
for ( ; num > 0; --num, ++src, ++dst)
{
HRESULT hr = def->getInfo((ATTRIBUTEINFO)*src, dst);
if (FAILED(hr))
{
VariantClear(pInfoValues);
return hr;
}
}
return S_OK;
}
STDMETHODIMP SdoDictionary::EnumAttributeValues(
ATTRIBUTEID Id,
VARIANT* pValueIds,
VARIANT* pValuesDesc
)
{
// Check the arguments.
if (pValueIds == NULL || pValuesDesc == NULL) { return E_INVALIDARG; }
// Initialize the out parameters.
VariantInit(pValueIds);
VariantInit(pValuesDesc);
// Find the attribute of interest.
const AttributeDefinition* def = findById(Id);
if (!def) { return DISP_E_MEMBERNOTFOUND; }
// If it's not enumerable, there's nothing to do.
if (def->enumNames == NULL) { return S_OK; }
// Copy the enum Names and Values.
HRESULT hr = SafeArrayCopy(def->enumValues, &V_ARRAY(pValueIds));
if (SUCCEEDED(hr))
{
V_VT(pValueIds) = VT_ARRAY | VT_I4;
hr = SafeArrayCopy(def->enumNames, &V_ARRAY(pValuesDesc));
if (SUCCEEDED(hr))
{
V_VT(pValuesDesc) = VT_ARRAY | VT_VARIANT;
}
else
{
VariantClear(pValueIds);
}
}
return hr;
}
STDMETHODIMP SdoDictionary::CreateAttribute(
ATTRIBUTEID Id,
IDispatch** ppAttributeObject
)
{
// Check the arguments.
if (ppAttributeObject == NULL) { return E_INVALIDARG; }
// Initialize the out parameter.
*ppAttributeObject = NULL;
// Find the attribute of interest.
const AttributeDefinition* def = findById(Id);
if (!def) { return DISP_E_MEMBERNOTFOUND; }
SdoAttribute* newAttr;
HRESULT hr = SdoAttribute::createInstance(def, &newAttr);
if (FAILED(hr)) { return hr; }
*ppAttributeObject = newAttr;
return S_OK;
}
STDMETHODIMP SdoDictionary::GetAttributeID(
BSTR bstrAttributeName,
ATTRIBUTEID* pId
)
{
// Check the arguments.
if (bstrAttributeName == NULL || pId == NULL) { return E_INVALIDARG; }
const AttributeDefinition* match;
// Check for LDAP Name first since this will speed up load time.
match = findByLdapName(bstrAttributeName);
if (!match)
{
// Maybe it's a display name instead.
match = findByName(bstrAttributeName);
}
if (!match) { return DISP_E_MEMBERNOTFOUND; }
*pId = (ATTRIBUTEID)match->id;
return S_OK;
}
STDMETHODIMP SdoDictionary::GetPropertyInfo(LONG Id, IUnknown** ppPropertyInfo)
{ return E_NOTIMPL; }
STDMETHODIMP SdoDictionary::GetProperty(LONG Id, VARIANT* pValue)
{
// Check the input args.
if (pValue == NULL) { return E_INVALIDARG; }
// Initialize the out parameter.
VariantInit(pValue);
// We only have one property.
if (Id != PROPERTY_DICTIONARY_LOCATION) { return DISP_E_MEMBERNOTFOUND; }
// dnaryLoc may be NULL.
if (dnaryLoc)
{
V_BSTR(pValue) = SysAllocString(dnaryLoc);
if (!V_BSTR(pValue)) { return E_OUTOFMEMORY; }
}
else
{
V_BSTR(pValue) = NULL;
}
V_VT(pValue) = VT_BSTR;
return S_OK;
}
STDMETHODIMP SdoDictionary::PutProperty(LONG Id, VARIANT* pValue)
{ return E_ACCESSDENIED; }
STDMETHODIMP SdoDictionary::ResetProperty(LONG Id)
{ return S_OK; }
STDMETHODIMP SdoDictionary::Apply()
{ return S_OK; }
STDMETHODIMP SdoDictionary::Restore()
{ return S_OK; }
STDMETHODIMP SdoDictionary::get__NewEnum(IUnknown** ppEnumVARIANT)
{ return E_NOTIMPL; }
HRESULT SdoDictionary::initialize(PCWSTR dsn, bool local) throw ()
{
const size_t IAS_MAX_STRING = 512;
// Save the dsn.
size_t nbyte = (wcslen(dsn) + 1) * sizeof(WCHAR);
dnaryLoc = (PWSTR)operator new (nbyte, std::nothrow);
if (!dnaryLoc) { return E_OUTOFMEMORY; }
memcpy(dnaryLoc, dsn, nbyte);
// Vector to hold the AttributeDefinitions.
vector<const AttributeDefinition*> defs;
HRESULT hr = S_OK;
try
{
// Names of various columns in the dictionary.
const PCWSTR COLUMNS[] =
{
L"ID",
L"Name",
L"Syntax",
L"MultiValued",
L"VendorID",
L"IsAllowedInProfile",
L"IsAllowedInCondition",
L"IsAllowedInProxyProfile",
L"IsAllowedInProxyCondition",
L"Description",
L"LDAPName",
L"EnumNames",
L"EnumValues",
NULL
};
// Open the attributes table.
IASTL::IASDictionary dnary(COLUMNS, (local ? NULL : dsn));
defs.reserve(dnary.getNumRows());
while (dnary.next())
{
// We're not interested in attributes that don't have a name.
if (dnary.isEmpty(1)) { continue; }
// Create a new AttributeDefinition.
CComPtr<AttributeDefinition> def;
HRESULT hr = AttributeDefinition::createInstance(&def);
if (FAILED(hr)) { throw bad_alloc(); }
/////////
// Process the fields in the query result.
/////////
def->id = (ULONG)dnary.getLong(0);
def->name = SysAllocString(dnary.getBSTR(1));
if (!def->name) { throw bad_alloc(); }
def->syntax = (ULONG)dnary.getLong(2);
if (dnary.getBool(3))
{
def->restrictions |= MULTIVALUED;
}
def->vendor = (ULONG)dnary.getLong(4);
if (dnary.getBool(5))
{
def->restrictions |= ALLOWEDINPROFILE;
}
if (dnary.getBool(6))
{
def->restrictions |= ALLOWEDINCONDITION;
}
if (dnary.getBool(7))
{
def->restrictions |= ALLOWEDINPROXYPROFILE;
}
if (dnary.getBool(8))
{
def->restrictions |= ALLOWEDINPROXYCONDITION;
}
if (dnary.isEmpty(9))
{
// Whistler machine. Load the string from the rc file
WCHAR strTemp[IAS_MAX_STRING];
int nbChar = LoadString(
_Module.GetResourceInstance(),
static_cast<UINT>(def->id),
strTemp,
IAS_MAX_STRING
);
if (nbChar > 0)
{
// Description found
def->description = SysAllocString(strTemp);
if (!def->description) { throw bad_alloc();}
}
else
{
// Load the Default string
nbChar = LoadString(
_Module.GetResourceInstance(),
IDS_DESC_NOT_AVAIL,
strTemp,
IAS_MAX_STRING
);
_ASSERT(nbChar > 0);
def->description = SysAllocString(strTemp);
if (!def->description) { throw bad_alloc();}
}
}
else
{
// This is a Windows 2000 machine
def->description = SysAllocString(dnary.getBSTR(9));
if (!def->description) { throw bad_alloc(); }
}
if (!dnary.isEmpty(10))
{
def->ldapName = SysAllocString(dnary.getBSTR(10));
}
else
{
def->ldapName = SysAllocString(def->name);
}
if (!def->ldapName) { throw bad_alloc(); }
// Get the enumeration SAFEARRAYs.
if (!dnary.isEmpty(11))
{
hr = SafeArrayCopy(
V_ARRAY(dnary.getVariant(11)),
&def->enumNames
);
if (FAILED(hr)) { _com_issue_error(hr); }
}
if (!dnary.isEmpty(12))
{
hr = SafeArrayCopy(
V_ARRAY(dnary.getVariant(12)),
&def->enumValues
);
if (FAILED(hr)) { _com_issue_error(hr); }
}
// Add this to the entries vector.
defs.push_back(def);
// We've safely stored the attribute, so detach.
*(&def) = NULL;
}
// Allocate the permanent arrays.
size = defs.size();
byId = new const AttributeDefinition*[size];
byName = new const AttributeDefinition*[size];
byLdapName = new const AttributeDefinition*[size];
// Fill in the arrays.
size_t nbyte = size * sizeof(AttributeDefinition*);
memcpy(byId, defs.begin(), nbyte);
memcpy(byName, defs.begin(), nbyte);
memcpy(byLdapName, defs.begin(), nbyte);
// Sort the arrays.
qsort(
byId,
size,
sizeof(AttributeDefinition*),
(CompFn)AttributeDefinition::sortById
);
qsort(
byName,
size,
sizeof(AttributeDefinition*),
(CompFn)AttributeDefinition::sortByName
);
qsort(
byLdapName,
size,
sizeof(AttributeDefinition*),
(CompFn)AttributeDefinition::sortByLdapName
);
}
catch (const _com_error& ce)
{
hr = ce.Error();
}
catch (const std::bad_alloc&)
{
hr = E_OUTOFMEMORY;
}
catch (...)
{
hr = DISP_E_EXCEPTION;
}
if (FAILED(hr))
{
vector<const AttributeDefinition*>::iterator i;
for (i = defs.begin(); i != defs.end(); ++i)
{
if (*i) { (*i)->Release(); }
}
delete[] byId;
delete[] byName;
delete[] byLdapName;
size = 0;
}
return hr;
}