步骤 1:创建项目
本教程将带领您逐步骤通过一个非属性化 ATL 项目,该项目创建一个显示多边形的 ActiveX 对象。此对象包括使用户得以更改组成多边形的边数的选项以及刷新显示的代码。
注意 本教程创建与 Polygon(多边形)示例相同的源代码。如果您希望避免手动输入源代码,则可以从 多边形示例摘要下载源代码。然后,您可以一边参考 Polygon 源代码一边阅读教程,或者用它来检查自己的项目中是否有错误。
使用“ATL 项目向导”创建初始 ATL 项目
- 在 Visual Studio 开发环境中,在“文件”菜单上单击“新建”,然后单击“项目”。
- 单击“Visual C++ 项目”文件夹并选择“ATL 项目”。
- 键入
Polygon
作为项目名称:源代码的位置通常默认为 My Documents\Visual Studio Projects,并且将自动创建一个新文件夹。
- 单击“确定”,“ATL 项目向导”随即打开。
- 单击“应用程序设置”以查看可用选项:
- 在创建控件时,如果控件必须是进程内服务器,则将“服务器类型”保留为 DLL。
- 本教程中将不使用属性,因此请确保没有选中“属性化”复选框。
- 将其他选项保留在它们的默认值,然后单击“完成”。
“ATL 项目向导”将通过生成若干个文件来创建项目。可以通过展开 Polygon 对象在解决方案资源管理器中查看这些文件。下面列出了这些文件。
文件 | 说明 |
---|---|
Polygon.cpp | 包含 DllMain、DllCanUnloadNow、DllGetClassObject、DllRegisterServer 和 DllUnregisterServer 的实现。还包含对象映射,该映射是项目中 ATL 对象的列表。它最初是空白的。 |
Polygon.def | 此模块定义文件为链接器提供有关 DLL 所需的导出的信息。 |
Polygon.idl | 接口定义语言文件,描述特定于对象的接口。 |
Polygon.rgs | 此注册表脚本包含用于注册程序的 DLL 的信息。 |
Polygon.rc | 资源文件,最初包含版本信息和含有项目名称的字符串。 |
Resource.h | 资源文件的头文件。 |
Polygonps.def | 此模块定义文件为链接器提供有关代理所需的导出和支持跨单元调用的存根 (stub) 代码的信息。有关详细信息,请参见 COM+ 单元模型。 |
stdafx.cpp | 将包括 (#include) ATL 实现文件的文件。 |
stdafx.h | 将包括 (#include) ATL 头文件的文件。 |
在下一步骤中,您将向项目添加控件。
请参见
步骤 2:添加控件
在此步骤中,您将向项目添加控件,生成此控件,并在 Web 页中对其进行测试。
向 ATL 项目添加对象
- 在“类视图”中,右击“Polygon”项目。
- 指向快捷菜单上的“添加”,然后单击“添加类”。
即会出现“添加类”对话框。左侧的树结构中列出了不同的对象类别:
- 展开树结构并单击“ATL”文件夹。
- 从右侧的模板列表选择“ATL 控件”。单击“打开”。“ATL 控件向导”将打开,从中可以配置控件:
- 键入
PolyCtl
作为简称,并注意其他字段将自动完成。先不要单击“完成”,因为需要做一些更改。
“ATL 控件向导”的“名称”页包含以下字段:
字段 | 内容 |
---|---|
简称 | 为控件输入的名称。 |
类 | 为了实现控件而创建的 C++ 类名。 |
.h 文件 | 为了包含 C++ 类的定义而创建的文件。 |
.cpp 文件 | 为了包含 C++ 类的实现而创建的文件。 |
CoClass | 此控件的组件类的名称。 |
接口 | 接口的名称,控件将在此接口上实现它的自定义方法和属性。 |
类型 | 对控件的说明。 |
ProgID | 可用于查找控件的 CLSID 的可读名称。 |
需要在“ATL 控件向导”中另外进行几个设置。
启用对多格式错误信息和连接点的支持
- 单击“选项”打开“选项”页。
- 选择“连接点”复选框。这将创建对 IDL 文件中输出接口的支持。
还可以使控件成为可插入的,这意味着它可以嵌入到支持嵌入对象的应用程序中,如 Excel 或 Word。
使控件成为可插入的
1. 单击“外观”打开“外观”页。
2. 选择“可插入”复选框,默认情况下该复选框会被清除。
对象显示的多边形将具有纯填充颜色,因此需要添加“填充颜色”常用属性。
添加“填充颜色”常用属性并创建控件
- 单击“常用属性”打开“常用属性”页。
- 在“不支持”下,向下滚动可能常用属性的列表。双击“Fill Color”以将其移动到“支持”列表:
- 这将完成控件的选项。单击“完成”。
在向导创建控件时,有若干代码改变了并添加了一些文件。创建了以下文件:
文件 | 说明 |
---|---|
PolyCtl.h | 包含 C++ 类 CPolyCtl 的大部分实现。 |
PolyCtl.cpp | 包含 CPolyCtl 的其余部分。 |
PolyCtl.rgs | 一个文本文件,包含用于注册控件的注册表脚本。 |
PolyCtl.htm | 一个 Web 页,包含对新创建的控件的引用。 |
向导还执行了以下代码更改:
- 向 stdafx.h 和 stdafx.cpp 文件添加了 #include 语句,以包含支持控件所必需的 ATL 文件。
- 更改了 Polygon.idl 以包含新控件的详细信息。
- 将新控件添加到了 Polygon.cpp 中的对象映射。
现在可以生成控件,查看它的运行情况。
生成和测试控件
生成和测试控件
- 在“生成”菜单上单击“生成 Polygon”。
- 控件完成了生成后,在解决方案资源管理器中双击 PolyCtl.htm。将显示包含控件的 HTML Web 页。您应看到一个矩形和文本
ATL 7.0 : PolyCtl
。这便是您的控件。
注意 当完成本教程时,如果收到 DLL 文件无法创建的错误信息,请关闭 PolyCtl.htm 文件和“ActiveX 控件测试”容器并重新生成解决方案。如果仍无法创建 DLL,请重新启动计算机或注销(如果您使用的是“终端服务”)。
下一步,您将向控件添加自定义属性。
请参见
步骤 3:向控件添加属性
IPolyCtl
是包含控件的自定义方法和属性的接口,您将在其中添加属性。
使用“添加属性向导”添加属性
- 在“类视图”中右击 IPolyCtl(展开“Polygon”分支找到它)。
- 在快捷菜单上单击“添加”,然后单击“添加属性”。
“添加属性向导”随即出现。
- 在属性类型的下拉列表中,选择“short”。
- 键入
Sides
作为属性名: - 单击“完成”完成属性的添加。
将属性添加到接口时,MIDL(编译 .idl 文件的程序)定义检索其值的 Get
方法和设置新值的 Put
方法。这些方法的命名方式是在属性名的前面加上 put_
和 get_
。
“添加属性向导”将必需的行添加到 .idl 文件。它还将 Get
和 Put
函数原型添加到 PolyCtl.h 中的类定义,并将一个空实现添加到 PolyCtl.cpp。您可以通过打开 PolyCtl.cpp 并查找函数 get_Sides
和 put_Sides
来进行检查。
虽然现在有了设置和检索属性的主干函数,但需要有地方存储属性。您将创建存储属性的变量,并相应地更新函数。
创建存储属性的变量并更新 put 和 get 方法
- 从解决方案资源管理器中,打开 PolyCtl.h 并在类定义末尾的
m_clrFillColor
定义后添加下行:short m_nSides;
- 设置
m_nSides
的默认值。向 PolyCtl.h 中的构造函数添加一行,使默认形状成为三角形:CPolyCtl() { m_nSides = 3; }
- 实现
Get
和Put
方法。get_Sides
和put_Sides
函数声明已经添加到 PolyCtl.h。将以下代码添加到 PolyCtl.cpp 以完成这两个方法:STDMETHODIMP CPolyCtl::get_Sides(short *pVal) { *pVal = m_nSides; return S_OK; } STDMETHODIMP CPolyCtl::put_Sides(short newVal) { if (newVal > 2 && newVal < 101) { m_nSides = newVal; return S_OK; } else return Error(_T("Shape must have between 3 and 100 sides")); }
get_Sides
方法通过 pVal
指针返回 Sides
属性的当前值。在 put_Sides
方法中,代码确保用户将 Sides
属性设置为可接受的值。最小值必须是 2,而且由于对每个边都要使用一系列点,100 是合理的最大值限制。
您现在有了一个名为 Sides
的属性。下一步,您将更改绘图代码以便使用它。
请参见
步骤 3:向控件添加属性
IPolyCtl
是包含控件的自定义方法和属性的接口,您将在其中添加属性。
使用“添加属性向导”添加属性
- 在“类视图”中右击 IPolyCtl(展开“Polygon”分支找到它)。
- 在快捷菜单上单击“添加”,然后单击“添加属性”。
“添加属性向导”随即出现。
- 在属性类型的下拉列表中,选择“short”。
- 键入
Sides
作为属性名: - 单击“完成”完成属性的添加。
将属性添加到接口时,MIDL(编译 .idl 文件的程序)定义检索其值的 Get
方法和设置新值的 Put
方法。这些方法的命名方式是在属性名的前面加上 put_
和 get_
。
“添加属性向导”将必需的行添加到 .idl 文件。它还将 Get
和 Put
函数原型添加到 PolyCtl.h 中的类定义,并将一个空实现添加到 PolyCtl.cpp。您可以通过打开 PolyCtl.cpp 并查找函数 get_Sides
和 put_Sides
来进行检查。
虽然现在有了设置和检索属性的主干函数,但需要有地方存储属性。您将创建存储属性的变量,并相应地更新函数。
创建存储属性的变量并更新 put 和 get 方法
- 从解决方案资源管理器中,打开 PolyCtl.h 并在类定义末尾的
m_clrFillColor
定义后添加下行:short m_nSides;
- 设置
m_nSides
的默认值。向 PolyCtl.h 中的构造函数添加一行,使默认形状成为三角形:CPolyCtl() { m_nSides = 3; }
- 实现
Get
和Put
方法。get_Sides
和put_Sides
函数声明已经添加到 PolyCtl.h。将以下代码添加到 PolyCtl.cpp 以完成这两个方法:STDMETHODIMP CPolyCtl::get_Sides(short *pVal) { *pVal = m_nSides; return S_OK; } STDMETHODIMP CPolyCtl::put_Sides(short newVal) { if (newVal > 2 && newVal < 101) { m_nSides = newVal; return S_OK; } else return Error(_T("Shape must have between 3 and 100 sides")); }
get_Sides
方法通过 pVal
指针返回 Sides
属性的当前值。在 put_Sides
方法中,代码确保用户将 Sides
属性设置为可接受的值。最小值必须是 2,而且由于对每个边都要使用一系列点,100 是合理的最大值限制。
您现在有了一个名为 Sides
的属性。下一步,您将更改绘图代码以便使用它。
请参见
步骤 5:添加事件
在此步骤中,您将把 ClickIn
和 ClickOut
事件添加到 ATL 控件。如果用户在多边形的内部单击,将激发 ClickIn
事件;如果用户在外部单击,将激发 ClickOut
。添加事件的任务如下:
- 添加
ClickIn
和ClickOut
方法 - 生成类型库
- 实现连接点接口
添加 ClickIn 和 ClickOut 方法
您在第 2 步中创建 ATL 控件时,选择了“连接点”复选框。这在 Polygon.idl 文件中创建了 _IPolyCtlEvents
接口。请注意,接口名称以下划线开头。此约定指示该接口是内部接口。这样,允许浏览 COM 对象的程序便可以选择不将此接口显示给用户。还请注意,选择“连接点”时在 Polygon.idl 文件中添加了下面的行,指示 _IPolyCtlEvents
是默认源接口:
[default, source] dispinterface _IPolyCtlEvents;
源属性指示控件为通知的源,因此它将对容器调用此接口。
现在将 ClickIn
和 ClickOut
方法添加到 _IPolyCtlEvents
接口。
添加 ClickIn 和 ClickOut 方法
- 在“类视图”中,展开 Polygon 和 PolygonLib 以显示 _IPolyCtlEvents。
- 右击 _IPolyCtlEvents。在快捷菜单上单击“添加”,然后单击“添加方法”。
- 选择
void
作为“返回类型”。 - 在“方法名称”框中输入
ClickIn
。 - 在“参数属性”下,选中“in”框。
- 选择“LONG”作为“参数类型”。
- 键入
x
作为参数名,然后单击“添加”。 - 重复第 5 步到第 7 步,这次键入
y
作为参数名。 - 单击“完成”。
- 重复以上步骤,用相同的 LONG 参数
x
和y
,相同的“参数属性”和相同的void
返回类型定义ClickOut
方法。
检查 Polygon.idl 文件,查看代码是否添加到了 _IPolyCtlEvents
调度接口。
Polygon.idl 文件中的 _IPolyCtlEvents
调度接口现在看起来应像这样:
dispinterface _IPolyCtlEvents { properties: methods: [id(1), helpstring("method ClickIn")] void ClickIn([in]LONG x, [in] LONG y); [id(2), helpstring("method ClickOut")] void ClickOut([in] LONG x, [in] LONG y); };
ClickIn
和 ClickOut
方法接受单击点的 x 和 y 坐标作为参数。
生成类型库
现在请生成类型库,因为“连接点向导”将用它来获取构造控件的连接点接口和连接点容器接口所需的信息。
生成类型库
- 重新生成项目。
- 或 -
- 在“解决方案资源管理器”中右击 Polygon.idl 文件,并在快捷菜单上单击“编译”。
这将创建 Polygon.tlb 文件,它就是您的类型库。从解决方案资源管理器中看不见 Polygon.tlb 文件,因为它是二进制文件,无法直接查看和编辑。
实现连接点接口
为您的控件实现一个连接点接口和一个连接点容器接口。在 COM 中,事件通过连接点机制来实现。为了从 COM 对象接收事件,容器建立一个到 COM 对象实现的连接点的报告连接。由于 COM 对象可以有多个连接点,COM 对象还实现连接点容器接口。通过该接口,容器可以确定哪些连接点受支持。
实现连接点的接口称为 IConnectionPoint,实现连接点容器的接口称为 IConnectionPointContainer。
为了帮助实现 IConnectionPoint,您将使用“实现连接点向导”。该向导通过读取类型库并为每个可以激发的事件实现函数来生成 IConnectionPoint 接口。
使用“实现连接点向导”
- 在“类视图”中,右击控件的实现类
CPolyCtl
。 - 在快捷菜单上单击“添加”,然后单击“添加连接点”。
- 从“源接口”列表中选择“_IPolyCtlEvents”并双击它,以将它添加到“实现连接点”列。单击“完成”。将生成连接点的代理类,这里是指
CProxy_IPolyCtlEvents
。
如果在解决方案资源管理器中查看生成的 _IPolyCtlEvents_CP.h 文件,则将看到它包含一个名为 CProxy_IPolyCtlEvents
的类,该类是从 IConnectionPointImpl
派生的。_IPolyCtlEvents_CP.h 还定义了两个方法 Fire_ClickIn
和 Fire_ClickOut
,它们接受两个坐标参数。当您需要从控件中激发事件时,将调用这些方法。
向导还将 CProxy_PolyEvents
和 IConnectionPointContainerImpl
添加到了控件的多重继承列表。向导还通过将适当的项添加到 COM 映射,为您公开了 IConnectionPointContainer
。
您已完成了实现支持事件的代码。现在,添加一些代码以在适当的时候激发事件。记住,当用户在控件中单击左鼠标按钮时,您将激发 ClickIn
或 ClickOut
事件。若要了解用户何时单击按钮,请添加 WM_LBUTTONDOWN 消息的处理程序。
为 WM_LBUTTONDOWN 消息添加处理程序
- 在“类视图”中,右击 CPolyCtl 类,并在快捷菜单上单击“属性”。
- 在“属性”窗口中,单击“消息”图标,然后从左边的列表中单击“WM_LBUTTONDOWN”。
- 从出现的下拉列表中,单击“<添加> OnLButtonDown”。
OnLButtonDown
处理程序声明将添加到 PolyCtl.h 中,处理程序实现将添加到 PolyCtl.cpp 中。
接下来修改该处理程序。
修改 OnLButtonDown 方法
- 更改 PolyCtl.cpp 中包含
OnLButtonDown
方法的代码(删除向导所放置的任何代码),使它看起来像这样:LRESULT CPolyCtl::OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { HRGN hRgn; WORD xPos = LOWORD(lParam); // horizontal position of cursor WORD yPos = HIWORD(lParam); // vertical position of cursor CalcPoints(m_rcPos); // Create a region from our list of points hRgn = CreatePolygonRgn(&m_arrPoint[0], m_nSides, WINDING); // If the clicked point is in our polygon then fire the ClickIn // event otherwise we fire the ClickOut event if (PtInRegion(hRgn, xPos, yPos)) Fire_ClickIn(xPos, yPos); else Fire_ClickOut(xPos, yPos); // Delete the region that we created DeleteObject(hRgn); return 0; }
此代码利用在 OnDraw
函数中计算的点创建一个区域,以通过调用 PtInRegion
来检测用户的鼠标单击。
uMsg
参数是所处理的 Windows 消息的 ID。这使您可以有一个处理消息范围的函数。wParam
和 lParam
参数是所处理消息的标准值。参数 bHandled
使您得以指定函数是否处理了消息。默认情况下,值设置为 TRUE
,指示函数处理了消息,但也可以将其设置为 FALSE
。这将使 ATL 继续查找要将消息发送到的其他消息处理程序函数。
生成和测试控件
现在尝试您的事件。生成控件并再次启动“ActiveX 控件测试容器”。这次查看事件日志窗口。若要将事件路由到输出窗口,请从“选项”菜单中单击“记录”,然后选择“记录到输出窗口”。插入控件并试着在窗口中单击。请注意,在填充多边形的内部单击将激发 ClickIn
,在它的外部单击将激发 ClickOut
。
接下来将添加属性页。
请参见
步骤 6:添加属性页
属性页作为单独的 COM 对象实现,这使得可以在需要时共享属性页。在此步骤中,您将执行以下任务以将属性页添加到控件:
- 创建属性页资源
- 添加用来创建和管理属性页的代码
- 向控件添加属性页
创建属性页资源
若要将属性页添加到控件,请使用“ATL 添加类向导”。
添加属性页
- 在解决方案资源管理器中,右击“Polygon”。
- 在快捷菜单上单击“添加”,然后单击“添加类”。
- 从模板列表中,选择“ATL 属性页”并单击“打开”。
- 当“ATL 属性页向导”出现时,输入
PolyProp
作为简称: - 单击“字符串”打开“字符串”页,然后输入
&Polygon
作为标题:属性页的“标题”是在该页的选项卡中出现的字符串。“文档字符串”是属性框架用来放在状态栏或工具提示中的说明。请注意,标准属性框架目前不使用该字符串,因此可以将它保留为默认内容。此时将不生成“帮助文件”,因此请删除该文本框中的项。
- 单击“完成”,将创建属性页对象。
创建了以下三个文件:
文件 | 说明 |
---|---|
PolyProp.h | 包含实现属性页的 C++ 类 CPolyProp 。 |
PolyProp.cpp | 包含 PolyProp.h 文件。 |
PolyProp.rgs | 注册属性页对象的注册表脚本。 |
还进行了以下代码更改:
- 新属性页被添加到 Polygon.cpp 中的对象项映射。
PolyProp
类被添加到 Polygon.idl 文件。- 新注册表脚本文件 PolyProp.rgs 被添加到项目资源。
- 对话框模板被添加到属性页的项目资源。
- 您指定的属性字符串被添加到资源字符串表。
现在添加您希望出现在属性页上的字段。
将字段添加到属性页
- 在“解决方案资源管理器”中,双击 Polygon.rc 资源文件。这将打开“资源视图”。
- 在“资源视图”中,展开“Dialog”节点并双击“IDD_POLYPROP”。请注意,出现的对话框是空的,只有一个标签告诉您在此处插入控件。
- 选择该标签,并将其显示文本改为
Sides:
,方法是改变“属性”窗口中的“Caption”文本并调整标签框的大小: - 将工具箱中的一个编辑控件拖动到标签的右侧:
- 最后,使用“属性”窗口将该编辑控件的“ID”更改为
IDC_SIDES
。
这就完成了创建属性页资源的过程。
添加用来创建和管理属性页的代码
既然已经创建了属性页资源,现在需要编写实现代码了。
首先,启用 CPolyProp
类以设置在按“应用”按钮时对象中的边数。
修改 Apply 函数以设置边数
- 像下面这样在 PolyProp.h 中更改
Apply
函数:STDMETHOD(Apply)(void) { USES_CONVERSION; ATLTRACE(_T("CPolyProp::Apply\n")); for (UINT i = 0; i < m_nObjects; i++) { CComQIPtr<IPolyCtl, &IID_IPolyCtl> pPoly(m_ppUnk[i]); short nSides = (short)GetDlgItemInt(IDC_SIDES); if FAILED(pPoly->put_Sides(nSides)) { CComPtr<IErrorInfo> pError; CComBSTR strError; GetErrorInfo(0, &pError); pError->GetDescription(&strError); MessageBox(OLE2T(strError), _T("Error"), MB_ICONEXCLAMATION); return E_FAIL; } } m_bDirty = FALSE; return S_OK; }
一次可以有不止一个客户端附加到属性页,因此 Apply
函数不断循环,并在每个客户端用从编辑框检索的值调用 put_Sides
。您使用的是 CComQIPtr 类,此类对每个对象执行 QueryInterface,以从 IUnknown 接口(存储在 m_ppUnk
数组中)获取 IPolyCtl
接口。
代码现在检查对 Sides
属性的设置是否真正有效。如果失败了,则代码显示一个消息框,其中显示了 IErrorInfo 接口中的错误详细信息。一般情况下,容器向对象请求 ISupportErrorInfo 接口并首先调用 InterfaceSupportsErrorInfo,以确定对象是否支持设置错误信息。您可以跳过此任务。
CComPtr 会通过自动处理引用计数来帮助您,因此您不需要对接口调用 Release。CComBSTR 用 BSTR 处理帮助您,因此您不必执行最终 SysFreeString 调用。您还使用各种字符串转换类之一,因此如有必要可以转换 BSTR(这就是为什么在函数的开始处添加 USES_CONVERSION 宏的原因)。
还需要设置属性页的更新标志以指示应启用“应用”按钮。这在用户更改“边”编辑框中的值时发生。
处理“应用”按钮
- 在“类视图”中,右击 CPolyProp 并在快捷菜单上单击“属性”。
- 在“属性”窗口中,单击“事件”图标。
- 展开事件列表中的“IDC_SIDES”节点。
- 选择“EN_CHANGE”,并从右边的下拉菜单中单击“<添加> OnEnChangeSides”。
OnEnChangeSides
处理程序声明将添加到 Polyprop.h 中,处理程序实现将添加到 Polyprop.cpp 中。
接下来将修改处理程序。
修改 OnEnChangeSides 方法
- 将以下代码添加到 Polyprop.cpp 中的
OnEnChangeSides
方法(删除向导放在那里的任何代码):LRESULT CPolyProp::OnEnChangeSides(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { SetDirty(TRUE); return 0; }
当 WM_COMMAND 消息与 IDC_SIDES
控件的 EN_CHANGE 通知一起发送时,将调用 OnEnChangeSides
。OnEnChangeSides
然后调用 SetDirty
并传递 TRUE
以指示属性页现已更新,应启用“应用”按钮。
向控件添加属性页
由于您的项目中可能有多个控件,“ATL 添加类向导”和“ATL 属性页向导”不会自动将属性页添加到控件中。您需要将项添加到控件的属性映射。
添加属性页
- 打开 PolyCtl.h 并将下行添加到属性映射:
PROP_ENTRY("Sides", 1, CLSID_PolyProp)
控件的属性映射现在看起来像这样:
BEGIN_PROP_MAP(CPolyCtl) PROP_DATA_ENTRY("_cx", m_sizeExtent.cx, VT_UI4) PROP_DATA_ENTRY("_cy", m_sizeExtent.cy, VT_UI4) PROP_ENTRY("FillColor", DISPID_FILLCOLOR, CLSID_StockColorPage) PROP_ENTRY("Sides", 1, CLSID_PolyProp) // Example entries // PROP_ENTRY("Property Description", dispid, clsid) // PROP_PAGE(CLSID_StockColorPage) END_PROP_MAP()
您可能已经用属性页的 CLSID 添加了 PROP_PAGE
宏,但如果按所显示的那样使用 PROP_ENTRY
宏,则在保存控件时也会保存 Sides
属性值。
此宏的三个参数是属性说明、属性的 DISPID 和包含属性的属性页的 CLSID。这很有用,例如将控件加载到 Visual Basic 中并在设计时设置 Sides 的数目时。由于保存了 Sides 的数目,在重新加载 Visual Basic 项目时,Sides 数目将还原。
生成和测试控件
现在生成那个控件并将其插入到“ActiveX 控件测试容器”中。在“测试容器”中,在“编辑”菜单上单击“PolyCtl 类对象”。出现属性页;单击“多边形”选项卡。
“应用”按钮最初是禁用的。开始在“边”框中键入值,“应用”按钮将变成已启用的。输入完值之后,单击“应用”按钮。控件显示更改,“应用”按钮再次被禁用。尝试输入无效的值。您将看到一个消息框,其中包含您从 put_Sides
函数设置的错误说明。
下一步,您将把控件放在 Web 页上。
请参见
步骤 7:将控件放在 Web 页上
控件现已完成。若要查看控件在现实情况中的工作,请将其放在 Web 页上。定义控件时创建了一个包含控件的 HTML 文件。从“解决方案资源管理器”中打开 PolyCtl.htm 文件,可以看到控件在 Web 页上。
在这一步中,您将撰写 Web 页的脚本以响应事件。还将修改控件,让 Internet Explorer 知道控件对于脚本撰写是安全的。
撰写 Web 页的脚本
控件仍然什么也不做,因此请更改 Web 页以响应您发送的事件。
撰写 Web 页的脚本
- 打开 PolyCtl.htm 并选择“HTML”视图。将下面以粗体显示的行添加到构成页的 HTML 代码中。
<HTML> <HEAD> <TITLE>ATL 3.0 test page for object PolyCtl</TITLE> </HEAD> <BODY> <OBJECT ID="PolyCtl" < CLASSID="CLSID:4CBBC676-507F-11D0-B98B-000000000000"> > </OBJECT> <SCRIPT LANGUAGE="VBScript"> <!-- Sub PolyCtl_ClickIn(x, y) PolyCtl.Sides = PolyCtl.Sides + 1 End Sub Sub PolyCtl_ClickOut(x, y) PolyCtl.Sides = PolyCtl.Sides - 1 End Sub --> </SCRIPT> </BODY> </HTML>
您已经添加了一些 VBScript 代码,该代码从控件获取 Sides 属性,并且当您在控件内部单击时,该代码会将边数增加一。如果在控件外部单击,则边数减少一。
指出控件对于脚本撰写是安全的
可以在 Internet Explore 中查看包含控件的 Web 页,或者更方便一些,使用 Visual C++ .NET 中内置的 Web 浏览器视图。若要在 Web 浏览器视图中查看控件,请右击 PolyCtl.htm,然后单击“在浏览器中查看”。
根据当前的 Internet Explorer 安全设置,您可能会收到一个“安全警报”对话框,指出该控件可能对于撰写脚本不安全,并且可能造成损坏。例如,如果您的控件既显示文件又有一个删除文件的 Delete 方法,那么仅在页上查看该控件是安全的。但撰写脚本则不安全,因为有人会调用 Delete 方法。
安全说明 为了学习本教程,您可以更改 Internet Explorer 中的安全设置,以运行未标记为安全的 ActiveX 控件。在控制面板中,单击“Internet 属性”并单击“安全”以更改相应的设置。当完成本教程后,请将安全设置更改回它们原来的状态。
您可以通过编程提示 Internet Explorer 不需要为此特定控件显示“安全警报”对话框。这可以用 IObjectSafety 接口来实现,ATL 在类 IObjectSafetyImpl 中提供了此接口的实现。若要将此接口添加到控件,请将 IObjectSafetyImpl 添加到继承类列表,并在 COM 映射中为其添加一项。
将 IObjectSafetyImpl 添加到控件
- 将以下行添加到 PolyCtl.h 中继承类列表的末尾,并在上一行中添加一个逗号:
public IObjectSafetyImpl<CPolyCtl, INTERFACESAFE_FOR_UNTRUSTED_CALLER>
- 将下行添加到 PolyCtl.h 中的 COM 映射:
COM_INTERFACE_ENTRY(IObjectSafety)
生成和测试控件
生成控件。生成完成后,再次在浏览器视图中打开 PolyCtl.htm。这次 Web 页应该直接显示,没有“安全警报”对话框。在多边形内部单击;边数增加一。在多边形外部单击以减少边数。如果试图将边数减少到 3 以下,您将看到您设置的错误信息。下面是经过一次单击后的控件: