C++ & Active Directory

Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain

Ответить
Kverter
Сообщения: 13
Зарегистрирован: 06 ноя 2013, 10:02

Всем здравствуйте!!! В общем возникла такая задача написать функции для работы с АД
1 функция должна получать sAMAccountName пользователя
2 функция должна получать UserPrincipalName пользователя
3 функция должна получить список групп безопасности в которых состоит пользователь
я смог это реализовать на VB на плюсах к сожелению пока не могу =( , ниже приведу то что пока сделал. Прошу помощи

Код: Выделить всё

int main()
{
	//IADs *pADs=NULL;
//VARIANT var;
	IADsContainer *pContainer;
HRESULT hr = S_OK;
LPWSTR path=L"LDAP://CN=xxxx,CN=xxxx,DC=xxxxDC=xxxx,DC=ru";
hr = ADsGetObject( path, IID_IADsContainer,(void**)&pContainer);
 cout<<"OK"<<endl;
 pContainer->get__NewEnum();
 system("PAUSE");
if(!(hr==S_OK)) {return hr;}
}
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Студии нет под рукой, но я раньше много работал с COM, могу рассказать на пальцах.

Во-первых, все COM интерфейсы порождены от IUnknown, который накладывает на COM объекты поведение автопоинтеров. Так что не забывай вызывать Release после того, как объект тебе уже стал не нужен.

Во-вторых, что дальше делать с get__NewEnum. Благодаря всё тому же IUnknown, все COM объекты умеют приводиться или не приводиться к указанному интерфейсу с помощью стандартного метода QueryInterface. Этот факт мы должны использовать следующим образом. Открываем help на интересующий метод get__NewEnum. Вот, что там написано о методе:
The IADsContainer::get__NewEnum method Retrieves an enumerator object for the container. The enumerator object implements the IEnumVARIANT interface to enumerate the children of the container object.
По поводу единственного параметра метода там говориться следующее:
ppEnumerator [ out ]
Pointer to an IUnknown pointer that receives the enumerator object. The caller must release this interface when it is no longer required.
Это значит, что мы можем написать следующий код:

Код: Выделить всё

IUnknown* pEnumUnkn = NULL;
pContainer->get__NewEnum(pEnumUnkn);
if (pEnumUnkn != NULL)
{
   IEnumVARIANT* pEnum = NULL;
   HRESULT hr = pEnumUnkn->QueryInterface(IID_IEnumVARIANT, &pEnum);
   if (hr == S_OK)
   {
      // work with enum
      pEnum->Release();
   }
   pEnumUnkn->Release();
}
Альтернатиный вариант - использовать хелпер функцию ADsBuildEnumerator, о которой написано в той же статье. В этом случае мы сразу получим указатель на IEnumVARIANT. Но нам нужно будет на забыть вызвать в конце ADSFreeEnumerator.

А вообще, очень печально работать с COM без всяких библиотек. Как видишь, получается очень много не несущего логической нагрузки кода. Рекомендую подключить к проекту ATL и использовать оттуда классы CComPtr (легковесная автопоинтер-обёртка с автоматическими вызовами AddRef/Release), CComQIPtr (то же самое, но в операторе присваивания автоматически делает QueryInterface), CComBSTR (для работы с BSTR строками) и прочие удобства библиотеки.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Kverter
Сообщения: 13
Зарегистрирован: 06 ноя 2013, 10:02

Подскажите как написать функцию для получения групп в которых состоит пользователь.
Есть наброска но она получает список из memberOf, и то я не могу вывести это на консоль.
вот код

Код: Выделить всё

VARIANT Group ()
{
	HRESULT hr;
	IADsADSystemInfo *pADsys;
BSTR bstr;
CoInitialize(NULL);
 hr = CoCreateInstance(CLSID_ADSystemInfo,
                              NULL,
                              CLSCTX_INPROC_SERVER,
                              IID_IADsADSystemInfo,
                             (void**)&pADsys);
 hr = pADsys->get_UserName(&bstr);
	IADs *pUsr=NULL;

USES_CONVERSION;
string strDesc = static_cast<CHAR*>(CW2A(bstr));

 string LDAP="LDAP://";
 string path = LDAP + strDesc;  
 wstring wstr( path.begin(), path.end() );

LPCTSTR path2 = W2CT( wstr.c_str( ) );
 //LPCWSTR path2 = (LPCWSTR)wstr;
hr = ADsGetObject( path2, IID_IADs,(void**)&pUsr);

VARIANT var;
VariantInit(&var);
hr = pUsr->Get(CComBSTR("memberOf"), &var );
return var;

получается что в переменной var создается массив, но она типа VARIANT как вывести массив можно?
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Уважаемый Kverter, вы так и не поняли из моего предыдущего поста, как пользоваться хелпом? :)

Хорошо, я распишу подробнее.

1. Открываем браузер, вводим в поле для адреса значение google.com.
2. На открывшейся странице в строке поиска пишем "IADs interface" и нажимаем "Искать".
3. Первая же ссылка ведёт на online MSDN, открываем эту ссылку.
4. Листаем открывшуюся страницу (можно даже особо не вчитываться) в самый низ, где находим прекрасные примеры для всех языков программирования, в том числе и для C++.
5. Там видим ответ на наш вопрос.

Код: Выделить всё

IADs *pSvc = NULL;
 
hr = ADsGetObject(L"WinNT://Fabrikam/Account/Browser,service", IID_IADs, (void**) &pSvc );
if ( !SUCCEEDED(hr) )
{
    return hr;
}
 
hr = pSvc->Get(CComBSTR("Dependencies"), &var );
if ( SUCCEEDED(hr) )
{
    LONG lstart, lend;
    SAFEARRAY *sa = V_ARRAY( &var );
    VARIANT varItem;
 
    // Get the lower and upper bound.
    hr = SafeArrayGetLBound( sa, 1, &lstart );
    hr = SafeArrayGetUBound( sa, 1, &lend );
 
    // Iterate and print the content.
    VariantInit(&varItem);
    printf("Getting service dependencies using IADs :\n");
    for ( long idx=lstart; idx <= lend; idx++ )
    {
        hr = SafeArrayGetElement( sa, &idx, &varItem );
        printf("%S ", V_BSTR(&varItem));
        VariantClear(&varItem);
    }
    printf("\n");
 
    VariantClear(&var);
}
 
// Cleanup.
if ( pSvc )
{
    pSvc->Release();
}
А ещё я рекоменду пересмотреть все эти ужасные преобразования из узких строк в широкие и обратно. Они там не нужны.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Ответить