打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
【图】【编程开发】编程开发教程大全

vc++技术内幕(第四版)笔记(第8章)

2016-02-19 0 1 收藏

最近很多朋友喜欢上设计,但是大家却不知道如何去做,别担心有图老师给你解答,史上最全最棒的详细解说让你一看就懂。

第八章:使用ActiveX控件

1,ActiveX控件是一个直接插入到C++程序中的软件模块,以前常称OLE控件(OCX),是基于MS-COM技术。

2,ActiveX控件与普通Windows控件比较:

相同点:ActiveX控件也可看成是一个子窗口(可以看成这样的)。

如果想在对话框上加入ActiveX控件,则只要在对话框编辑器中,把ActiveX控件放在适当的位置上,并在资源模板中标识该控件。如果要在运行的过程中建立ActiveX控件,则可以调用响应控件类的Create成员函数,而且通常在父窗口的WM_CREATE消息控制函数中调用。

不同点:属性和方法。

ActiveX控件不像普通控件那样发送以WM_打头的通知消息给它的包容器窗口,而是激发事件。事件实际上是由控件调用包容器函数。像普通的控件通知消息一样,事件并没有返回值传给ActiveX控件。事件如lick,KeyDown。但对于客户来说时间与控件的通知消息是一样的。

3,在MFC库中,ActiveX控件就像子窗口一样,但在控件窗口和包容器窗口之间有一层重要代码。实际上,ActiveX控件可能没有窗口。当调用Create函数时,并不是直接建立控件窗口,而是把控件代码载入进来,并激发一个“实地激活”(in-place activation)命令。然后ActiveX控件再建立它自己的窗口,通过MFC的CWnd类指针我们可以访问该窗口。不过客户程序最好不要使用ActiveX控件的hWnd句柄。

4,通常ActiveX控件会保存在扩展名为OCX的动态连接库中。包容器程序回根据Windows注册表利用COM技术在需要的时候装入动态连接库。

说明:

1)暂时可以这样认为,如果使用了ActiveX控件,那么在运行时候要装入该ActiveX控件代码。显然在发布含有ActiveX控件的程序时候,必须要包含相应的OCX文件,而且还得提供一个合适的安装程序。

5,安装ActiveX控件:

1)把找到的ActiveX控件动态连接库拷到硬盘上。

2)在WINDOWS注册表中登记注册。(可使用Regsvr32命令行命令)

3)在使用该控件的项目中安装该控件。(选择Project菜单,再选择Add To Project,再选择Components And Controls,再选择Registered ActiveX Controls,这时列表框列出系统已经注册所有的ActiveX控件,选择需要的控件INSERT即可。)

6,ActiveX控件包容器编程:

1)不管ActiveX控件是作为对话框控件,还是做为“子窗口”,MFC和ClassWizard都支持。

2)ActiveX控件编写者设计了ActiveX控件属性供使用者在设计时访问。所有的ActiveX控件属性(包括设计时属性),在运行时都是可以访问的,不过有些属性可能被设计成只读的。

3)当在项目中插入ActiveX控件时,ClassWizard就会产生相应的CWnd的派生类C++类,来满足对空间的方法和属性进行访问要求。控件的属性和方法都有相应的成员函数,同时生成的类还有一个构造函数可用以动态创建ActiveX控件的事例。

4)当在项目中插入ActiveX控件ClassWizard生成的CWnd的派生类C++类中,可以看到其成员函数的代码中都有对InvokeHelper函数的调用,InvokeHelper函数的第一个参数都和对应的属性或方法在ActiveX控件中的分发(dispatch)ID(标识ActiveX控件的方法或属性的)相对应。通过查看ActiveX控件hlp文件可以发现,ActiveX控件的方法在生存的C++类中都有同名的成员函数与之对应,ActiveX控件的属性都有一组Get和Set函数对其操作,其中ActiveX控件的方法和属性操作与生成的C++类成员函数相关联都是通过InvokeHelper函数的调用来完成的,InvokeHelper函数的第一个参数是由Component Gallery(控件提供者)提供的。因为经过这样的处理,所以我们如果要调用ActiveX控件的方法或对其属性进行取和设置操作,只需调用生成的C++类对应的成员函数便可。下面对InvokeHelper单独说明:

CWnd::InvokeHelper
void InvokeHelper( DISPID dwDispID, WORD wFlags, VARTYPE vtRet, void* pvRet, const BYTE* pbParamInfo, ... );

说明:

Call this member function to invoke the OLE control method or property specified by dwDispID, in the context specified by wFlags.
其中参数:
dwDispID:
//Identifies the method or property to be invoked. This value is usually supplied by Component Gallery.

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/bianchengyuyan/)

wFlags:可以为下面些值,指明调用InvokeHelper的目的。

