HOW TO:在 ATL 中创建要用于 Office XP 的智能标记 DLL

本文的发布号曾为 CHS292596
本文已归档。它按“原样”提供,并且不再更新。
概要
智能标记是随 Office XP 引进的技术,它使 Office 用户与 Office 文档可以更好地进行交互。智能标记是 Office 文档中文本的元素,它被视为具有与其关联的自定义操作。这些特殊文本元素之一的示例可以是在 Word 文档或 Excel 工作簿中键入的电子邮件名称。 如果该电子邮件名称被视为智能标记,则用户可以在该文本上执行一项或多项操作。 与电子邮件名称关联的操作可以是查阅其他联系人信息,或者向该联系人发送新的电子邮件。

可通过开发用于 Office 文档的智能标记识别器/操作动态链接库 (DLL) 来扩展 Office XP 的功能。 本文说明如何使用活动模板库 (ATL) 建立智能标记 DLL,并讨论 Office XP 需要哪些注册表设置来识别和使用智能标记 DLL。

备注:Office XP 应用程序中只有 Excel 2002 和 Word 2002 支持智能标记。 然而,您可以将文中的信息应用到为任何采用智能标记技术的应用程序进行的智能标记开发当中。智能标记 DLL 是实现以下两种特殊接口的标准组件对象模型 (COM) DLL:ISmartTagRecognizerISmartTagActionISmartTagRecognizer 接口识别作为智能标记键入文档的文本。 ISmartTagAction 接口应用户的要求在特定智能标记字符串上执行操作。无需在同一个 DLL 中实现这些接口。 可以有一个识别器 DLL 和一个或多个为不同操作扩展一个智能标记类型的操作 DLL。

返回页首


在 ATL 中创建智能标记 DLL 的步骤


