Introduction
These codes are written with VC++ ATL/COM for xreating an Outlook add-in and performing various tasks related to Outlook.
Those familiar with Outlook operations can understand and can extend these codes
to perform other tasks. It helps in creating an Outlook add-in, creating buttons and various controls, creating appointments,
retrieving all appointments, and connecting to a database and taking values to and from the database.
I assure
you that I would work in the future to enhance various other
operations with clear codes.
Using the code
- Start Visual Studio, click on New Project-> Extensibility and choose Shared Addin from it.
- Make sure to check "Create an Add-in using Visual C++/ATL" and "I would like my Add-in to load when the host application loads."
- Build the solution to ensure that it compiles good.
- Next, open up Class View, right-click on your
CConnect
class and select "Add -> Implement Interface…" In the dialog that pops up, select "Microsoft Office 12.0 Object Library <2.4>" type library and add the "IRibbonExtensibility
" interface from it.
If your library is not listed in the drop down, choose file and click on the Browse button to choose the MSO.dll file from
the Office folder. Click Finish once you are done. - Navigate to the Connect.h file and you should see the auto generated
GetCustomUI()
function. Delete "return E_NOTIMPL;
". And try to make your own code here. - The next step is to import an XML resource file having codes to create buttons or any other control you want to see on Outlook Tabs.
- Right click on the .rc file and choose Add Resource and select import from it. Add the
XML file to the project. For instance Ribbon.xml.
Add these codes inside the
GetCustomUI()
function.
if (!RibbonXml)
return E_POINTER;
*RibbonXml = GetXMLResource(IDR_XML1);
return (*RibbonXml ? S_OK : E_OUTOFMEMORY); return S_OK;
Ribbon.xml
="1.0"="utf-8"
<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui">
<ribbon startFromScratch="false">
<tabs>
<tab idMso="TabCalendar" >
<group id="Customer" label="Customer">
<button id="ReportButton"
size="large"
label="Report Button"
imageMso="SetLanguage"
onAction="OnReportButtonClicked"/>
</group>
</tab>
</tabs>
</ribbon>
</customUI>
The following code is used to parse the XML and send the values to the GetCustomUI()
function:
HRESULT HrGetResource(int nId, LPCTSTR lpType, LPVOID* ppvResourceData, DWORD* pdwSizeInBytes)
{
HMODULE hModule = _AtlBaseModule.GetModuleInstance();
if (!hModule)
return E_UNEXPECTED;
HRSRC hRsrc = FindResource(hModule, MAKEINTRESOURCE(nId), lpType);
if (!hRsrc)
return HRESULT_FROM_WIN32(GetLastError());
HGLOBAL hGlobal = LoadResource(hModule, hRsrc);
if (!hGlobal)
return HRESULT_FROM_WIN32(GetLastError());
*pdwSizeInBytes = SizeofResource(hModule, hRsrc);
*ppvResourceData = LockResource(hGlobal);
return S_OK;
}
BSTR GetXMLResource(int nId)
{
LPVOID pResourceData = NULL;
DWORD dwSizeInBytes = 0;
HRESULT hr = HrGetResource(nId, TEXT("XML"),
&pResourceData, &dwSizeInBytes);
if (FAILED(hr))
return NULL;
CComBSTR cbstr(dwSizeInBytes, reinterpret_cast<LPCSTR>(pResourceData));
return cbstr.Detach();
}
SAFEARRAY* GetOFSResource(int nId)
{
LPVOID pResourceData = NULL;
DWORD dwSizeInBytes = 0;
if (FAILED(HrGetResource(nId, TEXT("OFS"),
&pResourceData, &dwSizeInBytes)))
return NULL;
SAFEARRAY* psa;
SAFEARRAYBOUND dim = {dwSizeInBytes, 0};
psa = SafeArrayCreate(VT_UI1, 1, &dim);
if (psa == NULL)
return NULL;
BYTE* pSafeArrayData;
SafeArrayAccessData(psa, (void**)&pSafeArrayData);
memcpy((void*)pSafeArrayData, pResourceData, dwSizeInBytes);
SafeArrayUnaccessData(psa);
return psa;
}
Add the above functions in Connect.h.
- Open up "stdafx.h" and move the
#import
statement for MSO.dll from the bottom of the file up next to the
#import
statement for the
Extensibility library inside the #pragma
blocks (remove any 'no_namespace
' annotations from that line as well). - Add "
using namespace Office;
" to the top of the Connect.h file. - Now build the solution with either
static or shared libraries.
- You can see the button in the Outlook Calendar screen and you can use any other value to place various controls in Outlook.
Adding a button click event
- Right click on the project and choose Add Class and select ATL Simple Object" in the ATL
category, name it
ButtonCallBack
. - Now in Class View we have several new objects: an ATL interface called
IButtonCallBack
and an implementation class called CButtonCallBack
. We don't need the implementation, so go ahead and
delete all the ButtonCallBack
.* files from Solution Explorer.
- Under Class view, right click on
IButtonCallBack
and
select Add Method. In the Add Method Wizard, add a method named ButtonClicked
with one
[in]
parameter of type IDispatch*
called RibbonControl
. - Right click on the
CConnect
class and select "Implement Interface…" again to add IButtonCallBack
.
Double-click the ButtonClicked
function in Class View to be taken to the auto-generated implementation. - Write code under the auto generated function
ButtonClicked()
.
STDMETHOD(ButtonClicked)( IDispatch * RibbonControl){
MessageBoxW(NULL, L"The button was clicked!", L"Button Click Event", MB_OK);
}
- Now right click on project, choose Add Existing item, and import AddIn_i.c from the project folder. And make sure that the file
is "Not Using Precompiled Headers" under Configuration Properties. (Just right click the file and select properties).
- In Connect.h, switch the
IDispatch
line in COM_MAP
to
IButtonCallBack
instead of IRibbonExtensibility
:
- Now just Clean the solution and Build it.
- You will see the button in the Outlook Calendar screen and if you click on the button, you will get the MessageBox as added before.
Working with Appointments, Sending Mails, Saving Contacts, and Accessing Database ATL COM
- Add these two in the stdafx.h file:
#import "C:\Program Files\Microsoft Office\Office14\MSOUTL.OLB"
raw_interfaces_only, raw_native_types, named_guids, auto_search
#import "C:\Program Files\Common Files\System\ado\msado28.tlb" no_namespace rename("EOF", "EndOfFile")
- And in Connect.h, add
using namespace Outlook;
. - Add these codes wherever you want on the button click event or under the
OnConnection
function.
_ApplicationPtr pApp(pApplication);
_NameSpacePtr pNamespace;pApp->GetNamespace(L"MAPI",&pNamespace);
MAPIFolderPtr pFolder;
pNamespace->GetDefaultFolder(olFolderContacts,&pFolder);
_ItemsPtr pItems;
Create and open a new contact
_ContactItemPtr pNewContact;
pApp->CreateItem(olContactItem,(IDispatch**)&pNewContact);
pNewContact->put_LastName(OLESTR("India"));
pNewContact->put_FirstName(OLESTR("Gokulnath"));
pNewContact->Save();
You can use any values of folder names to retrieve values from those folders (olFolderContacts
).
Next is to get an appointment
_AppointmentItemPtr pGetApptt;
pNamespace->GetDefaultFolder(olFolderCalendar,&pFolder);
pFolder->get_Items(&pItems);
long count =5;
pItems->get_Count(&count);
int wd = (int)count;
VARIANT lpVar;
lpVar.vt = VT_INT;
lpVar.intVal = wd;
pItems->Item(lpVar,(IDispatch**)&pGetApptt);
BSTR subject = L"location";
pGetApptt->get_Subject(&subject);
BSTR body;
pGetApptt->get_Body(&body);
ConnectionPtr pConn = NULL;
_CommandPtr pCmdSelect = NULL;
_RecordsetPtr pRstValue = NULL;
_bstr_t strCon("DRIVER={SQL Server};SERVER=localhost;DATABASE=Client;");
_bstr_t strSQLSelect("SELECT City FROM Table1 WHERE ICode = '7'");
hr = pConn.CreateInstance((__uuidof(Connection)));
hr = pConn->Open(strCon,"","",0);
hr=pCmdSelect.CreateInstance(__uuidof(Command));
pCmdSelect->ActiveConnection = pConn;
pCmdSelect->CommandText = strSQLSelect;
VARIANT rowsaffected;
VARIANT param;
long optl = 0;;
pConn->Execute(strSQLSelect,NULL,adCmdText);
hr=pRstValue.CreateInstance(__uuidof(Recordset));
pRstValue->Open (strSQLSelect, _variant_t((IDispatch *) pConn, true),
adOpenForwardOnly, adLockOptimistic, adCmdText);
pRstValue->MoveFirst();
if ( pRstValue->EndOfFile ){
}
else
{
_bstr_t bstrType;
bstrType = pRstValue->Fields->GetItem("City ")->Value;
}
pConn->Close();
_MailItemPtr pNewMailItem;
pApp->CreateItem(olMailItem,(IDispatch**)&pNewMailItem);
pNewMailItem->put_BCC(L"mailid1");
pNewMailItem->put_Body(L"Mail Send from Visual C++/ATL");
pNewMailItem->put_To(L"mailid2");
pNewMailItem->Send();
DATE pStart;
SYSTEMTIME sysTime;
memset(&sysTime, 0, sizeof(SYSTEMTIME));
sysTime.wYear = 2013;
sysTime.wMonth = 1;
sysTime.wDay = 4;
SystemTimeToVariantTime(&sysTime, &pStart);
Creating the appointments
_AppointmentItemPtr pGetAppt;
pApp->CreateItem(olAppointmentItem,(IDispatch**)&pGetAppt);
pGetAppt->put_Body(L"Sample Appointment from ATL COM");
pGetAppt->put_Location(L"Coimbatore");
pGetAppt->put_Start(pStart);
pGetAppt->Save();
Points of Interest
These tasks are really interesting and challenging. Enjoyed it.
History
Version 1.0.