//[ DISPATCH_METHOD ]   The member is invoked as a method. If a property has the same name, both this and the DISPATCH_PROPERTYGET flag may be set.
[ DISPATCH_PROPERTYGET ] The member is retrieved as a property or data member.
[ DISPATCH_PROPERTYPUT ] The member is changed as a property or data member.
[ DISPATCH_PROPERTYPUTREF ] The member is changed by a reference assignment, rather than a value assignment. This flag is valid only when the property accepts a reference to an object.

vtRet:
//Specifies the type of the return value.
VT_EMPTY  void
VT_I2  short
VT_I4  long
VT_R4  float
VT_R8  double
VT_CY  CY
VT_DATE  DATE
VT_BSTR  BSTR
VT_DISPATCH  LPDISPATCH
VT_ERROR  SCODE
VT_BOOL  BOOL
VT_VARIANT VARIANT
VT_UNKNOWN  LPUNKNOWN

pvRet:
//Address of the variable that will that will receive the property value or return value. It must match the type specified by vtRet.

pbParamInfo:一般都设置为NULL
//Pointer to a null-terminated string of bytes specifying the types of the parameters following pbParamInfo.
specifies the types of the parameters passed to the method or property.
...:
//Variable List of parameters, of types specified in pbParamInfo.

5)AppWizard对ActiveX控件的支持是通过在生成的应用程序类的成员函数InitInstance中插入(AfxEnableControlContainer();),同时在响应项目文件的StdAfx.h文件中插入(#includeafxdisp.h)(原因可参考书P38一些说明)。

如果项目中不包含这两行,而又要加入ActiveX控件,则只要手工加入上面两行代码即可。

6)可以对话框编辑器来生成对话框的模板中加入一个或多个ActiveX控件,这样我们可以在对话框模板生成的类中添加数据成员或事件控制函数来获取ActiveX控件的属性或对其控制。

注意:(详细见书P159页的[致WIN32程序员])

实际上,资源模板并不是在对话框编辑器中所看的那样。函数CDialog::DoModal在把对话框模板交给WINDOWS内部的对话框过程之前,要先对模板进行预处理,即:它先会去掉所有的ActiveX控件,有剩下的控件建立对话框窗口,然后再装入ActiveX控件,激活它们并在正确的位置上创建它的窗口。

当模式对话框运行时候,MFC处理所有送给对话框消息时,是不管是有普通控件发送的,还是ActiveX控件发送的。故ActiveX控件虽然不是对话框模板一部分,但用户仍然可以用TAB键在所有的控件间切换。

7)调用UpdateData(FALSE)将会从所有的对话框控件中读取所有属性值。如果只需要得到ActiveX控件属性的话,可以调用ActiveX控件生成的C++类中Get函数(同样设置调用Set函数),这样就提高了效率。

8)事例部分代码对比说明:

代码一:

   CDataExchange dx(this,TRUE);
   DDX_Text(&dx,IDC_DAY,m_sDay);
   DDX_Text(&dx,IDC_MONTH,m_sMonth);
   DDX_Text(&dx,IDC_YEAR,m_sYear);

说明一:

CDataExchange类构造函数:(注,在MFC|SRC|AFXWIN.H中可以看到其构造函数声明,在MFC|SRC|WINCORE.CPP文件中可以看到其构造函数的定义。)

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/bianchengyuyan/)

原型:CDataExchange::CDataExchange(CWnd* pDlgWnd, BOOL bSaveAndValidate);

定义:

CDataExchange::CDataExchange(CWnd* pDlgWnd, BOOL bSaveAndValidate)
{
 ASSERT_VALID(pDlgWnd);
 m_bSaveAndValidate = bSaveAndValidate;
 m_pDlgWnd = pDlgWnd;
 m_hWndLastControl = NULL;
}

//其中m_pDlgWnd和m_bSaveAndValidate是CDataExchange数据成员,可以通过这中方式给它们赋值。
m_pDlgWnd:The dialog box or window where the data exchange takes place.
m_bSaveAndValidate Flag for the direction of DDX and DDV. 详见说明二。

说明二:

//CDataExchange does not have a base class.
//The CDataExchange class supports the dialog data exchange (DDX) and dialog data validation (DDV) routines used by the Microsoft Foundation classes. Use this class if you are writing data exchange routines for custom data types or controls, or if you are writing your own data validation routines.
//A CDataExchange object provides the context information needed for DDX and DDV to take place. The flag m_bSaveAndValidate is FALSE when DDX is used to fill the initial values of dialog controls from data members. The flag m_bSaveAndValidate is TRUE when DDX is used to set the current values of dialog controls into data members and when DDV is used to validate the data values. If the DDV validation fails, the DDV procedure will display a message box explaining the input error. The DDV procedure will then call Fail to reset the focus to the offending control and throw an exception to stop the validation process.

