Click here to Skip to main content
12,691,959 members (29,355 online)
Click here to Skip to main content
Add your own
alternative version

Stats

14.9K views
9 bookmarked
Posted

Outlook Addin using VC++ ATL/COM

, 7 Jan 2013 CPOL
Rate this:
Please Sign up or sign in to vote.
To get instant control over Outlook and various operations of outlook.
This is an old version of the currently published article.

Introduction 

These codes are written with VC++ ATL/COM . Creating an Outlook addin and performing various tasks related to Outlook. One who is familiar with Outlook operations can understand and can extend these codes to perform other tasks. It holds Creating an Outlook Addin, creating buttons and various controls, creating appointments, retrieving all appointments, connecting to database and take values to and from the database.

I assure that I would work in the future to enhance various other operations with clear codes.

Using the code

  1. Start Visual Studio, Click on New Project-> Extensibility and choose Shared Addin from it.
  2. 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."  
  3. Build the solution to ensure that it compiles good.
  4. Next, open up Class View, right-click on your CConnect class and select "Add -> Implement Interface…" In the dialog that pops up, select the "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 browse button to choose the MSO.dll file from Office folder.  Click Finish once you are done.
  5. Navigate to Connect.h file and you should see the auto generated GetCustomUI() function. Delete its "return E_NOTIMPL;" And try to make your own code here.
  6. Next step is to import a XML resource file having codes to create buttons or any other control you want to see on Outlook Tabs.
  7. Right Click on .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 GetCustomUI() function.
if (!RibbonXml)
            return E_POINTER;

        *RibbonXml = GetXMLResource(IDR_XML1);

        return (*RibbonXml ? S_OK : E_OUTOFMEMORY);  return S_OK; 

 Ribbon.xml

<?xml version="1.0" encoding="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 codes are used to parse the xml and sends the values to 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;
        // Assumes that the data is not stored in Unicode.
        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.

  1. 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)
  2. Add "using namespace Office;" to the top of the Connect.h file.  
  3. Now build the solution with either Static or shared libraries.
  4. You can see the button in the Outlook Calender screen and you can use any other value to place various controls in Outlook.

Adding button click event

  1. Right click on the project and choose Add Class and select ATL Simple Object" in the ATL category, name it as ButtonCallBack.
  2. 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 the Solution Explorer.
  3. 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: 
  4. 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.
  5. Write codes under the auto generated function ButtonClicked().
STDMETHOD(ButtonClicked)( IDispatch * RibbonControl){   // Add your function implementation here. MessageBoxW(NULL,     L"The button was clicked!",      L"Button Click Event",     MB_OK); }
  1. 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 selecting properties).
  2. In Connect.h, switch the IDispatch line in the COM_MAP to IButtonCallBack instead of IRibbonExtensibility:   
  3. Now just Clean the solution and Build it.
  4. You will see the button in 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

.1) Add these two in 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 whereever you want on the button click event or under OnConnection function.

3) _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'");
       //_bstr_t strSQLSelect("INSERT INTO master VALUES ('gokulnath','1','1','2011-01-04 00:00:00.000','1','2011-01-04 00:00:00.000',1);");

       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;;
       //pCmdSelect->Execute(&rowsaffected,&param,optl);

       pConn->Execute(strSQLSelect,NULL,adCmdText); // only for updating and inserting data into the database


       hr=pRstValue.CreateInstance(__uuidof(Recordset));
       pRstValue->Open (strSQLSelect, _variant_t((IDispatch *) pConn, true), adOpenForwardOnly, adLockOptimistic, adCmdText); // For Selecting values from Database  (SELECT Statements)

       // Ensure at top of recordset.
       pRstValue->MoveFirst();

       // If EOF is true, then no data and skip print loop.
       if ( pRstValue->EndOfFile ){

       }
       else
       {
           // Define strings for output conversions.  Initialize to first record's values.
           //_bstr_t bstrTitle;
           _bstr_t bstrType;

           //// Enumerate Recordset and print from each.
           //while ( !(pRstValue->EndOfFile) )
           //{


               bstrType  = pRstValue->Fields->GetItem("City ")->Value; // Use different column values to get those inside GetItem("Your column name")
           //}
       }

       //Close the database
       pConn->Close();
     Sending Mails to various accounts and operations.
   _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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Gokulnath007
Software Developer CG-VAK Softwares and Exports
India India
Am a Computer Science and Engineering Graduate.
Currently I am working as a software developer in VC++.

You may also be interested in...

Comments and Discussions


Discussions posted for the Published version of this article. Posting a message here will take you to the publicly available article in order to continue your conversation in public.
 
QuestionWhere can I get that template? Pin
Member 1053914610-Jun-14 7:13
memberMember 1053914610-Jun-14 7:13 
QuestionFor Chinese character in ASCII Pin
Member 998829718-Feb-14 20:09
memberMember 998829718-Feb-14 20:09 
QuestiongetLabel callback Pin
BenediktUA7-Mar-13 10:22
memberBenediktUA7-Mar-13 10:22 
GeneralMy vote of 5 Pin
Sankar Chandra Bose7-Jan-13 19:47
memberSankar Chandra Bose7-Jan-13 19:47 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.170117.1 | Last Updated 7 Jan 2013
Article Copyright 2013 by Gokulnath007
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid