Accessing the Windows Address Book

Introduction

After releasing my first freeware product QuickE numerous request came in, to have the application integrate with the user's address book in their Windows Address Book. On Windows XP, you can find this application by clicking Start->Programs->Accessories->[click] Address Book. I was surprised that anyone was using Windows Address Book, as I was under the naive assumption that everyone uses Outlook or at least Outlook Express (since the latter is at least free), but to my astonishment a lot of people just use the normal Windows Address Book application that comes with most installation of Windows, and if you do use Outlook Express you can actually see that the address book is filled with the same address in Outlook Express. As soon as I started this task, the first thing I did was type in WAB (Windows Address Book) into my MSDN search facility, lo and behold my surprise, at the very small amount of information that was returned to me. I wrote this class in order for other people to have at least a starting point in accessing and using the WAB. I hope you find the source code useful.

System requirements

This code was written and tested in Visual Studio.NET using unmanaged C++ and Win XP Professional. Tony R. tested this code using Visual C++ 6 and was able to get it to run. If anyone else can run this on another platform, let us know so I can post it here, that would be great. Until I get confirmation that this class works in other development environments and on other operating systems, I will list only what I have tested on a first hand basis.

Accessing the WAB

In order to access the WAB you must first load the wab32.dll library and get the address to WAB open which also gives you pointers to the IAdrBook and IWABObject interfaces. Below is a code snippet on how I made this call:

ssWABOpen is a typedef to the WABOpen function. Something I came across when writing this is, finding out that when you typedef this function you must declare the calling mechanism as WINAPI or when compiling you will get a mismatch error.

After this I then call the object's LoadEmails() function. This private function called from within the InitAddrBook function, loads the emails into a UDT of objects within an STL::vector object. I decide to go this route, mainly because of more ignorance on my part, my address book is about 20 names and this method does not soak up too much system resources. If this does not work out for others, I will change it to something more system resource friendly.

Inside the LoadEmails() function is where all the email extraction from the WAB to my UDT vector takes place. You can modify or change this into something that would be more appropriate for your specific use. Or, extract the information into a more useful UDT other than the one I have created.

Usage and special functions

In order to give you a foundation of how to use the class, this is how I use the class in my current beta build of my application. In the main dialog's class I declare a private variable of class CWinAddrBook. I then initialize this variable inside of the dialogs class' OnInitDialog() function, by calling object.InitAddrBook member method. This does two things, first it loads the wab32.dll and then, retrieves from this, the address for the WABOpen() function.

In order to test this class before releasing and not having to build its on application container I created the member method TestAddr(). This basically takes the contents of the vector after you initialized it, and outputs it (TRACE) while running in debug mode to the output window, it then separates the output by carriage line feed pair. This way you are insured that something is actually in your vector and you can look at the output compared to your address book to insure that all the information transferred over correctly.

Request for comments/dilemmas

When creating this class, here are some strange things I came across, maybe someone could shed some light. First thing that caught me off guard is just by using MSDN documents I tried to only include wabapi.h, when in fact it is better to include just wab.h. By going with what is listed on the interface help sections all I saw was WABAPI and for a while I could not get it to compile.

When I first compiled it into my code, I kept getting a

error C2371: 'WCHAR' redfinition; different basic types

inside of wabdefs.h which is included when you specify wab.h. The work around I used was go into this file and around line line 77 I made this change in order to get my code to compile. I do not know why I had to do this or if it is even right, but it worked. If someone knows what this means I would be greatly appreciative of knowing why it does this.

#if !defined(UNIX) && !defined(WIN16) && !defined(WIN32)

LoadEmails() used to be a separate function that was called after InitAddr() however I kept getting an unhandled exception inside the OnInitDialog function. After removing the public function call to LoadEmails, and made it a private function called from within InitAddr() it works fine.

Contributors

Not MSDN! j/k Most of the contributors are included in the header file comments. I will also include here Hirosh for his article on Extracting Email ID's from an address book using Memory mapped file, and another author is anonymous. I got the code snippet from a friend, who said he found it on the Internet, and I have included it in the download file the way I received it. But if anyone knows the author's name or web address please let me know, so I can give him/her the proper credit.

Tony R. for testing out the code in Visual C++ 6 and finding numerous other bugs.

Revisions

1/2/2003: Updated code and changed the extraction process to extract information into separate areas instead of repeatedly extracting all address information to the name field. Changed the structure that holds addresses to use basic_string instead of a fixed sized array of characters to avoid buffer overrun problems I was experiencing.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

Share

About the Author

My real name is Sam I live in Monterey, California. I am currently unemployed - long story. I am trying to secure a job as a programmer in the Silicon Valley area of CA but so far no luck. Now with all this extra time I am writing code and learning concepts I have put off because I was too busy working

I have completed two of my programming goals: release software in the form of freeware, and write an article for CodeProject!

Currently i am writing one application which will get all vcards from WAB whcih are created after with in time frame. Here i am not able to get the creation time of the vcard. But there is macro PR_CREATION_TIME. How to get the creation time of a vcard?

From Microsoft MSDN Online ,I can create [mail users] and [distribution lists] in code ,But how to create [folder] in WAB ?
MSDN only that [ When a user creates a folder, the WAB creates an IABContainer : IMAPIContainer object. ]
How to create folder? Help me !! Thanks in advance!!

Change the setting "Treat wchar_t as Built-in Type" under Project --> Properties --> C/C++ --> Language to No. This variable is set to "Yes (/Zc:wchar_t)" by default when you create a new project. You do not need to modify any system include file. Why is this so? I don't know. But I think Microsoft has a little bug to fix right there.

First, very cool code... both yours and Vattila's. However, I needed to be able to extract birthdates as well as email addresses and other info from the WAB for an event managment project. Once I found the property codes listed in the wabtags.h file, the rest was fairly easy. The PR_BIRTHDAY property returns a PT_SYSTIME value which is a FILETIME datatype. However, when I convert the FILETIME structure to string for screen display, the date is ALWAYS one day short.

In other words, if you enter May 28, 2005 in the address book, the API will return May 27, 2005. Does anyone know why this occurs? I am compiling with VC++ 6.0 on a Windows 2000 system. I'm not sure if it's a OS bug, an API bug or what. Here is my conversion code:

Pretty straight-forward, eh? I don't think the error is here. It's no big deal to just add a day to the time COleDateTime value before doing string format, but this app runs on multiple platforms, so I'm wondering if anyone has experienced similar behavior on other platforms.

Dear All:
Have you ever encountered a problem like this?
In my program, I added these codes in a view's OnInitialUpdate function :
void CTestWABView::OnInitialUpdate(){
CFormView::OnInitialUpdate();
GetParentFrame()->RecalcLayout();
ResizeParentToFit();

I'm a newbie... I don't know how to add new contact to Address Book by code. In your source code and from MS does not show how to... It show the new item dialog box only.... I want to add it by my code!

Hey,
Finally managed to crack it. U can add contact details to the WAB using CreateEntry which does not display any Message Box . U can add contacts by code using IABContainer::CreateEntry Method. Check this link out n u ll get an idea on how to use it in ur code.

Thanks for your contribution. I searched the net for info and samples on the WAB API, and your code was one of few hits and a good starting point. That said, the code has some bugs:

Interfaces are not released. All acquired interfaces must be released, in particular IAddrBook, IWABObject, IABContainer and IMAPITable in your sample.

All buffers returned, i.e. all memory referred to by pointers to returned structures, as well as pointers within those structures, must be properly freed with IWABObject::FreeBuffer. In particular, lpEntryID is not freed in your sample.

There is a bug in WinAddrBook.cpp:149 where a static part of a struct is attempted freed: "FreeBuffer(lpRow)" should be "FreeBuffer(lpRow->lpProps)". This may have caused the "unhandled exception" errors you were getting. I got similar crashes.

I recommend taking a look at Microsoft's WAB Property Inspector Tool code sample to learn how to use the API safely. (If the link doesn't work, search Google for "wabtool".)

I have written a small encapsulation class for the address book that I use in my project. It uses C++ exception handling and the "resource acquisition is initialization" idiom to encapsulate and safely handle interfaces and buffer resources, even in case of errors/exceptions. If anyone is interested I'll make my code available. The code is fairly limited (adapted to my project's needs) but could serve as a sample and starting point.