Hi !

Could somebody help me how can I import email addresses from Windows Address Bok (wab) file programatically ?

The simplest code would be the best one, as I was able to found several but far too hard code to understand the hole issue.

Many many thanks for anybody concrete help.

Moore

Try this this really good :)

#include "StdAfx.h"
#include "winaddrbook.h"

CWinAddrBook::CWinAddrBook(void)
:lpWABObject(NULL),
lpAddrBook(NULL)
, IsInit(false)
{

	//Opens the default WAB file in the system and loads it into the object
	HINSTANCE hinstWAB=NULL;
	HRESULT hr=E_FAIL;
	HKEY keyResult;
	BYTE keyValue[MAX_PATH];
	DWORD dataout=800;

	RegOpenKeyEx(HKEY_LOCAL_MACHINE, WAB_DLL_PATH_KEY, 0, KEY_ALL_ACCESS, &keyResult); //"Software\\Microsoft\\WAB\\DLLPath"
	long result = RegQueryValueEx(keyResult, "", 0, 0, keyValue, &dataout);
	RegCloseKey(keyResult);

	//Get the full path of WAB and store in PathToWAB
	strcpy(PathToWAB, (char*)keyValue);

	//Now let us load the library
	hModule = LoadLibrary(PathToWAB);

}

CWinAddrBook::~CWinAddrBook(void)
{
	//Free the library we use to get the WAB file
	FreeLibrary(hModule);
	IsInit = false;
}

// Initialize the address book and basically open the address book
int CWinAddrBook::InitAddrBook(void)
{
	//After opening the library go ahead and try and get the values into memory
	//maybe implement a memory map file later depending on how big some on the 
	//performance of this class after release, and on some people's systems (i.e. huge address files)
	//
	// For now go ahead and store the information in a STL Vector

		if (hModule!=NULL)
		{
			//We're safe the module was initialzised let's do what we need to do
			ssWABOpen = (fWABOpen)GetProcAddress(hModule, "WABOpen");
			//If not successful throw an error throw the value = 2
			if (ssWABOpen == NULL) return 2;
			//It is successful call it
			HRESULT hr = (ssWABOpen)(&lpAddrBook, &lpWABObject, NULL, 0);
		}
		
		IsInit = true;
		LoadEmails(); //Moved here was being weird when called as another function from outsidethe class... hmmmm... go figure?!?

		//Everything was OK
		return 0;
}

// Load email addresses into the vector
int CWinAddrBook::LoadEmails(void)
{
	HRESULT hr = E_FAIL;

	if (ssWABOpen==NULL) return 1; //ssWABOpen cannot be NULL
	{
		ULONG lpcbEntryID;
		ENTRYID* lpEntryID;

		hr = lpAddrBook->GetPAB(&lpcbEntryID, &lpEntryID);
		if (hr!=S_OK) return 10; //error opening the darn PAB
		
		//Declare variables for MAPI and specific access to the PAB
		ULONG ulFlags = MAPI_BEST_ACCESS,
			  ulObjType = NULL;
		LPUNKNOWN lpIUnknown = NULL;
		hr = lpAddrBook->OpenEntry(lpcbEntryID,
								   lpEntryID,
								   NULL,
								   ulFlags,
								   &ulObjType,
								   &lpIUnknown);

		ulFlags = NULL; //We are using it again :)

		if (ulObjType==MAPI_ABCONT) //See if an address book container was passed which we are looking for
		{
			IABContainer* lpABContainer = static_cast<IABContainer*>(lpIUnknown); //cast the IUnknown pointer returned from previous function to what we need
			LPMAPITABLE lpMAPItbl = NULL;
			hr = lpABContainer->GetContentsTable(ulFlags, &lpMAPItbl);
			ASSERT(lpMAPItbl);
			
			ULONG ulRows; //Number of rows in the MAPI table (Addresses)
			hr = lpMAPItbl->GetRowCount(0, &ulRows);
				if (hr!=S_OK) return 11; //Return 11 to tell them we where unable to get the row count
			
			SRowSet* lpRowSet;
			hr = lpMAPItbl->QueryRows(		//Return all the rows found in the address book
									ulRows,
									0,
									&lpRowSet);
			
			//Grow variable
			AddrMemBook.resize(lpRowSet->cRows);
			//char Match[200]; strset(Match, 0);

			for (ULONG x = 0; x < lpRowSet->cRows; x++) 
			{
				//Loop through all the rows and add it to our address book
				//vector variable
				EMAILS thisAddr;											

				SRow* lpRow = &lpRowSet->aRow[x]; //Get this specific row
				for (ULONG y = 0; y < lpRow->cValues; y++)
				{
					//Loop through the fields in the address book and assign
					//to our variable and put it in the address book variable					
					SPropValue* lPropVal = &lpRow->lpProps[y];
					switch (lPropVal->ulPropTag)
					{
					case PR_DISPLAY_NAME_A:		
						thisAddr.DisplayName = lPropVal->Value.lpszA;						
						//strcpy(thisAddr->DisplayName, lPropVal->Value.lpszA);
						break;

					case PR_EMAIL_ADDRESS_A:						
						thisAddr.EmailAddr = lPropVal->Value.lpszA;
						if (strchr(thisAddr.EmailAddr.c_str(), '@')==NULL) //replace with empty string
							thisAddr.EmailAddr='\0';
						//strcpy(thisAddr->EmailAddr, lPropVal->Value.lpszA);						
						break;

					case PR_NICKNAME_A:						
						thisAddr.NickName = lPropVal->Value.lpszA;
						//strcpy(thisAddr->NickName, lPropVal->Value.lpszA);
						break;

					default:
						break;
					}

				}//End of cycling through fields
				//Add the information to the vector variable				
				if (!thisAddr.EmailAddr.empty()) 
					AddrMemBook.push_back(thisAddr);				

				lpWABObject->FreeBuffer(lpRow);

			}//End of cycling through rows
			lpWABObject->FreeBuffer(lpRowSet);
		}
	}

	return 0;
}

