#include "stdafx.h" #include "namemap.h" #include "query.h" #include "assert.h" #include using std::wcout; using std::endl; DisplayNameMapMap DisplayNames::m_mapMap; DisplayNameMap* DisplayNames::m_pmapClass = NULL; LCID DisplayNames::m_locale = GetSystemDefaultLCID(); /////////////////////////////////////////////// DisplayNameMapMap::~DisplayNameMapMap() { for (DisplayNameMapMap::iterator it = begin(); it != end(); it++) delete (*it).second; } /////////////////////////////////////////////////////////////////////// // // class DisplayNames // /////////////////////////////////////////////// DisplayNameMap* DisplayNames::GetMap(LPCWSTR name) { DisplayNameMapMap::iterator it; if ((it = m_mapMap.find(name)) != m_mapMap.end()) { (*it).second->AddRef(); return (*it).second; } else { DisplayNameMap* nameMap = new DisplayNameMap(); if( !nameMap) return NULL; m_mapMap.insert(DisplayNameMapMap::value_type(name, nameMap)); nameMap->AddRef(); nameMap->InitializeMap(name); return nameMap; } } DisplayNameMap* DisplayNames::GetClassMap() { if( !m_pmapClass ) { m_pmapClass = new DisplayNameMap(); if( !m_pmapClass ) return NULL; m_pmapClass->InitializeClassMap(); } return m_pmapClass; } /////////////////////////////////////////////// DisplayNameMap::DisplayNameMap() { m_nRefCount = 0; } void DisplayNameMap::InitializeMap(LPCWSTR name) { if( !name ) return; // Check schema for naming attribute do { // Special case for printer queue // (display descr maps "Name" to printerName, but schema reports cn) if (wcscmp(name, L"printQueue") == 0) { m_strNameAttr = L"printerName"; break; } tstring strScope = L"LDAP://schema/"; strScope += name; CComPtr pObj; HRESULT hr = ADsGetObject((LPWSTR)strScope.c_str(), IID_IADsClass, (void**)&pObj); BREAK_ON_FAILURE(hr) CComVariant var; hr = pObj->get_NamingProperties(&var); BREAK_ON_FAILURE(hr); if (var.vt == VT_BSTR) m_strNameAttr = var.bstrVal; } while (FALSE); // if no display name specified, default to "cn" if (m_strNameAttr.empty()) m_strNameAttr = L"cn"; CComPtr spDispSpecCont; CComBSTR bstrProp; CComVariant svar; // Open Display specifier for this object LPCWSTR pszConfigDN; EXIT_ON_FAILURE(GetNamingContext(NAMECTX_CONFIG, &pszConfigDN)); //Build the string to bind to the DisplaySpecifiers container. WCHAR szPath[MAX_PATH]; _snwprintf(szPath, MAX_PATH-1, L"LDAP://cn=%s-Display,cn=%x,cn=DisplaySpecifiers,%s", name, DisplayNames::GetLocale(), pszConfigDN); //Bind to the DisplaySpecifiers container. EXIT_ON_FAILURE(ADsOpenObject(szPath, NULL, NULL, ADS_SECURE_AUTHENTICATION, //Use Secure Authentication IID_IADs, (void**)&spDispSpecCont)); bstrProp = _T("attributeDisplayNames"); EXIT_ON_FAILURE(spDispSpecCont->Get( bstrProp, &svar )); #ifdef MAP_DEBUG_PRINT WCHAR szBuf[128]; _snwprintf(szBuf, (128)-1, L"\n DisplayNameMap for %s\n", name); OutputDebugString(szBuf); #endif tstring strIntName; tstring strFriendlyName; if ((svar.vt & VT_ARRAY) == VT_ARRAY) { CComVariant svarItem; SAFEARRAY *sa = V_ARRAY(&svar); LONG lStart, lEnd; // Get the lower and upper bound EXIT_ON_FAILURE(SafeArrayGetLBound(sa, 1, &lStart)); EXIT_ON_FAILURE(SafeArrayGetUBound(sa, 1, &lEnd)); for (long idx=lStart; idx <= lEnd; idx++) { CONTINUE_ON_FAILURE(SafeArrayGetElement(sa, &idx, &svarItem)); if( svarItem.vt != VT_BSTR ) return; strIntName.erase(); strIntName = wcstok(svarItem.bstrVal, L","); if (strIntName != m_strNameAttr) { strFriendlyName.erase(); strFriendlyName = wcstok(NULL, L","); m_map.insert(STRINGMAP::value_type(strIntName, strFriendlyName)); } #ifdef MAP_DEBUG_PRINT _snwprintf( szBuf, (128)-1, L" %-20s %s\n", strIntName.c_str(), strFriendlyName.c_str() ); OutputDebugString(szBuf); #endif svarItem.Clear(); } } else { if( svar.vt != VT_BSTR ) return; strIntName = wcstok(svar.bstrVal, L","); if (strIntName != m_strNameAttr) { strFriendlyName = wcstok(NULL, L","); m_map.insert(STRINGMAP::value_type(strIntName, strFriendlyName)); } } svar.Clear(); bstrProp = _T("classDisplayName"); EXIT_ON_FAILURE(spDispSpecCont->Get( bstrProp, &svar )); m_strFriendlyClassName = svar.bstrVal; } void DisplayNameMap::InitializeClassMap() { CComPtr spDirSrch; CComVariant svar; tstring strIntName; tstring strFriendlyName; m_strFriendlyClassName = L""; LPCWSTR pszConfigContext; EXIT_ON_FAILURE(GetNamingContext(NAMECTX_CONFIG, &pszConfigContext)); HRESULT hr; do { //Build the string to bind to the DisplaySpecifiers container. WCHAR szPath[MAX_PATH]; _snwprintf( szPath, MAX_PATH-1, L"LDAP://cn=%x,cn=DisplaySpecifiers,%s", DisplayNames::GetLocale(), pszConfigContext ); //Bind to the DisplaySpecifiers container. hr = ADsOpenObject(szPath, NULL, NULL, ADS_SECURE_AUTHENTICATION, //Use Secure Authentication IID_IDirectorySearch, (void**)&spDirSrch); // if no display specifiers found, change locale to English (if not already English) and try again if (FAILED(hr) && DisplayNames::GetLocale() != MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)) DisplayNames::SetLocale(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)); else break; } while (TRUE); EXIT_ON_FAILURE(hr); // Set search preferences ADS_SEARCHPREF_INFO prefInfo[3]; prefInfo[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE; // sub-tree search prefInfo[0].vValue.dwType = ADSTYPE_INTEGER; prefInfo[0].vValue.Integer = ADS_SCOPE_ONELEVEL; prefInfo[1].dwSearchPref = ADS_SEARCHPREF_ASYNCHRONOUS; // async prefInfo[1].vValue.dwType = ADSTYPE_BOOLEAN; prefInfo[1].vValue.Boolean = TRUE; prefInfo[2].dwSearchPref = ADS_SEARCHPREF_PAGESIZE; // paged results prefInfo[2].vValue.dwType = ADSTYPE_INTEGER; prefInfo[2].vValue.Integer = 64; EXIT_ON_FAILURE(spDirSrch->SetSearchPreference(prefInfo, 3)); static LPWSTR pAttr[] = {L"name", L"classDisplayName", L"iconPath"}; static LPWSTR pFilter = L"(&(objectCategory=displaySpecifier)(attributeDisplayNames=*))"; // Initiate search ADS_SEARCH_HANDLE hSearch = NULL; EXIT_ON_FAILURE(spDirSrch->ExecuteSearch(pFilter, pAttr, lengthof(pAttr), &hSearch)); // Get Results while (spDirSrch->GetNextRow(hSearch) == S_OK) { ADS_SEARCH_COLUMN col; CONTINUE_ON_FAILURE(spDirSrch->GetColumn(hSearch, const_cast(pAttr[0]), &col)); strIntName.erase(); strIntName = wcstok(col.pADsValues->PrintableString, L"-"); spDirSrch->FreeColumn(&col); CONTINUE_ON_FAILURE(spDirSrch->GetColumn(hSearch, const_cast(pAttr[1]), &col)); strFriendlyName.erase(); strFriendlyName = col.pADsValues->PrintableString; spDirSrch->FreeColumn(&col); m_map.insert(STRINGMAP::value_type(strIntName, strFriendlyName)); //add icon string to map ICONHOLDER IH; //if iconPath exists in the AD, copy the value to the ICONHOLDER structure if(SUCCEEDED(spDirSrch->GetColumn(hSearch, const_cast(pAttr[2]), &col))) { IH.strPath = col.pADsValues->PrintableString; spDirSrch->FreeColumn(&col); } //add the ICONHOLDER structure to the map (empty string for default types) m_msIcons.insert(std::pair(strFriendlyName, IH)); } spDirSrch->CloseSearchHandle(hSearch); } LPCWSTR DisplayNameMap::GetAttributeDisplayName(LPCWSTR pszname) { if( !pszname ) return L""; STRINGMAP::iterator it; if ((it = m_map.find(pszname)) != m_map.end()) return (*it).second.c_str(); else return pszname; } LPCWSTR DisplayNameMap::GetInternalName(LPCWSTR pszDisplayName) { if( !pszDisplayName ) return L""; STRINGMAP::iterator it; for (it = m_map.begin(); it != m_map.end(); it++) { if ((*it).second == pszDisplayName) return (*it).first.c_str(); } return pszDisplayName; } LPCWSTR DisplayNameMap::GetFriendlyName(LPCWSTR pszDisplayName) { if( !pszDisplayName ) return L""; STRINGMAP::iterator it; if((it = m_map.find(pszDisplayName)) != m_map.end()) return it->second.c_str(); return pszDisplayName; } void DisplayNameMap::GetFriendlyNames(string_vector* vec) { if( !vec ) return; STRINGMAP::iterator it; for (it = m_map.begin(); it != m_map.end(); it++) { vec->push_back((*it).first); } } // retreives a handle to the icon for the provided class // params: pszClassName - class name // returns: boolean success bool DisplayNameMap::GetIcons(LPCWSTR pszClassName, ICONHOLDER** pReturnIH) { if( !pszClassName || !pReturnIH ) return FALSE; static UINT iFreeIconIndex = RESULT_ITEM_IMAGE + 1; //next free virtual index static ICONHOLDER DefaultIH; //upon construction, this item holds default values *pReturnIH = &DefaultIH; //In the case of errors, returned icon will hold default icon std::map::iterator iconIter; ICONHOLDER *pIH; //pointer to the ICONHOLDER //CASE: Requested class not found in list returned by Active Directory if((iconIter = m_msIcons.find(pszClassName)) == m_msIcons.end()) { return false; } pIH = &(iconIter->second); //convenience variable to ICONHOLDER //CASE: Requsted icons already loaded if(pIH->bAttempted == true) { *pReturnIH = pIH; return true; } //CASE: An attempt to load the icon has not yet been made while(pIH->bAttempted == false) { //making first attempt pIH->bAttempted = true; //try to load the icon using the IDsDisplaySpecifier interface first IDsDisplaySpecifier *pDS; HRESULT hr = CoCreateInstance(CLSID_DsDisplaySpecifier, NULL, CLSCTX_INPROC_SERVER, IID_IDsDisplaySpecifier, (void**)&pDS); if( FAILED(hr) ) return false; //load all icon sizes and states tstring strIntClassName = GetInternalName(pszClassName); pIH->hSmall = pDS->GetIcon(strIntClassName.c_str(), DSGIF_ISNORMAL, 16, 16); pIH->hLarge = pDS->GetIcon(strIntClassName.c_str(), DSGIF_ISNORMAL, 32, 32); pIH->hSmallDis = pDS->GetIcon(strIntClassName.c_str(), DSGIF_ISDISABLED, 16, 16); pIH->hLargeDis = pDS->GetIcon(strIntClassName.c_str(), DSGIF_ISDISABLED, 32, 32); pDS->Release(); //CASE: Icon loaded from AD if(pIH->hSmall) break; //CASE: No file specified if(pIH->strPath.empty()) break; //tokenize the iconPath variable tstring strState = wcstok(const_cast(pIH->strPath.c_str()), L","); tstring strFile = wcstok(NULL, L","); tstring strIndex = wcstok(NULL, L","); int iIndex; //integer value of index //CASE: file is environment variable if(strFile.at(0) == L'%' && strFile.at(strFile.length()-1) == L'%') { //chop off '%' indicators strFile = strFile.substr(1, strFile.length()-2); int nSize = 512; WCHAR* pwszBuffer = new WCHAR[nSize]; if( !pwszBuffer ) break; DWORD dwSize = GetEnvironmentVariable( strFile.c_str(), pwszBuffer, nSize ); if( dwSize == 0 ) break; if( dwSize >= nSize ) { delete [] pwszBuffer; nSize = dwSize; pwszBuffer = new WCHAR[nSize]; if( !pwszBuffer ) break; dwSize = GetEnvironmentVariable( strFile.c_str(), pwszBuffer, nSize ); if( dwSize == 0 || dwSize >= nSize ) break; } strFile = pwszBuffer; } if(strIndex.empty()) { //CASE: ICO file specified pIH->hSmall = (HICON)LoadImage(NULL, strFile.c_str(), IMAGE_ICON, 16, 16, LR_LOADFROMFILE); pIH->hLarge = (HICON)LoadImage(NULL, strFile.c_str(), IMAGE_ICON, 32, 32, LR_LOADFROMFILE); } else { //CASE: DLL file specified iIndex = _wtoi(strIndex.c_str()); assert(iIndex <= 0); //in all known cases, the index is indicating an absolute reference HINSTANCE hLib = LoadLibraryEx(strFile.c_str(), NULL, LOAD_LIBRARY_AS_DATAFILE); if(hLib == NULL) break; pIH->hSmall = CopyIcon((HICON)LoadImage(hLib, MAKEINTRESOURCE(-iIndex), IMAGE_ICON, 16, 16, NULL)); pIH->hLarge = CopyIcon((HICON)LoadImage(hLib, MAKEINTRESOURCE(-iIndex), IMAGE_ICON, 32, 32, NULL)); FreeLibrary(hLib); } } //CASE: something failed. Fill with default values and return. if(pIH->hSmall == NULL) { pIH->hSmall = pIH->hSmallDis = NULL; pIH->hLarge = pIH->hLargeDis = NULL; pIH->iNormal = RESULT_ITEM_IMAGE; pIH->iDisabled = RESULT_ITEM_IMAGE; } //CASE: succeeded. Must assign permanent virtual index. else { pIH->iNormal = iFreeIconIndex++; pIH->iDisabled = pIH->hSmallDis ? iFreeIconIndex++ : pIH->iNormal; } *pReturnIH = pIH; return true; }