LDAP access

  • Thread starter Thread starter Sergeichik
  • Start date Start date
S

Sergeichik

I'm trying to read AD(Active directory) content from Outlook addin (C++,
MAPI) by the following way:
(AD's in Outlook are represented by LDAP, and neither I nor plugin don't
know their logins or passwords, hidden somewhere in depth of Outlook internal
data)

accessing containers:
//////////////////////////////////////////////
HRESULT hr;
CComPtr<IMAPISession> pSess;
hr = MAPILogonEx(0, NULL, NULL, MAPI_EXTENDED|MAPI_UNICODE, &pSess);
if(FAILED(hr))
{
errorMes = _T("MAPI Logon failed.");
return false;
}
// open address book
CComPtr<IAddrBook> pAddr;
hr = pSess->OpenAddressBook(0, 0, 0, &pAddr);
if(FAILED(hr))
{
pSess->Logoff(0, 0, 0);
return false;
};

LPSRowSet containers;
hr = pAddr->GetSearchPath(MAPI_UNICODE , &containers);
if (hr!=S_OK)
{
pAddr.Release();
pSess->Logoff(0, 0, 0);
return false;
}

// number of folders in address book
long cont_count = containers->cRows;
if (cont_count <= 0)
{
pAddr.Release();
pSess->Logoff(0, 0, 0);
return false;
}


for (int folder_number = 0; folder_number < cont_count; folder_number++)
{
WCHAR tx [30];
_itow(folder_number, tx, 10);
CAtlString f_mess = _T("Processing folder number '");
f_mess += CAtlString(tx); f_mess += _T("' from address book.");


SRow* folder_row = &containers->aRow[folder_number];
if (!folder_row)
{
continue;
}

LPSPropValue lpDN_cont =
PpropFindProp(folder_row->lpProps,folder_row->cValues,PR_ENTRYID);
if (!lpDN_cont)
{
continue;
}

_PV* ContainerEntryId = NULL;
ContainerEntryId = &lpDN_cont->Value;
if (!ContainerEntryId)
{
continue;
}
ReadContainerContents(pAddr, ContainerEntryId);
}

///////////////////////////////////////////////////////////////////////////////
// reading container ..
void ReadContainerContents(CComPtr<IAddrBook>& pAddr, _PV* ContainerEntryId)
{

HRESULT hr = S_OK;
ULONG ulCount = NULL;
LPSRowSet pRows = NULL;
ULONG cbeid = 0L;
LPENTRYID lpeid = NULL;
LPMAPITABLE lpMAPItbl = NULL;
LPABCONT lpGAL = NULL;


if ((pAddr == NULL)||(ContainerEntryId == NULL)) return;

// SizedSPropTagArray(2, Columns) =
// {2, {PR_ENTRYID, PR_DISPLAY_TYPE}};

LPUNKNOWN lpIUnknown = NULL;
ULONG ulObjType = NULL;

if (FAILED(pAddr->OpenEntry(ContainerEntryId->bin.cb,
(LPENTRYID)ContainerEntryId->bin.lpb, NULL, MAPI_BEST_ACCESS,
&ulObjType, (LPUNKNOWN*)&lpIUnknown)))
{
return;
}

//See if it is an address book container
// If no, return ...
if (ulObjType != MAPI_ABCONT))
{
return;
}


ULONG ulFlags = NULL;
IABContainer* lpABContainer = static_cast<IABContainer*>(lpIUnknown);
//cast the IUnknown pointer returned from previous function to what we need
hr = lpABContainer->GetContentsTable(ulFlags, &lpMAPItbl);
// ASSERT(lpMAPItbl);
if (hr!=S_OK)
{
if (lpABContainer) lpABContainer->Release();
return;
}

ULONG ulRows; //Number of rows in the MAPI table

hr = lpMAPItbl->GetRowCount(0, &ulRows);
if (hr!=S_OK)
{
if (lpMAPItbl) lpMAPItbl->Release();
if (lpABContainer) lpABContainer->Release();
return;
}

if (ulRows <= 0)
{
// MessageBox("No contacts was finded");
if (lpMAPItbl) lpMAPItbl->Release();
if (lpABContainer) lpABContainer->Release();
return;
}

// ... process here founded contacts ..

}
/////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////

But haven't any success in case of AD!!
I can read the names of AD LDAP directories(by such a way) as well as usual
local 'Address book' folders,
but if I try to read the count of contacts in them, I receive 0(zero).
Though, local folders quering return valid number of contcts (not zero) and
then I can read all of them fully.
Sure, there are some contacts in my LDAP directory exist certain and can be
viewed from the Outlook contacts book !!
And I can access them through another technology (ADO).
But need through MAPI(for example), without knowing login and password which
is already stored somewhere in Outlook and I don't authorized to know them.
Best regards, SergK.
 
I'm trying to read AD(Active directory) content from Outlook addin (C++,
MAPI) by the following way:
(AD's in Outlook are represented by LDAP, and neither I nor plugin don't
know their logins or passwords, hidden somewhere in depth of Outlook internal
data)

accessing containers:
//////////////////////////////////////////////
  HRESULT hr;
  CComPtr<IMAPISession> pSess;
  hr = MAPILogonEx(0, NULL, NULL, MAPI_EXTENDED|MAPI_UNICODE, &pSess);
  if(FAILED(hr))
  {
          errorMes = _T("MAPI Logon failed.");
          return false;
  }
  // open address book
  CComPtr<IAddrBook> pAddr;
  hr = pSess->OpenAddressBook(0, 0, 0, &pAddr);
  if(FAILED(hr))
  {
    pSess->Logoff(0, 0, 0);
    return false;
  };

        LPSRowSet containers;
        hr = pAddr->GetSearchPath(MAPI_UNICODE , &containers);
        if (hr!=S_OK)
        {
                    pAddr.Release();
                    pSess->Logoff(0, 0, 0);
                    return false;
        }

        // number of folders in address book
        long cont_count = containers->cRows;
        if (cont_count <= 0)
        {
                pAddr.Release();
                pSess->Logoff(0, 0, 0);
                return false;
        }

        for (int folder_number = 0; folder_number < cont_count;folder_number++)
        {
            WCHAR tx [30];
            _itow(folder_number, tx, 10);
            CAtlString f_mess = _T("Processing folder number '");    
            f_mess += CAtlString(tx); f_mess += _T("' from address book.");

                SRow* folder_row = &containers->aRow[folder_number];
                if (!folder_row)
                {
                        continue;
                }

                LPSPropValue lpDN_cont =
PpropFindProp(folder_row->lpProps,folder_row->cValues,PR_ENTRYID);
                if (!lpDN_cont)
                {
                        continue;
                }

                _PV* ContainerEntryId = NULL;
                ContainerEntryId = &lpDN_cont->Value;
                if (!ContainerEntryId)
                {
                        continue;
                }
                ReadContainerContents(pAddr, ContainerEntryId);
        }

///////////////////////////////////////////////////////////////////////////////
// reading container ..
void ReadContainerContents(CComPtr<IAddrBook>& pAddr, _PV* ContainerEntryId)
{

    HRESULT      hr = S_OK;
    ULONG      ulCount = NULL;
    LPSRowSet      pRows =   NULL;
    ULONG cbeid = 0L;
    LPENTRYID lpeid = NULL;
    LPMAPITABLE lpMAPItbl = NULL;
    LPABCONT lpGAL = NULL;

        if ((pAddr == NULL)||(ContainerEntryId == NULL)) return;

//      SizedSPropTagArray(2, Columns) =
//              {2, {PR_ENTRYID, PR_DISPLAY_TYPE}};

                LPUNKNOWN lpIUnknown = NULL;
                ULONG ulObjType = NULL;

                if (FAILED(pAddr->OpenEntry(ContainerEntryId->bin.cb,
(LPENTRYID)ContainerEntryId->bin.lpb, NULL, MAPI_BEST_ACCESS,
                                                     &ulObjType, (LPUNKNOWN*)&lpIUnknown)))
                  {
                          return;
                  }

//See if it is an address book container  
        // If no, return ...
                if (ulObjType != MAPI_ABCONT))
                {
                        return;
                }

                ULONG ulFlags = NULL;
                IABContainer* lpABContainer = static_cast<IABContainer*>(lpIUnknown);
