Code examples of MSOutlook automation in C++

first you need a properly set up app or dll ...find out how to do that here.

Lets start with a simple simple program. But first a NOTE: these are all code snippets.. I personally place all this code in the OnAboutXXX() function that gets created by the app wizard when i create the project. That way i know all the automation stuff has finished loading and i have control over when it runs without writing a single line of mfc code..(of course u can insert it wherever you want in your code, just make sure the automation stuff has all been initialised prior to you running this code.)

	_DApplication da;  //create an application object.

	//now run a copy of Outlook or attach to an existing copy
	if(!da.CreateDispatch("Outlook.Application"))
		return FALSE; //perhaps Outlook doesnt exist on this computer?
	else da.Quit(); //Quit the application.
	
	return true;  //success!

Thats a really boring snippet of code, it doesnt do much.. and it hasn't helped you get at any of the information within Outlook.. let us venture a little farther:


	_DApplication da; //create instance of Outlook object.
	
	//get a handle on the Outlook dlls
	if(!da.CreateDispatch("Outlook.Application"))
		return FALSE;
	//get the contacts folder from the proper namespace.
	NameSpace ns(da.GetNamespace("MAPI"));	
	//get contacts folder.
	// for all the magic-number constants see Outlook Constants.
	MAPIFolder cf(ns.GetDefaultFolder(10));// 10 = constant associated with Contacts folder i found this in msdn VBA documentation.

	cf.Display(); //pop up the Contacts folder.

At least now it is visually stimulating :) and you know you have gotten somewhere. Lets examine the contents of the Contacts folder:

	_DApplication da;

	if(!da.CreateDispatch("Outlook.Application"))
		return FALSE;

	NameSpace ns(da.GetNamespace("MAPI"));	

	MAPIFolder cf(ns.GetDefaultFolder(10));

	// get a list of all the _DContactItem s in the Contacts folder.
	Items is( cf.GetItems() );

	// grab the first _DContactItem
	//
	// Items::Item() takes a location that is > 0 and <= Items::GetCount()
	// and returns an LPDISPATCH to the corresponding Item.
	// or throws an exception or something if the item doesnt exist...
	//  i forget.
	_DContactItem firstContact( is.Item(COleVariant((short)1)) );
	
	firstContact.Display(); //show off our new toy

Now we know we can get @ the information. two comments to make here. The first is about COleVariant():
COleVariant seems to be a nifty casting function for translating normal types into VARIANTs which OLE objects understand nice n easy. COleVariant calls have worked for me with shorts and CStrings.. i don't think i've tried anything else, i cast all ints to shorts before sending them to COleVariant because i saw some code that did that and it seems to work :)

Second point: these first few examples assume that everything is working okee but if you want/need to be more cautious you can make use of LPDISPATCH variables and the AttachDispatch and DetachDispatch functions like so:


	_DApplication da;
	NameSpace ns;	
	MAPIFolder cf;
	Items is;
	_DContactItem firstContact;
		
	LPDISPATCH lp = NULL;

	if(!da.CreateDispatch("Outlook.Application"))
	do_your_graceful_exit();
	
	lp = da.GetNamespace("MAPI");
	if(lp) ns.AttachDispatch(lp);
	else do_your_graceful_exit();
	
	lp = ns.GetDefaultFolder(10);
	if(lp) cf.AttachDispatch(lp);
	else do_your_graceful_exit();
	
	lp = cf.GetItems();
	if(lp) is.AttachDispatch(lp);	
	else do_your_graceful_exit();
	
	lp = is.Item(COleVariant((short)1));
	if(lp) firstContact.AttachDispatch(lp);
	else do_your_graceful_exit();
	 
	firstContact.Display();
	
	do_your_graceful_happydance_then_exit();
	

This actually looks nicer and more straighforward for the most part. But it functions the same in the event that everything works properly.

Thats basically all there is to Automating MSOutlook.. everything else is just making use of the functions provided by the objects. here is a simple interation through all contacts getting a list of Full Names:


	_DApplication da;
	NameSpace ns;	
	MAPIFolder cf;
	Items is;
	_DContactItem currContact;
		
	LPDISPATCH lp = NULL;

	if(!da.CreateDispatch("Outlook.Application"))
	do_your_graceful_exit();
	
	lp = da.GetNamespace("MAPI");
	if(lp) ns.AttachDispatch(lp);
	else do_your_graceful_exit();
	
	lp = ns.GetDefaultFolder(10);
	if(lp) cf.AttachDispatch(lp);
	else do_your_graceful_exit();
	
	lp = cf.GetItems();
	if(lp) is.AttachDispatch(lp);	
	else do_your_graceful_exit();

	short i;
	CString names;

	names = "You know all these people(";

	for(i = 1; i <= is.GetCount(); i++)
	{
		lp = is.Item(COleVariant((short)i));
		if(lp) currContact.AttachDispatch(lp);
		else break;
	
		//add the current contact's full name to the list.
		names += (currContact.GetFullName() + ", ");
	}

	names += ")?";

	AfxMessageBox(names);

there are a ton of Get/Set_XXX_() functions in _DContactItem check them out.

There is one other area that could bear some explaining: Adding items like contacts, here is a quick demo:



	_DApplication da;
	NameSpace ns;	
	MAPIFolder cf;
	Items is;
	_DContactItem newContact;
		
	LPDISPATCH lp = NULL;

	if(!da.CreateDispatch("Outlook.Application"))
	do_your_graceful_exit();
	
	lp = da.GetNamespace("MAPI");
	if(lp) ns.AttachDispatch(lp);
	else do_your_graceful_exit();

	// Create a new Contact Item ..  goes in the Contacts folder by default.
	// for all the magic-number constants see Outlook Constants.
	lp = da.CreateItem(2); //2 = the constant associated with _DContactItem
	if(lp) newContact.AttachDispatch(lp);
	else do_your_graceful_exit();

	newContact.SetFullName("Helvetica Henrique");
	newContact.SetJobTitle("helluvaPilot");
	newContact.SetWebPage("http://www.helmut.com/");
	newContact.SetHobby("Puddle Jumping...that is all.");
	//save Miss Henrique.
	newContact.Save();
	//show her off for all to see.
	newContact.Display();
		

That is basically all their is to it.. now it's just a matter of dealing with the interfaces and figuring stuff out.

one more thing I will show you how to do, Add/Remove UserDefined properties.. these were really annoying to get done.. and if you have a simpler way of converting from VARIANT to CString let me know : )
BTW: the next two examples require the UserProperties and UserProperty objects from Outlook. (As well as the other Objects that are always necesary)


/**************
 * This sets the first Contact(in the 'Contacts' folder) 's UserProperty "HowMuchHelvaLikesThem"
 * 	to: "this much----->|      |<---------"
 */

	_DApplication da;
	NameSpace ns;	
	MAPIFolder cf;
	Items is;
	_DContactItem firstContact;
		
	LPDISPATCH lp = NULL;

	if(!da.CreateDispatch("Outlook.Application"))
	do_your_graceful_exit();
	
	lp = da.GetNamespace("MAPI");
	if(lp) ns.AttachDispatch(lp);
	else do_your_graceful_exit();
	
	lp = ns.GetDefaultFolder(10);
	if(lp) cf.AttachDispatch(lp);
	else do_your_graceful_exit();
	
	lp = cf.GetItems();
	if(lp) is.AttachDispatch(lp);	
	else do_your_graceful_exit();
	
	lp = is.Item(COleVariant((short)1));
	if(lp) firstContact.AttachDispatch(lp);
	else do_your_graceful_exit();

	UserProperties up(firstContact.GetUserProperties());
	CString prop_name1("HowMuchHelvaLikesThem"); //not sure if spaces are allowed.

	//Try and find it
	pl = up.Item(( COleVariant(prop_name1)));

	if(pl==NULL) 
	{	//couldnt find the property so add it.
		// for all the magic-number constants see Outlook Constants.
		up.Add(prop_name1, 1, covFalse, covFalse);//1 = olText or something like that
		pl = up.Item(( COleVariant(prop_name1)));
	}

	if(pl) //if the property exists now.
	{
		CString str("this much----->|      |<---------");
		UserProperty upity(pl);  //attach upity to the (possibly) new property.			
		upity.SetValue(COleVariant(str)); // give a (certainly) new value :)
	}


That wasn't so bad, and now for some of the Ugly not-so-horrorshow ultra-violence involved in the way i found to convert VARIANT to CString.

	_DApplication da;
	NameSpace ns;	
	MAPIFolder cf;
	Items is;
	_DContactItem firstContact;
		
	LPDISPATCH lp = NULL;

	if(!da.CreateDispatch("Outlook.Application"))
	do_your_graceful_exit();
	
	lp = da.GetNamespace("MAPI");
	if(lp) ns.AttachDispatch(lp);
	else do_your_graceful_exit();
	
	lp = ns.GetDefaultFolder(10);
	if(lp) cf.AttachDispatch(lp);
	else do_your_graceful_exit();
	
	lp = cf.GetItems();
	if(lp) is.AttachDispatch(lp);	
	else do_your_graceful_exit();
	
	lp = is.Item(COleVariant((short)1));
	if(lp) firstContact.AttachDispatch(lp);
	else do_your_graceful_exit();

	UserProperties up(firstContact.GetUserProperties());
	UserProperty* upty = NULL;
	BSTR h = NULL;
	LPDISPATCH lp;

	CString prop_name("HowMuchHelvaLikesThem");

	//find the property we want to read.
	lp = up.Item(( COleVariant(prop_name)));
	upty = new UserProperty(lp);

	if(upty&&lp)
	{ //if the property exists, read it.

		_variant_t v;
		v.Attach(upty->GetValue()); //here's where we get the VARIANT... ::shudder::..
		_bstr_t b = (_bstr_t)(v);
		h = b.copy(); //may be only unnecesary step.
		delete upty;
	}
	else 
		h = NULL;
	CString strProperty(h);
	CString msg("Helva Must Like Them about this much: ");
	msg += strProperty;
	AfxMessageBox(msg);

These few pages were put together after an intense period of coding OLE Automation over parts of the summer of 99 using MS winNT4(sp4..i think) & MS Visual Studio 6.0 (visualc++). I found volumes of information on Automating Outlook with VBA and VB .. but either none at all or next to none on Automating Outlook in C++. This information is all pieced together from wwweb examples, MSDN VB examples, MSDN C++ examples for MSWord and MSExcel, my own experimentation, and help from my peers(I don't recall any .. but in case I recieved help.. I should acknowledge it.) [be aware.. a month ago I had never written a single line of MS-specific code. (only java and C/C++ w/ std libs.)]

I hope this helps you, but as it's provided for free, and to contribute to the simplicity of life, I cant claim responsibility for whatever silly or stupid things people may do with this stuff. I ask that it only be used to further aid people and never for destructive purposes. I also can't guarantee it won't cause damage in it's current state, I feel that it shouldn't and wouldn't but as I don't have your system or the code you integrate this into in front of me, I can't be sure.
If you would like to reach me with questions, problems, or for help please contact me via email yitz@datalife.com.
Otherwise I can be found on AOL InstantMessenger as "TenVessels".