下列步骤创建一个简单的智能标记 DLL,它可识别 Microsoft Network (MSN) Instant Messenger 联系人并使用户可以向识别的联系人发送电子邮件或即时消息。使用此示例需要 Instant Messenger。如果没有 Instant Messenger,可从以下 MSN Web 站点获得一个副本:
  1. 在 Visual C++ 中,创建一个新的 ATL COM AppWizard 项目。 将该项目的名称指定为 MessengerSmartTag。
  2. 单击确定启动 ATL COM 向导。 在下一个对话框中,确保选定了动态链接库,然后单击完成。 单击确定创建项目。
  3. 若要创建 Recognizer 类,请单击插入菜单上的新建 ATL 对象。 选择简单对象,然后单击下一步。 对于简称,键入 Recognizer,然后单击确定
  4. 若要创建 Action 类,按照第 3 步的说明操作,但键入 Action 作为简称。
  5. 打开 ClassView 并展开 MessengerSmartTag 类。 右键单击 CRecognizer 类并选择实现接口。出现警告对话框时单击确定。单击浏览并选择 Microsoft Smart Tags 1.0 类型库。 选择 ISmartTagRecognizer 接口并按确定

    备注: Microsoft Smart Tags 1.0 类型库的默认位置是 C:\Program Files\Common Files\Microsoft Shared\Mstag.tlb。
  6. 在 ClassView 中,右键单击 CAction 类并选择实现接口。出现警告对话框时单击确定。单击浏览并选择 Microsoft Smart Tags 1.0 类型库。 选择 ISmartTagAction 接口并单击确定
  7. 打开 Recognizer.h 文件,用以下代码替换该类的内容:
    ///////////////////////////////////////////////////////////////////////////// // CRecognizerclass ATL_NO_VTABLE CRecognizer :    public CComObjectRootEx<CComSingleThreadModel>,   public CComCoClass<CRecognizer, &CLSID_Recognizer>,   public IDispatchImpl<IRecognizer, &IID_IRecognizer, &LIBID_MESSENGERSMARTTAGLib>,   public IDispatchImpl<ISmartTagRecognizer, &IID_ISmartTagRecognizer, &LIBID_SmartTagLib>{public:    CRecognizer();    ~CRecognizer();DECLARE_REGISTRY_RESOURCEID(IDR_RECOGNIZER)DECLARE_PROTECT_FINAL_CONSTRUCT()BEGIN_COM_MAP(CRecognizer)    COM_INTERFACE_ENTRY(IRecognizer)//Removed -- COM_INTERFACE_ENTRY(IDispatch)    COM_INTERFACE_ENTRY2(IDispatch, IRecognizer)    COM_INTERFACE_ENTRY(ISmartTagRecognizer)END_COM_MAP()// IRecognizerpublic:// ISmartTagRecognizer    STDMETHOD(get_ProgId)(BSTR * ProgId);    STDMETHOD(get_Name)(INT LocaleID, BSTR * Name);    STDMETHOD(get_Desc)(INT LocaleID, BSTR * Desc);    STDMETHOD(get_SmartTagCount)(INT * Count);    STDMETHOD(get_SmartTagName)(INT SmartTagID, BSTR * Name);    STDMETHOD(get_SmartTagDownloadURL)(INT SmartTagID, BSTR * DownloadURL);    STDMETHOD(Recognize)(BSTR Text, IF_TYPE DataType, INT LocaleID,                  ISmartTagRecognizerSite * RecognizerSite);private:    long lCount;    SAFEARRAY *psa;};
  8. 打开 Recognizer.cpp 文件,将以下代码添加到文件末尾:
    CRecognizer::CRecognizer(){    Messenger::IMsgrObject2Ptr oMsgrObj = NULL;    Messenger::IMsgrUsersPtr oUsers = NULL;    Messenger::IMsgrUserPtr oUser = NULL;    SAFEARRAYBOUND rgsaBound[1];    long rgIndices[1];		    HRESULT hr;		    // Create an instance of Instant Messenger.    oMsgrObj.CreateInstance("Messenger.MsgrObject");    // Get the list of contacts    oUsers = oMsgrObj->GetList(Messenger::MLIST_CONTACT);    // Store the number of contacts you have.    lCount = oUsers->GetCount();    rgsaBound[0].lLbound = 0;    rgsaBound[0].cElements = lCount;    // Create a SAFEARRAY to hold the list of contacts.    psa = SafeArrayCreate(VT_VARIANT, 1, rgsaBound);    // Loop through all contacts.    for (long l=0; l<lCount-1; l++)    {        rgIndices[0] = l;	        // Set the specific user.        oUser = oUsers->Item(l);        // Convert the Friendly Name to lower case        // and store it in a VARIANT.        _variant_t v = _wcslwr(oUser->GetFriendlyName());        // Put the VARIANT into the SAFEARRAY.       hr = SafeArrayPutElement(psa, rgIndices, &v);    }}CRecognizer::~CRecognizer(){    // Destroy the SAFEARRAY.    SafeArrayDestroy(psa);}HRESULT CRecognizer::get_ProgId(BSTR * ProgId){    // Set the ProgID of the Recognizer interface.    *ProgId = SysAllocString(L"MessengerSmartTag.Recognizer");    return S_OK;}HRESULT CRecognizer::get_Name(INT LocaleID, BSTR * Name){    // Set a short title about the recognizer.    *Name = SysAllocString(L"Microsoft Messenger Contacts Visual C++ Recognizer");    return S_OK;}HRESULT CRecognizer::get_Desc(INT LocaleID, BSTR * Desc){    // Set a long description of the recognizer.    *Desc = SysAllocString(L"Microsoft Messenger recognizes your Instant Messenger Contacts");    return S_OK;}HRESULT CRecognizer::get_SmartTagCount(INT * Count){    // Set the number of Smart Tags that are supported.    *Count = 1;    return S_OK;}HRESULT CRecognizer::get_SmartTagName(INT SmartTagID, BSTR * Name){    // This method is called the same number of times as you    // return in SmartTagCount. This method sets a unique name    // for the Smart Tag.    *Name = SysAllocString(L"microsoft/messenger#contacts");    return S_OK;}HRESULT CRecognizer::get_SmartTagDownloadURL(INT SmartTagID, BSTR * DownloadURL){    // Set the URL that gets embedded in documents.    *DownloadURL = NULL;    return S_OK;}HRESULT CRecognizer::Recognize(BSTR Text, IF_TYPE DataType, INT LocaleID,       ISmartTagRecognizerSite * RecognizerSite){    // The Recognize method is called and passed a text value.    // You should recognize strings in the text and set up the actions.    WCHAR *pch, *strText = _wcslwr(Text);    ISmartTagProperties  *pSmartTagProp = NULL;    long rgIndices[1];    HRESULT hr;    // Look through all contacts    for (long l = 0; l<lCount; l++).    {        rgIndices[0] = l;        // Get the contact name.        _variant_t v;        hr = SafeArrayGetElement(psa,rgIndices,&v);        // Convert the VARIANT to a BSTR.        _bstr_t bstrContact = v;        // Loop through the string looking for contacts.        for (pch = strText; (pch = wcsstr(pch, bstrContact))!=NULL; pch++)        {                // Create a new property bag.            hr = RecognizerSite->GetNewPropertyBag(&pSmartTagProp);            if (SUCCEEDED(hr)) {                // Commit the Smart Tag to the property bag.		                hr = RecognizerSite->CommitSmartTag(                      _bstr_t("microsoft/messenger#contacts"),                      pch - strText+1, wcslen(bstrContact),                      pSmartTagProp);                                if (pSmartTagProp != NULL)                    pSmartTagProp->Release();            }        }    }    return S_OK;}
  9. 打开 Action.h 文件,用以下代码替换该类的内容:
    ///////////////////////////////////////////////////////////////////////////// // CActionclass ATL_NO_VTABLE CAction :    public CComObjectRootEx<CComSingleThreadModel>,   public CComCoClass<CAction, &CLSID_Action>,   public IDispatchImpl<IAction, &IID_IAction, &LIBID_MESSENGERSMARTTAGLib>,   public IDispatchImpl<ISmartTagAction, &IID_ISmartTagAction, &LIBID_SmartTagLib>{public:   CAction(){}DECLARE_REGISTRY_RESOURCEID(IDR_ACTION)DECLARE_PROTECT_FINAL_CONSTRUCT()BEGIN_COM_MAP(CAction)    COM_INTERFACE_ENTRY(IAction)//Removed -- COM_INTERFACE_ENTRY(IDispatch)    COM_INTERFACE_ENTRY2(IDispatch, IAction)    COM_INTERFACE_ENTRY(ISmartTagAction)END_COM_MAP()// IActionpublic:// ISmartTagAction    STDMETHOD(get_ProgId)(BSTR * ProgId);    STDMETHOD(get_Name)(INT LocaleID, BSTR * Name);    STDMETHOD(get_Desc)(INT LocaleID, BSTR * Desc);    STDMETHOD(get_SmartTagCount)(INT * Count);    STDMETHOD(get_SmartTagName)(INT SmartTagID, BSTR * Name);    STDMETHOD(get_SmartTagCaption)(INT SmartTagID, INT LocaleID,                  BSTR * Caption);    STDMETHOD(get_VerbCount)(BSTR SmartTagName, INT * Count);    STDMETHOD(get_VerbID)(BSTR SmartTagName, INT VerbIndex, INT * VerbID);    STDMETHOD(get_VerbCaptionFromID)(INT VerbID, BSTR ApplicationName,                  INT LocaleID, BSTR * Caption);    STDMETHOD(get_VerbNameFromID)(INT VerbID, BSTR * Name);    STDMETHOD(InvokeVerb)(INT VerbID, BSTR ApplicationName,                  IDispatch * Target, ISmartTagProperties * Properties,                  BSTR Text, BSTR Xml);};
  10. 打开 Action.cpp 文件,将以下代码添加到文件末尾:
    HRESULT CAction::get_ProgId(BSTR * ProgId){   // Set the ProgID of the Action interface.   *ProgId = SysAllocString(L"MessengerSmartTag.Action");   return S_OK;}HRESULT CAction::get_Name(INT LocaleID, BSTR * Name){   // Set a short name describing the Action.   *Name = SysAllocString(L"Messenger Smart Tag");   return S_OK;}HRESULT CAction::get_Desc(INT LocaleID, BSTR * Desc){   // Set a long description describing the action.   *Desc = SysAllocString(L"Provides actions for the Messenger Smart Tag");   return S_OK;}HRESULT CAction::get_SmartTagCount(INT * Count){    // Set the number of smart tags this action supports.    *Count = 1;    return S_OK;}HRESULT CAction::get_SmartTagName(INT SmartTagID, BSTR * Name){    // This method is called the same number of times as you    // return in SmartTagCount. This method sets a unique name    // for the smart tag.    *Name = SysAllocString(L"microsoft/messenger#contacts");    return S_OK;}HRESULT CAction::get_SmartTagCaption(INT SmartTagID, INT LocaleID, BSTR * Caption){    // This caption is displayed on the menu for the smart tag.    *Caption = SysAllocString(L"Messenger Smart Tag");    return S_OK;}HRESULT CAction::get_VerbCount(BSTR SmartTagName, INT * Count){    // Return the number of verbs we support.    if (wcsstr(SmartTagName,L"microsoft/messenger#contacts") != 0) {        *Count = 2;    }    return S_OK;}HRESULT CAction::get_VerbID(BSTR SmartTagName, INT VerbIndex, INT * VerbID){    // Return a unique ID for each verb we support.    *VerbID = VerbIndex;    return S_OK;}HRESULT CAction::get_VerbCaptionFromID(INT VerbID, BSTR ApplicationName,                     INT LocaleID, BSTR * Caption){    // Set a caption for each verb. This caption is displayed    // on the Smart Tag menu.    switch (VerbID) {      case 1:        *Caption = SysAllocString(L"Send this contact an Instant Message");        break;      case 2:        *Caption = SysAllocString(L"Send email to this contact");        break;      default:        *Caption = NULL;        break;    }    return S_OK;}HRESULT CAction::get_VerbNameFromID(INT VerbID, BSTR * Name){    // Set a string name for each verb.    switch (VerbID) {      case 1:        *Name = SysAllocString(L"SendInstantMessage");        break;      case 2:        *Name = SysAllocString(L"SendEmail");        break;    }    return S_OK;}HRESULT CAction::InvokeVerb(INT VerbID, BSTR ApplicationName,      IDispatch * Target, ISmartTagProperties * Properties,      BSTR Text, BSTR Xml){    // This method is called when a user invokes a verb    // from the Smart Tag menu.    Messenger::IMessengerApp2Ptr oMessenger = NULL;    Messenger::IMsgrObject2Ptr oMsgrObj = NULL;    Messenger::IMsgrUsersPtr oUsers = NULL;    Messenger::IMsgrUserPtr oUser = NULL;    _variant_t v;		    // Create an instance of Instant Messenger.    oMessenger.CreateInstance("Messenger.MessengerApp");    oMsgrObj.CreateInstance("Messenger.MsgrObject");    // Get a list of contacts.    oUsers = oMsgrObj->GetList(Messenger::MLIST_CONTACT);    // Loop through all contacts.    for (long l=0; l<(oUsers->GetCount()-1); l++)    {        // Get a specific contact.        oUser = oUsers->Item(l);        // Check to see if the contact is the correct one.	if (wcscmp(_wcslwr(oUser->GetFriendlyName()),_wcslwr(Text)) == 0)        {            switch (VerbID) {              case 1:                // The user wants to display the Instant Message                // box to send the contact a message.                v = oUser.GetInterfacePtr();					                oMessenger->LaunchIMUI(v);                break;              case 2:                // Shell the "mailto" protocol to start the                // user's mail program and create a new message.                _bstr_t bstrTemp = "mailto:";                bstrTemp += oUser->GetEmailAddress();				                ShellExecute(0,"open",bstrTemp,NULL,NULL,1);                break;            }        }    }    return S_OK;}
  11. 打开 Stdafx.h 文件,将以下命令行添加到 #include <atlcom.h> 行之后:
    #import "C:\Program Files\Messenger\msmsgs.exe"
    备注: 将 Msmsgs.exe 文件的路径改为 Instant Messenger 的安装路径。 Instant Messenger 的默认位置是 C:\Program Files\Messenger。
  12. 按 F7 键创建 DLL。

返回页首


注册智能标记 DLL 的步骤



在使用任何智能标记 DLL 之前,必须在系统上注册它。 当您编译项目或使用 DLL 名称调用 Regsvr32.exe 时,将为您完成普通的 COM 注册。必须创建不属于普通 COM 注册的额外注册表项,以便 Office 应用程序可以将 DLL 识别为智能标记 DLL。为此,请按照下列步骤操作:
  1. 从命令行启动 Regedit.exe。
  2. HKEY_CURRENT_USER\Software\Microsoft\Office\Common\Smart Tag\Actions 下,添加名为 MessengerSmartTag.Action 的新子项。
  3. HKEY_CURRENT_USER\Software\Microsoft\Office\Common\Smart Tag\Recognize 下,添加名为 MessengerSmartTag.Recognize 的新子项。
  4. 关闭注册表编辑器。

返回页首


测试智能标记 DLL 的步骤



智能标记与宏遵循相同的安全模型。 如果应用程序的安全设置被设为“高”,则不会加载智能标记 DLL,除非 DLL 有数字签名(和 VBA 宏的情况相同)。有关数字签名的更多信息,请参见“参考”一节。

若要在 Word 中测试自定义的智能标记识别器/操作 DLL,请按照以下步骤操作:
  1. 启动 Instant Messenger 并登录。

    备注: 示例智能标记要求您登录 Instant Messenger;如果没有登录 Instant Messenger,将加载自定义 DLL,但不会识别任何联系人。
  2. 启动 Word 2002。在工具菜单上,指向,然后单击安全性。 将宏安全性设置为,然后单击确定。如果宏的安全设置以前被设置为,请重新启动 Word。
  3. 在新文档中键入联系人的友好名称(如 John Smith),然后按 ENTER 键。在友好名称下面出现一条虚线,指示它被识别为智能标记。在友好名称上方移动鼠标,将出现“智能标记操作”按钮。
  4. 单击智能标记操作,然后从下拉菜单中选择一个自定义操作项。可从新文档向联系人发送电子邮件或即时消息。
在 Excel 2002 中可使用类似的步骤测试智能标记 DLL。


返回页首


疑难解答



如果在使用自定义智能标记时出现问题,首先检查是否加载了自定义智能标记 DLL。 在 Word 或 Excel 中,单击工具菜单上的自动更正选项,单击智能标记选项卡,确保选中使用智能标记标识文字,并且列出并选定了您的智能标记 DLL。如果未列出智能标记,则说明它未正确注册。

如果是执行自定义 Recognizer 或 Action 类时导致该问题,可以像调试任何 Visual C++ DLL 那样对智能标记 DLL 进行调试。 为 Recognizer 类在构造函数中设置一个断点。 当您按 F5 键调试应用程序时,会出现一个对话框,要求提供用于调试会话的可执行文件。 选择 Winword.exe Excel.exe。 当 Excel 或 Word 启动并加载智能标记后,代码将在断点处停下来,您可以逐句对代码进行调试。

返回页首

参考


智能标记软件开发工具包 (SDK) 中提供了这些接口的文档以及定义它们所必需的类型库。您应当先安装智能标记 SDK(如果尚未这样做),然后进行创建示例智能标记的步骤。 可以从 Microsoft Office XP Developer (MOD) CD-ROM 获得智能标记 SDK,或者从以下 Microsoft Developer Network (MSDN) Web 站点下载它:


有关创建自定义智能标记识别器/操作 DLL 的更多信息,请参见智能标记 SDK 所包括的智能标记开发帮助文件。

有关数字签名的其他信息,请单击下列文章编号,查看相应的 Microsoft 知识库文章:
CHS247257 信息:对 .cab 文件进行签名的步骤
有关使用 CLSID(而不是 ProgID)注册智能标记 DLL 的信息,请参见以下 Microsoft 知识库文章:
CHS294422 错误:在启用或禁用智能标记时状态标记不更新


返回页首

smart tag sdk factoid
属性

文章 ID:292596 - 上次审阅时间:02/24/2014 20:20:02 - 修订版本: 3.1

  • Microsoft Excel 2002 标准版
  • Microsoft Word 2002 标准版
  • Microsoft Visual C++ 6.0 专业版
  • kbnosurvey kbarchive kbhowtomaster kbatl kbword kbexcel kbgrpdso KB292596
反馈