682 lines
16 KiB
C++
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;
|
|
}
|