/////////////////////////////////////////////////////////////////////////////// // // 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 #include #include #include #include #include #include #include #include #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(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 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 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(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::iterator i; for (i = defs.begin(); i != defs.end(); ++i) { if (*i) { (*i)->Release(); } } delete[] byId; delete[] byName; delete[] byLdapName; size = 0; } return hr; }