代码二:(是为了比较代码一做些说明的)

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/bianchengyuyan/)

void CActiveXDialog::DoDataExchange(CDataExchange* pDX)
{
 CDialog::DoDataExchange(pDX);//调用基类的DoDataExchange
 //{{AFX_DATA_MAP(CActiveXDialog)
 DDX_Control(pDX, IDC_CALENDAR1, m_calendar);
 DDX_Text(pDX, IDC_DAY, m_sDay);
 DDX_Text(pDX, IDC_MONTH, m_sMonth);
 DDX_Text(pDX, IDC_YEAR, m_sYear);
 /

来源:http://www.tulaoshi.com/n/20160219/1611590.html 第二天:Microsoft基本类库应用程序框架

◎MFC是C++的Microsoft Windows API,如果想要开发WINDOWS的应用程序当然VC/MFC是开发环境的首选。 
◎MFC产生的应用程序使用了标准化的结构。(我现在还体会不出这点的优势所在,请高手指点) 
◎MFC产生的应用程序短而运行速度快。这应该说的是可以很容易的建立动态连接,其实程序还是需要大量的DLL,不过由于WINDOWS上有很多可以用DLL所以应用程序很短,我是这样想的不知对否。 
◎VC++工具降低了编码的复杂性。这点不容质疑比起TC方便太多了。 
◎MFC库功能非常丰富。书上列出了MFC从1.0--4.21的一些特性,我就不废话了,大家应该看看。

   这一章节主要介绍了MFC库的优点,其实我本人认为在某些特定环境下其实MFC不一定就象说的那样好。我想不会有人用纯VC做MIS系统吧,太累了。我是这样理解编程序的,如果把学编程看成学武的话,C/C++语言及编程思想(OOP)是内功,API是基本功(编程思想是内功、API是基本功这适用于任何WIN32编程,不论Visual C++、Delphi、C++Builder、VB......),VC/MFC应该不同武功其中的一种,不同的学习方法效果不一样,只要下工夫也都可以达到一定的境界。真正的高手是有着深厚的内功,扎实的基本功,至于武功招数无所谓了,随便一站不丁不八全无破绽,无招胜有招了。对不住扯远了。

   C++可以通过类库来进行扩展,我们除了可以使用随编译器提供的类库外还可以很方便使用软件公司销售的类库产品,甚至可以自己开发。而应用程序框架是一种类库的超集,它定义了程序的结构。

   下面给出两个示例程序(一个是书上的一个是我写的):

雷神建议: 虽然现在很多书都附CD,CD上有书中所有示例的源代码,但还是应该亲自在VC6用手敲进去。这样可以加深印象以及感受一下编译除错后程序正确运行时的乐趣,因为是纯手工打造。自从我敲了近一百个代码示例后,由于笔误的BUG就很少了,打字速度也提高了。而且最好在原示例代码的基础上做些改动例如别千篇一律的显示HELLO WORLD!换点别的,这样做也可以加深对示例程序的理解。 
   我的HELLO WORLD用AppWizard向导创建一个显示一个字符串的单文档程序,只需要敲入一行语句,主要是体验MFC的强大功能。

1、打开VC++6从菜单选择NEW,给项目命名为”MyApp01“。

2、选择MFC AppWizard[exe] 选项,除STEP 1选择单文档外其他STEP缺省。

3、在Class View选择CMyApp01View类的OnDraw()成员函数双击会在C++编译器看到以下内容 
void CMyApp01View::OnDraw(CDC* pDC) 

CMyApp01Doc* pDoc = GetDocument(); 
ASSERT_VALID(pDoc); 
// TODO: add draw code for native data here 

在 // TODO: add draw code for native data here的位置增加一行代码 
void CMyApp01View::OnDraw(CDC* pDC) 

CMyApp01Doc* pDoc = GetDocument(); 
ASSERT_VALID(pDoc); 
pDC-TextOut(10,10,"雷神愿意和所有学VC的朋友共同进步!"); //-----------增加的一行 
// TODO: add draw code for native data here 

   完了,就这么简单。编译运行。看到了吗?这个程序具备WINDOWS程序的所有特性,例如有菜单、工具条、状态栏、最大化、关闭、甚至还有关于对话框、打印预览.....全了,这就是AppWizard通过MFC动态创建的一个应用程序。从这个小例子可以看出用VC/MFC设计WINDOWS程序多么方便。下面我们看看书上的例子,以便更进一步了解应用程序框架。

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/bianchengyuyan/)

     书上的例子:

1、先建立一个Win32 Application的应用程序。

2、选择Project-Add to project-Files,分别创建一个名为MyApp.h和一个名为MyApp.cpp的文件。

3、添加代码:(最好照敲以下代码到编译器,别用Ctrl+C/Ctrl+V) 
//*********************************************** 
// MyApp.h 
//

class CMyApp:public CWinApp //见下② 

public: 
virtual BOOL InitInstance(); 
};

class CMyFrame:public CFrameWnd 

public: 
CMyFrame(); 
protected: 
afx_msg void OnLButtonDown(UINT nFlags,CPoint point); 
afx_msg void OnPaint(); 
DECLARE_MESSAGE_MAP() 
};

//***************************************************** 
// MyApp.cpp 
//

#include "afxwin.h" 
#include "myapp.h" 
CMyApp theApp;//建立一个CMyAPP对象见下②

BOOL CMyApp::InitInstance () 

m_pMainWnd=new CMyFrame(); 
m_pMainWnd-ShowWindow (m_nCmdShow); 
m_pMainWnd-UpdateWindow (); 
return TRUE; 
}

BEGIN_MESSAGE_MAP(CMyFrame,CFrameWnd) 
ON_WM_LBUTTONDOWN() 
ON_WM_PAINT() 
END_MESSAGE_MAP()

CMyFrame::CMyFrame(){ 
Create(NULL,"MYAPP Application"); 

void CMyFrame::OnLButtonDown (UINT nFlags,CPoint point) 

TRACE("Entering CMyFrame::OnLButtonDown - %lx,%d,%d", 
(long)nFlags,point.x ,point.y); 
}

void CMyFrame::OnPaint () 

CPaintDC dc(this); 
dc.TextOut (0,0,"Hello World!"); 

4、编译运行,报错。为什么呢?原来还没有添加MFC的支持,在Project Setting选项General属性页选择”Use MFC in a Static Library"

5、再Ctrl+F5,哈成功了。

     让我们看看这个程序中的一些元素。

①WinMain函数:并非不存在只是已经被隐藏在应用程序框架内部。

②CMyApp类:CMyApp类的对象代表一个应用程序,CWinApp基类决定它的大部分行为。

③应用程序的启动:当开始运行应用程序时WINDOWS会调用WinMain函数,WinMain会查找该应用程序的全局对象theApp。

④CMyApp::InitInstance成员函数:发现theApp后自动调用重载的虚函数InitInstance来完成主窗口的构造和显示工作。记住这个函数。

⑤CWinApp::Run成员函数:WinMain在调用InitInstance之后紧接着调用Run函数,它被隐藏在基类中负责传递应用程序的消息给相映的窗口。(我把它理解为好象SDK的窗口的过程函数不知对不对)

⑥CMyFrame类:此类的对象代表着应用程序的主窗口。它的构造函数调用基类CFrameWnd的Create函数创建具体的窗口结构。

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/bianchengyuyan/)

⑦CMyFrame::OnLButtonDown函数:演示消息处理机制,当鼠标坐键被按下这一事件被映射到CMyFrame的OnLButtonDown函数上,如果你选择F5进行编译运行的话可以在调试窗口看到TRACE宏显示的类似下面的信息 
Entering CMyFrame::OnLButtonDown - 1,309,119 
Entering CMyFrame::OnLButtonDown - 1,408,221

⑧CMyFrame::OnPaint函数:应用程序每次重新绘制窗口都需要调用此函数,将显示"Hello World!"放在这里是因为每次窗口发生变化时保证"Hello World!"被显示,你可以试着将语句: 
CPaintDC dc(this); 
dc.TextOut (0,0,"Hello World!");

写在别出,例如写在 
void CMyFrame::OnLButtonDown (UINT nFlags,CPoint point) 

TRACE("Entering CMyFrame::OnLButtonDown - %lx,%d,%d", 
(long)nFlags,point.x ,point.y); 
CPaintDC dc(this); 
dc.TextOut (0,0,"Hello World!"); 

运行后当点击左键时显示"Hello World!",但当窗口最小化再最大化时"Hello World!"不见了。

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/bianchengyuyan/)

⑧关闭应用程序:用户关闭应用程序时会有一系列事件发生。首先CMyFrame对象被删除,然后退出Run,进而退出WinMain,最后删除CMyApp对象。

   通过上面的示例我们看见程序的大部分功能包含在基类CWinApp和CFrameWnd中,我们只写了很少的函数,便可以完成很复杂的功能。所以应用程序框架不仅仅是一种类库,它还定义了应用程序的结构,除了基类外还包括WinMain函数,以及用来支持消息处理、诊断、DLL、等都包含在应用程序框架中。

来源:http://www.tulaoshi.com/n/20160219/1602452.html

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
编程中国 - MFC应用程序中浏览PDF、Word文件
OCX和DLL的区别
MFC 机制
MFC中类的组织结构
用VC++实现FLASH的UI启动画面 (zz)
孙鑫VC视频教程笔记之第十八课“ActiveX控件”
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服