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);