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.
466 lines
14 KiB
466 lines
14 KiB
#include "stdafx.h"
|
|
#include "namemap.h"
|
|
#include "query.h"
|
|
#include "assert.h"
|
|
|
|
#include <iostream>
|
|
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<IADsClass> 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<IADs> 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<IDirectorySearch> 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<LPWSTR>(pAttr[0]), &col));
|
|
|
|
strIntName.erase();
|
|
strIntName = wcstok(col.pADsValues->PrintableString, L"-");
|
|
spDirSrch->FreeColumn(&col);
|
|
|
|
CONTINUE_ON_FAILURE(spDirSrch->GetColumn(hSearch, const_cast<LPWSTR>(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<LPWSTR>(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<tstring, ICONHOLDER>(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<tstring, ICONHOLDER>::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<wchar_t*>(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;
|
|
}
|