Comment modifier l'attribut ThumbnailPhoto d'un objet utilisateur dans Active Directory à l’aide de la fonction IADs::PutEx()

Bonjour,

Une fois n’est pas coutume, cet article va parler de C++.

L’interface IADsUser permet de mettre à jour la photo d’un utilisateur dans l’Active Directory à l’aide de la méthode Put_Picture.
Toutefois il est aussi possible de passer par la fonction IADs::PutEx qui a le mérite d’être générique. En effet cette function prend 3 paramètres qui sont dans l’ordre :

  1. Une énumération indiquant l’action à faire : ajout, suppression, remplacement, … de la valeur.
  2. Une chaine de caractères contenant le nom de l’attribut Active Directory que l'on souhaite ajouter / modifier / supprimer.
  3. La (les) nouvelle(s) valeur(s) passée(s) dans un tableau de VARIANT.

Pour plus d’informations, je vous invite à vous référer à la documentation MSDN de cette fonction.

Après quelques heures de recherches pour mettre à jour l’attribut ThumbnailPhoto via cette fonction, je partage le fruit de mes recherches afin d’éviter à d’autres personnes de perdre du temps….

 

Nous allons procéder en 5 étapes via une simple application console :

  1. Lecture de l’image et stockage dans un tableau d’octets.
  2. Conversion du tableau d’octets en tableau de VARIANT.
  3. Création d’un tableau de VARIANT à 1 dimension contenant l’image convertie à l’étape précédente (la fonction PutEx attend un tableau de VARIANT contenant la ou les valeurs à passer).
  4. Appel de la fonction PutEx (qui ne modifie la valeur que dans le cache des propriétés ADSI).
  5. Appel de la fonction SetInfo afin de répercuter les changements dans l’Active Directory.

 

Commençons par le code permettant de convertir le tableau d’octets (contenant notre image) en tableau de VARIANT. Cette méthode vient de cet article MSDN :

 /********************************************************************
 
    BytesToVariantArray()
 
    Converts an array of BYTEs into a VARIANT array.
 
    Parameters:
 
    pValue = Contains an array of BYTES to convert. cValueElements 
    contains the number of elements in this array.
 
    cValueElements - Contains the number of elements in the pValue
    array.
 
    pVariant - Receives the VARIANT that contains an octet string
    (VT_UI1 | VT_ARRAY)
 
*********************************************************************/
 
HRESULT BytesToVariantArray(
    PBYTE pValue,
    ULONG cValueElements,
    VARIANT *pVariant
    )
{
    HRESULT hr = E_FAIL;
    SAFEARRAY *pArrayVal = NULL;
    SAFEARRAYBOUND arrayBound;
    CHAR HUGEP *pArray = NULL;
 
    // Check parameters.
    if((NULL == pValue) || !(cValueElements > 0))
    {
        return E_INVALIDARG;
    }
 
    // Set bound for array.
    arrayBound.lLbound = 0;
    arrayBound.cElements = cValueElements;
 
    // Create the safe array for the octet string. unsigned char
    // elements;single dimension;aBound size.
    pArrayVal = SafeArrayCreate(VT_UI1, 1, &arrayBound);
 
    if (!(NULL == pArrayVal))
    {
        hr = SafeArrayAccessData(pArrayVal,
                                 (void HUGEP * FAR *) &pArray);
        if (SUCCEEDED(hr))
        {
            // Copy the bytes to the safe array.
            memcpy(pArray, pValue, arrayBound.cElements);
            SafeArrayUnaccessData(pArrayVal);
            
            // Set type to array of unsigned char.
            V_VT(pVariant) = VT_ARRAY | VT_UI1;
            
            // Assign the safe array to the array member.
            V_ARRAY(pVariant) = pArrayVal;
            
            hr = S_OK;
        }
        else
        {
            // Cleanup if the array cannot be accessed.
            if (pArrayVal)
            {
                SafeArrayDestroy(pArrayVal);
            }
        }
    }
    else
    {
      hr = E_OUTOFMEMORY;
    }
 
    return hr;
}
  

Le code pour les autres étapes est regroupé dans le main :

 int _tmain(int argc, _TCHAR* argv[])
{
 CoInitialize(NULL);
 HRESULT ret=E_FAIL;
 
   int hfile = _open("c:\\temp\\MonImage.jpg", _O_BINARY | _O_RDONLY );
  long iFileSize = _lseek( hfile, 0l, SEEK_END);              
    LPBYTE lpbPicture = (LPBYTE)malloc( iFileSize );
   _lseek( hfile, 0l, SEEK_SET);
    long bRead = _read( hfile, lpbPicture, iFileSize);
 
 
 
   try
   {
       IADsUser * infoUser=NULL;
     ret=ADsOpenObject(L"LDAP://Le_Chemin_LDAP_Vers_Le_User",NULL,NULL,ADS_SECURE_AUTHENTICATION,IID_IADsUser,(void**)&infoUser);
     if (FAILED(ret))
     {           
            throw std::string("Erreur ADsOpenObject");
      }
 
      VARIANT var;
       VariantInit(&var);
      //Conversion du tableau d'octets en VARIANT
      BytesToVariantArray(lpbPicture, iFileSize, &var);
 
       //Création du tableau de VARIANT à 1 dimension
     VARIANT varArr;
        VariantInit(&varArr);
       varArr.vt = VT_ARRAY | VT_VARIANT;
 
     SAFEARRAY* pSafArr;
        SAFEARRAYBOUND safArrBnds = {1, 0};
     pSafArr = SafeArrayCreate(VT_VARIANT, 1, &safArrBnds);   
 
       VARIANT* inputArray;
       SafeArrayAccessData(pSafArr, reinterpret_cast<void**>(&inputArray));
                 //Affectation du VARIANT contenant l'image dans le tableau de VARIANT
      inputArray[0] = var;
      SafeArrayUnaccessData(pSafArr);
     varArr.parray = pSafArr;
 
 
      //Appel de la fonction PutEx en lui passant le tableau de VARIANT
       ret = infoUser->PutEx (ADS_PROPERTY_UPDATE, L"thumbnailPhoto",varArr);
      if (FAILED(ret))
     {           
            throw std::string("Erreur PutEx ");
     }  
  
                 //Appel de la fonction SetInfo 
        ret=infoUser->SetInfo();
     if (FAILED(ret))
     {           
            throw std::string("Erreur SetInfo");
        }
   
    }
   catch (_com_error &e)
   {
       _bstr_t exDescription=e.Description();
     wprintf(L"com_error : %s", exDescription.GetBSTR());
 
 }
   catch(const std::string& Msg)
 {
       wprintf(L"Exception : %S\n",Msg.c_str());
  }
 
  _getch();
 
  return 0;
}
  
 A bientôt,
 Aurélien