65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 VC++ ATL/COM 开发 Outlook 加载项

starIconstarIconstarIconstarIconstarIcon

5.00/5 (4投票s)

2013年1月7日

CPOL

4分钟阅读

viewsIcon

35216

即时控制 Outlook 和 Outlook 的各种操作。

介绍 

这些代码是用 VC++ ATL/COM 编写的,用于创建 Outlook 加载项并执行与 Outlook 相关的各种任务。熟悉 Outlook 操作的人可以理解并扩展这些代码来执行其他任务。它有助于创建 Outlook 加载项、创建按钮和各种控件、创建约会、检索所有约会以及连接到数据库并从数据库读写值。

我保证未来会用清晰的代码来增强各种其他操作。

使用代码

  1. 启动 Visual Studio,然后点击“新建项目” -> “扩展性”,然后从中选择“共享加载项”。
  2. 确保选中“使用 Visual C++/ATL 创建加载项”和“我希望我的加载项在宿主应用程序加载时加载”。
  3. 生成解决方案以确保其能够成功编译。
  4. 接下来,打开“类视图”,右键单击您的 CConnect 类,然后选择“添加” -> “实现接口…” 在弹出的对话框中,选择“Microsoft Office 12.0 Object Library <2.4>”类型库,并从中添加“IRibbonExtensibility”接口。如果您的库未在下拉列表中列出,请选择“文件”并单击“浏览”按钮从 Office 文件夹中选择 MSO.dll 文件。完成后单击“完成”。
  5. 导航到 Connect.h 文件,您应该会看到自动生成的 GetCustomUI() 函数。删除“return E_NOTIMPL;”。然后在此处编写您自己的代码。
  6. 下一步是导入一个 XML 资源文件,其中包含创建 Outlook 选项卡上按钮或您希望看到的任何其他控件的代码。
  7. 右键单击 .rc 文件,选择“添加资源”,然后从中选择“导入”。将 XML 文件添加到项目中。例如 Ribbon.xml。将这些代码添加到 GetCustomUI() 函数中。
  8. 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>

以下代码用于解析 XML 并将值发送到 GetCustomUI() 函数。

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

将上述函数添加到 Connect.h 文件中。

  1. 打开“stdafx.h”,并将 MSO.dll#import 语句从文件底部移到 Extensibility 库的 #import 语句旁边,位于 #pragma 块内(同时删除该行上的任何 'no_namespace' 注释)。
  2. 将“using namespace Office;”添加到 Connect.h 文件的顶部。
  3. 现在使用静态或共享库生成解决方案。
  4. 您可以在 Outlook 日历屏幕中看到该按钮,您可以使用任何其他值在 Outlook 中放置各种控件。

添加按钮单击事件

  1. 右键单击项目,选择“添加类”,然后在 ATL 类别中选择“ATL 简单对象”,将其命名为 ButtonCallBack
  2. 现在,在“类视图”中,我们将看到几个新对象:一个名为 IButtonCallBack 的 ATL 接口和一个名为 CButtonCallBack 的实现类。我们不需要实现,所以请在“解决方案资源管理器”中删除所有 ButtonCallBack.* 文件。
  3. 在“类视图”下,右键单击 IButtonCallBack,然后选择“添加方法”。在“添加方法向导”中,添加一个名为 ButtonClicked 的方法,该方法带有一个类型为 IDispatch*[in] 参数,称为 RibbonControl
  4. 再次右键单击 CConnect 类并选择“实现接口…” 以添加 IButtonCallBack。在“类视图”中双击 ButtonClicked 函数,即可跳转到自动生成的实现。
  5. 在自动生成的 ButtonClicked() 函数下编写代码。
  6. STDMETHOD(ButtonClicked)( IDispatch * RibbonControl){
      // Add your function implementation here.
      MessageBoxW(NULL, L"The button was clicked!", L"Button Click Event", MB_OK);
    }
  7. 现在右键单击项目,选择“添加现有项”,然后从项目文件夹中导入 AddIn_i.c。并确保在“配置属性”下该文件“不使用预编译头”。(只需右键单击文件并选择属性)。
  8. Connect.h 文件中,将 COM_MAP 中的 IDispatch 行切换为 IButtonCallBack 而不是 IRibbonExtensibility:   
  9. 现在只需清理解决方案并生成它。
  10. 您将在 Outlook 日历屏幕中看到该按钮,如果您单击该按钮,您将看到之前添加的 MessageBox。

处理约会、发送邮件、保存联系人和访问数据库 ATL COM

  1. 将以下两项添加到 stdafx.h 文件中。
  2. #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")
  3. 然后在 Connect.h 文件中,添加 using namespace Outlook;
  4. 将这些代码添加到您想要的位置,例如按钮单击事件或 OnConnection 函数下。
  5. _ApplicationPtr pApp(pApplication);
    _NameSpacePtr pNamespace;pApp->GetNamespace(L"MAPI",&pNamespace);
    MAPIFolderPtr pFolder;
    pNamespace->GetDefaultFolder(olFolderContacts,&pFolder);
    _ItemsPtr pItems;

创建并打开一个新联系人

_ContactItemPtr pNewContact;
pApp->CreateItem(olContactItem,(IDispatch**)&pNewContact);
pNewContact->put_LastName(OLESTR("India"));
pNewContact->put_FirstName(OLESTR("Gokulnath"));
pNewContact->Save();

您可以使用任何文件夹名称的值从这些文件夹(olFolderContacts)中检索值。

接下来是获取一个约会

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

创建约会

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

关注点

这些任务确实很有趣且富有挑战性。我很享受。

历史 

版本 1.0。

© . All rights reserved.