//cast the IUnknown pointer returned from previous function to what we need
                hr = lpABContainer->GetContentsTable(ulFlags, &lpMAPItbl);
//              ASSERT(lpMAPItbl);
                if (hr!=S_OK)
                {
                        if (lpABContainer) lpABContainer->Release();
                        return;
                }

                ULONG ulRows; //Number of rows in the MAPI table

                hr = lpMAPItbl->GetRowCount(0, &ulRows);
                if (hr!=S_OK)
                {
                        if (lpMAPItbl) lpMAPItbl->Release();
                        if (lpABContainer) lpABContainer->Release();
                        return;
                }

                if (ulRows <= 0)
                {
//                  MessageBox("No contacts was finded");
                        if (lpMAPItbl) lpMAPItbl->Release();
                        if (lpABContainer) lpABContainer->Release();
                        return;
                }

//              ... process here founded contacts ..

}

/////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////

But haven't any success in case of AD!!
I can read the names of AD LDAP directories(by such a way) as well as usual
local 'Address book' folders,
        but if I try to read the count of contacts in them, I receive 0(zero).
Though, local folders quering return valid number of contcts (not zero) and
then I can read all of them fully.
Sure, there are some contacts in my LDAP directory exist certain and can be
viewed from the Outlook contacts book !!
And I can access them through another technology (ADO).
But need through MAPI(for example), without knowing login and password which
is already stored somewhere in Outlook and I don't authorized to know them.
Best regards, SergK.

You're looking for the Global Address List (GAL), which is a MAPI
interface onto the Global Catalog (GC). It's best to leave the LDAP
terminology aside; that's what's going on underneath, but it's not
going to help you understand what you need to do in MAPI. In
psuedocode, what you want to do is:

session->OpenAddressBook( &ab);
ab->OpenEntry( 0, NULL, NULL, 0, ..., &rootContainer); //Open the root
container by passing a NULL entry ID
rootContainer->GetHierarchyTagble( &table); //Get the container table

The rest is actual code:

SizedSPropTagArray( 1, columns) = { 1, PR_ENTRYID};

SPropValue criteria[ 2];
SRestriction restrictions[ 2];
SRestriction andNode;

criteria[ 0].ulPropTag = PR_AB_PROVIDER_ID;
criteria[ 0].Value.bin.cb = 16;
const BYTE muid[] = MUIDEMSAB;
criteria[ 0].Value.bin.lpb = (BYTE *) muid;
restrictions[ 0].rt = RES_PROPERTY;
restrictions[ 0].res.resProperty.relop = RELOP_EQ;
restrictions[ 0].res.resProperty.ulPropTag = PR_AB_PROVIDER_ID;
restrictions[ 0].res.resProperty.lpProp = &criteria[ 0];

criteria[ 1].ulPropTag = PR_EMS_AB_CONTAINERID;
criteria[ 1].Value.l = 0;
restrictions[ 1].rt = RES_PROPERTY;
restrictions[ 1].res.resProperty.relop = RELOP_EQ;
restrictions[ 1].res.resProperty.ulPropTag = PR_EMS_AB_CONTAINERID;
restrictions[ 1].res.resProperty.lpProp = &criteria[ 1];

andNode.rt = RES_AND;
andNode.res.resAnd.cRes = 2;
andNode.res.resAnd.lpRes = &restrictions[ 0];

