Windows核心编程系列文章仅作为实验报告和Windows编程学习参考,不作为任何技术文章,还望大佬们勿喷。
1. 实验名称
ActiveX控件编程
2. 实验环境
- VS2015
- Windows 10
3. 实验目的
- 理解Window系统COM概念,了解ActiveX控件编程基本原理、概念,以及编程流程。
- 理解容器应用程序和服务器应用程序的概念
- 采用ActiveX控件编写一个求两数最大公约数的组件,并调用组件,完成两数最大公约数。
4. 实验内容、步骤及结果
1. 实验内容
- 采用MFC ActiveX编写一个求两数最大公约数组件。如下图所示

- 然后编写一个测试程序,调用组件完成组件调用。如下图所示:

2. 实验步骤
- 首先创建一个MFC ActiveX项目
- 采用MFC ActiveX编写一个求两数最大公约数组件
- 代码如下:
// myActiveXCtrl.cpp : CmyActiveXCtrl ActiveX 控件类的实现。#include "stdafx.h"#include "myActiveX.h"#include "myActiveXCtrl.h"#include "myActiveXPropPage.h"#include "afxdialogex.h"#ifdef _DEBUG#define new DEBUG_NEW#endifIMPLEMENT_DYNCREATE(CmyActiveXCtrl, COleControl)// 消息映射BEGIN_MESSAGE_MAP(CmyActiveXCtrl, COleControl)ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)ON_WM_LBUTTONDOWN()END_MESSAGE_MAP()// 调度映射BEGIN_DISPATCH_MAP(CmyActiveXCtrl, COleControl)DISP_FUNCTION_ID(CmyActiveXCtrl, "AboutBox", DISPID_ABOUTBOX, AboutBox, VT_EMPTY, VTS_NONE)DISP_FUNCTION_ID(CmyActiveXCtrl, "SetNum", dispidSetNum, SetNum, VT_EMPTY, VTS_I4 VTS_I4)DISP_PROPERTY_NOTIFY_ID(CmyActiveXCtrl, "direction", dispiddirection, m_direction, OndirectionChanged, VT_I2)DISP_FUNCTION_ID(CmyActiveXCtrl, "Mcd", dispidMcd, Mcd, VT_I4, VTS_I4 VTS_I4)END_DISPATCH_MAP()// 事件映射BEGIN_EVENT_MAP(CmyActiveXCtrl, COleControl)EVENT_CUSTOM_ID("FirmMsg", eventidFirmMsg, FirmMsg, VTS_NONE)END_EVENT_MAP()// 属性页// TODO: 按需要添加更多属性页。 请记住增加计数!BEGIN_PROPPAGEIDS(CmyActiveXCtrl, 1)PROPPAGEID(CmyActiveXPropPage::guid)END_PROPPAGEIDS(CmyActiveXCtrl)// 初始化类工厂和 guidIMPLEMENT_OLECREATE_EX(CmyActiveXCtrl, "MYACTIVEX.myActiveXCtrl.1",0x85f4510, 0xb64, 0x4e28, 0x88, 0x45, 0x3c, 0x43, 0x8c, 0x22, 0xe9, 0xfe)// 键入库 ID 和版本IMPLEMENT_OLETYPELIB(CmyActiveXCtrl, _tlid, _wVerMajor, _wVerMinor)// 接口 IDconst IID IID_DmyActiveX = { 0x12328EFC, 0x9968, 0x4FCE, { 0xA3, 0x26, 0x65, 0x99, 0x6E, 0xB7, 0x5A, 0x3D } };const IID IID_DmyActiveXEvents = { 0xF481325A, 0xD7BC, 0x4389, { 0x9A, 0xA8, 0x56, 0x16, 0x3A, 0x6C, 0xEE, 0x2B } };// 控件类型信息static const DWORD _dwmyActiveXOleMisc =OLEMISC_ACTIVATEWHENVISIBLE |OLEMISC_SETCLIENTSITEFIRST |OLEMISC_INSIDEOUT |OLEMISC_CANTLINKINSIDE |OLEMISC_RECOMPOSEONRESIZE;IMPLEMENT_OLECTLTYPE(CmyActiveXCtrl, IDS_MYACTIVEX, _dwmyActiveXOleMisc)// CmyActiveXCtrl::CmyActiveXCtrlFactory::UpdateRegistry -// 添加或移除 CmyActiveXCtrl 的系统注册表项BOOL CmyActiveXCtrl::CmyActiveXCtrlFactory::UpdateRegistry(BOOL bRegister){// TODO: 验证您的控件是否符合单元模型线程处理规则。// 有关更多信息,请参考 MFC 技术说明 64。// 如果您的控件不符合单元模型规则,则// 必须修改如下代码,将第六个参数从// afxRegApartmentThreading 改为 0。if (bRegister)return AfxOleRegisterControlClass(AfxGetInstanceHandle(),m_clsid,m_lpszProgID,IDS_MYACTIVEX,IDB_MYACTIVEX,afxRegApartmentThreading,_dwmyActiveXOleMisc,_tlid,_wVerMajor,_wVerMinor);elsereturn AfxOleUnregisterClass(m_clsid, m_lpszProgID);}// CmyActiveXCtrl::CmyActiveXCtrl - 构造函数CmyActiveXCtrl::CmyActiveXCtrl(){InitializeIIDs(&IID_DmyActiveX, &IID_DmyActiveXEvents);// TODO: 在此初始化控件的实例数据。// 设置控件的初始大小SetInitialSize(230, 230);m_a = 16;m_b = 12;m_direction = FALSE;// 控制结果球的显示位置}// CmyActiveXCtrl::~CmyActiveXCtrl - 析构函数CmyActiveXCtrl::~CmyActiveXCtrl(){// TODO: 在此清理控件的实例数据。}// CmyActiveXCtrl::OnDraw - 绘图函数void CmyActiveXCtrl::OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& /* rcInvalid */){if (!pdc)return;// TODO: 用您自己的绘图代码替换下面的代码。CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH));//pdc->Ellipse(rcBounds);// 设置控件的背景颜色CBrush brush(RGB(255, 255, 0));pdc->FillRect(&rcBounds, &brush);// 绘制3个圆// 设置圆的背景色CBrush brush2(RGB(0, 0, 0));// 设置圆心位置POINT p1 = { 40, 120 };POINT p2 = { 190, p1.y };POINT p3 = { (p1.x + p2.x) / 2, m_direction ? p1.y - 50 : p1.y + 50 };// 设置圆的半径int radious = 15;// 画圆CBrush *pOldBrush = pdc->SelectObject(&brush2);pdc->Ellipse(p1.x - radious, p1.y - radious, p1.x + radious, p1.y + radious);pdc->Ellipse(p2.x - radious, p2.y - radious, p2.x + radious, p2.y + radious);pdc->Ellipse(p3.x - radious, p3.y - radious, p3.x + radious, p3.y + radious);// 连接线pdc->MoveTo(p1);pdc->LineTo(p3);pdc->LineTo(p2);// 设置字体的颜色、对齐方式、背景透明pdc->SetTextColor(RGB(255, 255, 255));pdc->SetTextAlign(TA_CENTER);pdc->SetBkMode(TRANSPARENT);// 在圆中写入数值CString strMsg;strMsg.Format(L"%d", m_a);pdc->TextOut(p1.x, p1.y - 9, strMsg);strMsg.Format(L"%d", m_b);pdc->TextOut(p2.x, p2.y - 9, strMsg);strMsg.Format(L"%d", Mcd(m_a, m_b));pdc->TextOut(p3.x, p3.y - 9, strMsg);pdc->SelectObject(pOldBrush);brush.DeleteObject();brush2.DeleteObject();}// CmyActiveXCtrl::DoPropExchange - 持久性支持void CmyActiveXCtrl::DoPropExchange(CPropExchange* pPX){ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));COleControl::DoPropExchange(pPX);// TODO: 为每个持久的自定义属性调用 PX_ 函数。}// CmyActiveXCtrl::OnResetState - 将控件重置为默认状态void CmyActiveXCtrl::OnResetState(){COleControl::OnResetState(); // 重置 DoPropExchange 中找到的默认值// TODO: 在此重置任意其他控件状态。}// CmyActiveXCtrl::AboutBox - 向用户显示“关于”框void CmyActiveXCtrl::AboutBox(){CDialogEx dlgAbout(IDD_ABOUTBOX_MYACTIVEX);dlgAbout.DoModal();}// CmyActiveXCtrl 消息处理程序void CmyActiveXCtrl::SetNum(LONG m_num1, LONG m_num2){AFX_MANAGE_STATE(AfxGetStaticModuleState());// TODO: 在此添加调度处理程序代码m_a = m_num1;m_b = m_num2;// 引发控件重绘调用我们的MCd函数结算结果并显示Invalidate(TRUE);}void CmyActiveXCtrl::OndirectionChanged(){AFX_MANAGE_STATE(AfxGetStaticModuleState());// TODO: 在此添加属性处理程序代码SetModifiedFlag();}LONG CmyActiveXCtrl::Mcd(LONG a, LONG b){AFX_MANAGE_STATE(AfxGetStaticModuleState());// TODO: 在此添加调度处理程序代码if (b == 0)return a;return Mcd(b, a%b);}void CmyActiveXCtrl::OnLButtonDown(UINT nFlags, CPoint point){// TODO: 在此添加消息处理程序代码和/或调用默认值FirmMsg();COleControl::OnLButtonDown(nFlags, point);}
3. 实验结果(实验运行截图)

5. 实验中的问题及心得
- 理解Window系统COM概念,了解ActiveX控件编程基本原理、概念,以及编程流程。
- 学会了采用ActiveX控件编写组件。
- 一开始不会添加方法,事件,属性,后面看了附录2,跟着一步一步做,完成了操作,但是在过程中遇到了组件缺失问题,VS自动下载更新后就可以了。
- 注册ActiveX控件:管理员权限打开cmd,输入regsvr32 “组件所在的文件路径” 注册组件即可注册成功。
6. 附件
以下是实验代码
