|
|
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.
|
|
On Nov 26, 3:53 am, Sergeichik <Sergeic...[ at ]discussions.microsoft.com> wrote:
[Quoted Text] > 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 ?
|
|
|
[Quoted Text] > It's best to leave the LDAP > terminology aside;
but it is standard Outlook terminology
|
|
|
|
On Dec 2, 11:19šam, Sergeichik <Sergeic...[ at ]discussions.microsoft.com> wrote:
[Quoted Text] > 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.
|
|
|