本部分介绍如何使用活动模板库 (ATL) 和组件对象模型 (COM) 从数学输入控件检索 MathML 标记。
若要从数学输入控件检索已识别的数学公式,可以替代按下插入按钮时发生的行为。 为此,需要设置一个事件处理程序,用于实现 _IMathInputControlEvents 接口支持的各种事件。 设置事件处理程序涉及对要支持的事件执行以下步骤,在本例中 (插入) 。
创建包含事件接收器的模板类
实现使用数学输入控件的事件接收器时,必须先指定接收器 ID。然后,必须创建一个从事件、事件控件处理程序和数学输入控件事件接口继承的模板类。 以下代码演示如何设置接收器 ID 并创建从必要接口继承的此类模板类 CMathInputControlEventHandler。 此模板类还设置为具有专用的未知接口指针,该指针将用于在初始化时将数学输入控件传递给它,m_ulAdviseCount成员用于计算建议/取消添加的调用数。
#pragma once
static const int MATHINPUTCONTROL_SINK_ID = 1 ;
template <class T>
class ATL_NO_VTABLE CMathInputControlEventHandler :
public IDispEventSimpleImpl<MATHINPUTCONTROL_SINK_ID, CMathInputControlEventHandler<T>, &__uuidof(_IMathInputControlEvents)>
{
private:
IUnknown *m_pUnknown;
ULONG m_ulAdviseCount;
CDialog *m_pMain;
注意
如果不使用对话,则实现中的成员 m_pMain 应不同。
有了基本模板类后,必须为要重写的事件处理程序提供前向声明,然后必须为要处理的事件设置接收器映射。 下面的代码演示如何为 Insert 方法设置事件处理程序,当用户单击数学输入控件上的插入按钮时调用,以及当用户单击数学输入控件上的取消按钮时调用 的 Close 方法。
public:
static const _ATL_FUNC_INFO OnMICInsertInfo; // = {CC_STDCALL, VT_I4, 1, {VT_BSTR}};
static const _ATL_FUNC_INFO OnMICCloseInfo; // = {CC_STDCALL, VT_I4, 0, {VT_EMPTY}};
BEGIN_SINK_MAP(CMathInputControlEventHandler)
SINK_ENTRY_INFO(MATHINPUTCONTROL_SINK_ID, __uuidof(_IMathInputControlEvents), DISPID_MICInsert, OnMICInsert, const_cast<_ATL_FUNC_INFO*>(&OnMICInsertInfo))
SINK_ENTRY_INFO(MATHINPUTCONTROL_SINK_ID, __uuidof(_IMathInputControlEvents), DISPID_MICClose, OnMICClose, const_cast<_ATL_FUNC_INFO*>(&OnMICCloseInfo))
END_SINK_MAP()
由于你将使用数学输入控件,因此设置对相关接口的内部引用会很有用。 在示例类中创建以下实用工具函数来设置此引用。
HRESULT Initialize(IUnknown *pUnknown, CDialog *pMain)
{
m_pMain = pMain;
m_pUnknown = pUnknown;
m_ulAdviseCount = 0;
return S_OK;
}
设置事件处理程序
设置事件接收器后,需要创建事件接收器的实现。 在以下代码示例的两种方法中,事件接收器检索数学输入控件接口的句柄。 在 Insert 函数中,识别结果显示为 MathML,并且控件处于隐藏状态。 在 Close 函数中,数学输入控件处于隐藏状态。
// Methods
HRESULT __stdcall OnMICInsert( BSTR bstrRecoResult)
{
CComQIPtr<IMathInputControl> spMIC(m_pUnknown);
HRESULT hr=S_OK;
if (spMIC)
{
MessageBox(NULL,bstrRecoResult,L"Recognition Result",MB_OK);
hr = spMIC->Hide();
return hr;
}
return E_FAIL;
}
HRESULT __stdcall OnMICClose()
{
CComPtr<IMathInputControl> spMIC;
HRESULT hr = m_pUnknown->QueryInterface<IMathInputControl>(&spMIC);
if (SUCCEEDED(hr))
{
hr = spMIC->Hide();
return hr;
}
return hr;
}
};
继承 main 类中的事件处理程序类
实现模板类后,需要将其继承到要设置数学输入控件的类中。 就本指南而言,此类是一个对话,CMIC_TEST_EVENTSDlg。 在对话框标头中,必须包含必需的标头,并且必须继承创建的模板类。 要继承的类和事件处理程序必须具有前向声明,以便实现模板。 下面的代码示例演示如何执行此操作。
#pragma once
#include <atlbase.h>
#include <atlwin.h>
// include for MIC
#include "micaut.h"
// include for event sinks
#include <iacom.h>
#include "mathinputcontroleventhandler.h"
class CMIC_TEST_EVENTSDlg;
const _ATL_FUNC_INFO CMathInputControlEventHandler<CMIC_TEST_EVENTSDlg>::OnMICInsertInfo = {CC_STDCALL, VT_I4, 1, {VT_BSTR}};
const _ATL_FUNC_INFO CMathInputControlEventHandler<CMIC_TEST_EVENTSDlg>::OnMICCloseInfo = {CC_STDCALL, VT_I4, 0, {VT_EMPTY}};
// CMIC_TEST_EVENTSDlg dialog
class CMIC_TEST_EVENTSDlg : public CDialog,
public CMathInputControlEventHandler<CMIC_TEST_EVENTSDlg>
{
public:
CComPtr<IMathInputControl> m_spMIC; // Math Input Control
注意
模板类型 (CMIC_TEST_EventsDlg)将有所不同,除非你为类命名与示例相同。
初始化类以继承事件接收器 ()
将类设置为从模板类继承后,即可将其设置为处理事件。 这将包括初始化 类,以具有数学输入控件和调用类的句柄。 此外,必须将处理事件中的数学输入控件发送到 CMathInputControlEventHandler 示例类继承的 DispEventAdvise 方法。 从示例类中的 OnInitDialog 方法调用以下代码以执行这些操作。
// includes for implementation
#include "micaut_i.c"
// include for event handler
#include "mathinputcontroleventhandler.h"
...
OnInitDialog{
...
// TODO: Add extra initialization here
CoInitialize(NULL);
HRESULT hr = g_spMIC.CoCreateInstance(CLSID_MathInputControl);
if (SUCCEEDED(hr)){
hr = CMathInputControlEventHandler<CMIC_TEST_EVENTSDlg>::Initialize(m_spMIC, this);
if (SUCCEEDED(hr)){
hr = CMathInputControlEventHandler<CMIC_TEST_EVENTSDlg>::DispEventAdvise(m_spMIC);
if (SUCCEEDED(hr)){
hr = m_spMIC->Show();
}
}
}
}
}
注意
除非将类命名为与示例相同的名称,否则模板类型(在本示例中CMIC_TEST_EventsDlg)将有所不同。