// Test mostly for debug purposes so you can step through and ensure that all the information is present for the address book vector
void CWinAddrBook::TestAddrBook(void)
{
	for (int x =0; x < (int)AddrMemBook.size(); x++)
	{
		//Set break here maybe later do a trace command instead
		EMAILS thisAddr = AddrMemBook[x];
		TRACE(thisAddr.DisplayName.c_str()); TRACE("\r\n");
		TRACE(thisAddr.EmailAddr.c_str()); TRACE("\r\n");
		TRACE(thisAddr.NickName.c_str()); TRACE("\r\n");
	}
}

Hi !

Many thanks, but this one I had found few weeks ago at Code project, and the trouble is that after it was able to compile, it runs perfectly, but as soon as I close the application it generates error.

I am 100% sure that it has bugs with freeing memory, but I wasnt able to find it.

Could you help me to compile and locate the problem ?

I had really tried all other possibilities and I got lost.

I had attached the complete project ZIPed for BCB, which I had been cleared and organised, so it run and compile perfectly, but this bloody memory issue.

Many thanks in advance,

Moore

I had the same problem with the code. I replaced the memory management calls with more appropriate ones (I guess they are ...)

>>>>>>>>>
// Add the information to the vector variable
if (!thisAddr.EmailAddr.empty())
this->AddrMemBook.push_back(thisAddr);


// lpWABObject->FreeBuffer(lpRow);


} // End of cycling through rows


// the destroys an SRowSet structure and frees associated memory i.e. all the rows
FreeProws(lpRowSet);  // ##############
// lpWABObject->FreeBuffer(lpRowSet);


if (lpABContainer != NULL)   // ############
lpABContainer->Release();
} // if (ulObjType == MAPI_ABCONT)


<<<<<<<<<<<


... also release the interface ...


and released passed interfaces in the destructor


>>>>>>>>>>>


CWinAddrBook::~CWinAddrBook(void)
{
// Free the library we use to get the WAB file



//  Causes execption when freeing the library
//  Look for using DLLs in AX Components !!!
this->lpAddrBook->Release();  // +++++++++++++++++++
this->lpWABObject->Release(); // ++++++++++++++++++


if (hModule != NULL)
FreeLibrary(hModule);


IsInit = false;
}


<<<<<<<<<<<

I hope thad you have already fixed minor bug with 'Growing the vector'
which caused empty entries in the vector ...
and either commented it out or even added

AddrMemBook.clear();

Myself, I created an ActiveX Dll and used this code in it without any problem ( ... so far ) ...

... hope it helps

Edited 3 Years Ago by happygeek: fixed formatting

=======================================================
I hope thad you have already fixed minor bug with 'Growing the vector'
which caused empty entries in the vector ...
and either commented it out or even added

AddrMemBook.clear();

Myself, I created an ActiveX Dll and used this code in it without any problem ( ... so far ) ...

... hope it helps

Hi !

Extremely thanks for your post, as I got lost completely. Could you do me a big big favour and post the complete BCB code zipped or send it to my email please : coolice@freemail.hu

Many many thanks in advance,

Moore

Hello.
Please, say, how can I obtain a contact's Birthdate? The standart export from Addres Book does not export it.

If I'm writing a code, there is a property PR_BIRTHDATE.
How do I convert it to the text string and write anywhere, like
Edit3.Text = lpProp->Value.(something here) ?;

Besides, why does MSDN say "Do not use" about all that WAB stuff like WABOpen()?

Hello.
Please, say, how can I obtain a contact's Birthdate? The standart export from Addres Book does not export it.

If I'm writing a code, there is a property PR_BIRTHDATE.
How do I convert it to the text string and write anywhere, like
Edit3.Text = lpProp->Value.(something here) ?;

Besides, why does MSDN say "Do not use" about all that WAB stuff like WABOpen()?

Don't reply to a 5 year old thread, start your own.

This article has been dead for over six months. Start a new discussion instead.