CMapiAbContainer *retval = NULL;
LPSRowSet rows = NULL;
if( SUCCEEDED( LogMapiResult( HrQueryAllRows( table,
(LPSPropTagArray) &columns, &andNode, NULL, 0, &rows), table, _T
( "HrQueryAllRows on IABContainer hierarchy table"))))
{
if( rows->cRows)
{
if( rows->cRows > 1)
LogEntry( cLogError, _T( "Found %d entries matching GAL
properties"), rows->cRows);

LPABCONT mapiContainer = NULL;
ULONG objectType = 0;
hResult = LogMapiResult( GetContainer()->OpenEntry( rows->aRow
[ 0].lpProps[ 0].Value.bin.cb, (LPENTRYID) rows->aRow[ 0].lpProps
[ 0].Value.bin.lpb, NULL, GetMapiSession()->GetAccessFlags(),
&objectType, (LPUNKNOWN *) &mapiContainer), GetContainer(), _T
( "IABContainer::OpenEntry"));
if( SUCCEEDED( hResult))
{
assert( objectType == MAPI_ABCONT);
*gal = new CMapiAbContainer( mMapiSession, mapiContainer);
hResult = S_OK;
}
}
else
{
LogEntry( cLogError, _T( "No entries matching GAL properties
found"));
hResult = MAPI_E_NOT_FOUND;
}
FreeProws( rows);
}

You're doing a restriction on the AB containers inside the address
book to find the GAL, then opening it.

Here's the definition of MUIDEMSAB:

#ifndef MUIDEMSAB
#define MUIDEMSAB { 0xDC, 0xA7, 0x40, 0xC8, 0xC0, 0x42, 0x10, 0x1A,
0xB4, 0xB9, 0x08, 0x00, 0x2B, 0x2F, 0xE1, 0x82}
#endif
 
I have write:

bool ReadAD()
{

// Initialize MAPI.
HRESULT hRes = S_OK;

if (FAILED(hRes = MAPIInitialize(NULL)))
{
return false;
}

HRESULT hr;
LPMAPISESSION pSess;
hr = MAPILogonEx(0, NULL, NULL, MAPI_EXTENDED, &pSess);
if(FAILED(hr))
{
MAPIUninitialize();
return false;
}

// open address book
LPADRBOOK pAddr;
hr = pSess->OpenAddressBook(0, 0, 0, &pAddr);
if(FAILED(hr))
{
pSess->Logoff(0, 0, 0);
MAPIUninitialize();
return false;
};

// open root container by passing a NULL entry ID
ULONG obj_type;
LPMAPICONTAINER rootContainer = NULL;
hr = pAddr->OpenEntry( 0, NULL, NULL, 0, &obj_type,
(LPUNKNOWN*)&rootContainer);

//Get рierarchy table
LPMAPITABLE hierh_table;
hr = rootContainer->GetHierarchyTable(0, &hierh_table);

//The rest is actual code:
SizedSPropTagArray( 1, columns) = { 1, PR_ENTRYID};

SPropValue criteria[ 2];
SRestriction restrictions[ 2];
SRestriction andNode;

criteria[ 0].ulPropTag = PR_AB_PROVIDER_ID;
criteria[ 0].Value.bin.cb = 16;
const BYTE muid[] = MUIDEMSAB;
criteria[ 0].Value.bin.lpb = (BYTE *) muid;
restrictions[ 0].rt = RES_PROPERTY;
restrictions[ 0].res.resProperty.relop = RELOP_EQ;
restrictions[ 0].res.resProperty.ulPropTag = PR_AB_PROVIDER_ID;
restrictions[ 0].res.resProperty.lpProp = &criteria[ 0];

criteria[ 1].ulPropTag = PR_EMS_AB_CONTAINERID;
criteria[ 1].Value.l = 0;
restrictions[ 1].rt = RES_PROPERTY;
restrictions[ 1].res.resProperty.relop = RELOP_EQ;
restrictions[ 1].res.resProperty.ulPropTag = PR_EMS_AB_CONTAINERID;
restrictions[ 1].res.resProperty.lpProp = &criteria[ 1];

andNode.rt = RES_AND;
andNode.res.resAnd.cRes = 2;
andNode.res.resAnd.lpRes = &restrictions[ 0];

LPSRowSet rows = NULL;

if( SUCCEEDED( HrQueryAllRows( hierh_table,
(LPSPropTagArray) &columns, &andNode, NULL, 0, &rows)))
{
if( rows->cRows)
{
int rows_count = rows->cRows;
}
FreeProws( rows);
}

if (hierh_table) hierh_table->Release();
if (rootContainer) rootContainer->Release();
if (pAddr) pAddr->Release();
if (pSess) pSess->Release();

MAPIUninitialize();

return true;
}


But rows_count is 0, although Outlook have connected AD with several
contacts in it.

What's wrong ?
 
I have write:

bool ReadAD()
{

// Initialize MAPI.
HRESULT hRes = S_OK;

if (FAILED(hRes = MAPIInitialize(NULL)))
{
š š š š return false;

}

HRESULT hr;
LPMAPISESSION pSess;
hr = MAPILogonEx(0, NULL, NULL, MAPI_EXTENDED, &pSess);
if(FAILED(hr))
{
š š š š MAPIUninitialize();
š š š š return false;

}

// open address book
LPADRBOOK pAddr;
hr = pSess->OpenAddressBook(0, 0, 0, &pAddr);
if(FAILED(hr))
{
š š š š pSess->Logoff(0, 0, 0);
š š š š MAPIUninitialize();
š š š š return false;

};

// open root container by passing a NULL entry ID
ULONG obj_type;
LPMAPICONTAINER rootContainer = NULL;
hr = pAddr->OpenEntry( 0, NULL, NULL, 0, &obj_type,
(LPUNKNOWN*)&rootContainer);

//Get Òierarchy table
LPMAPITABLE hierh_table;
hr = rootContainer->GetHierarchyTable(0, &hierh_table);

//The rest is actual code:
SizedSPropTagArray( 1, columns) = { 1, PR_ENTRYID};

SPropValue criteria[ 2];
SRestriction restrictions[ 2];
SRestriction andNode;

criteria[ 0].ulPropTag = PR_AB_PROVIDER_ID;
criteria[ 0].Value.bin.cb = 16;
const BYTE muid[] = MUIDEMSAB;
criteria[ 0].Value.bin.lpb = (BYTE *) muid;
restrictions[ 0].rt = RES_PROPERTY;
restrictions[ 0].res.resProperty.relop = RELOP_EQ;
restrictions[ 0].res.resProperty.ulPropTag = PR_AB_PROVIDER_ID;
restrictions[ 0].res.resProperty.lpProp = &criteria[ 0];

criteria[ 1].ulPropTag = PR_EMS_AB_CONTAINERID;
criteria[ 1].Value.l = 0;
restrictions[ 1].rt = RES_PROPERTY;
restrictions[ 1].res.resProperty.relop = RELOP_EQ;
restrictions[ 1].res.resProperty.ulPropTag = PR_EMS_AB_CONTAINERID;
restrictions[ 1].res.resProperty.lpProp = &criteria[ 1];

andNode.rt = RES_AND;
andNode.res.resAnd.cRes = 2;
andNode.res.resAnd.lpRes = &restrictions[ 0];

LPSRowSet rows = NULL;

if( SUCCEEDED( HrQueryAllRows( hierh_table,
š (LPSPropTagArray) &columns, &andNode, NULL, 0, &rows)))
{
š š š š if( rows->cRows)
š š š š {
š š š š š š int rows_count = rows->cRows;
š š š š }
š š š š FreeProws( rows);

}

if (hierh_table) hierh_table->Release();
if (rootContainer) rootContainer->Release();
if (pAddr) pAddr->Release();
if (pSess) pSess->Release();

MAPIUninitialize();

return true;

}

But rows_count is 0, although Outlook have connected AD with several
contacts in it.

What's wrong ?

Look through your address book containers using OutlookSpy/MFCMAPI or
else take out the restriction and dump those properties for all the
rows and see what's not matching up. You're looking for a container
which is probably called "Global Address List", but querying by name
is unwise.
 
Back
Top