VC++笔记
匈牙利表示法
关于构造函数
显式调用基类的有参数的构造函数:
类继承当中的三种属性:
引用和指针
重复命名错误及解决
。。。
Windows程序运行原理PPT
窗口的创建步骤
- 设计一个窗口类;
typedef struct _WNDCLASS {
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HANDLE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCTSTR lpszMenuName;
LPCTSTR lpszClassName;
} WNDCLASS;
- 注册窗口类;
- 创建窗口;
- 显示及更新窗口。
虚函数
它是C++语言多态性的体现之一;
多态性是指不同类型的对象接收相同的消息时产生不同的行为;
多态性分为编译时的多态性和运行时的多态性;
编译时的多态性是通过函数的重载或运算符的重载来实现的;
运行时的多态性是通过虚函数来实现的;
这两种多态性的方式对应的是两种编译方式,静态联编(早期联编)和动态联编(晚期联编)
虚函数特点如下:
1、 虚函数在重新定义时参数的类型和个数必须和基类的虚函数完全匹配,这一特点与函数重载完全不同;
2、 虚函数所具有的功能只有通过指针 才能得到,虚函数在用对象名和运算符以正常方式调用时,不能达到其功能;
3、 虚函数必须是类的一个成员函数,不能是友元函数,也不能是静态的成员函数;
4、 可以把析构函数定义为虚函数,但是不能将构造函数定义为虚函数;通常释放基类中和其派生类中的动态申请的存储空间时,也要把析构函数定义为虚函数,以便实现撤销对象时的多态性。
纯虚函数是一种特殊的虚函数。
文件操作
1、创建文件实例:fstream file;
2、声明文件操作类型:file.open(“file.txt”,ios::out|ios::app)
3、进行相应的文件读写操作:file.write(&ch,Num)
单文档应用程序SDI :
程序框架:
1) 应 用 类:MyClass.h和MyClass.cpp,继承类CWinApp, ,消息映射机制
2) 文 档 类:MyClassDoc.h和MyClass.cpp ,继承类CDocument, ,消息映射机制
3) 视 图 类:MyClassView.h和MyCassView.cpp, 继承类Cview,消息处理、文档格式化 和文档数据可视化处理,消息映射机制
4) 主框架类:MainFrm.h和MainFrm.cpp ,继承类CframeWnd,创建和控制选单、工具栏 和状态栏等界面元素,消息映射机制
5) “关于”对话框类:MyClass.cpp,继承类Cdialog,数据映射机制
MFC三种消息的区别?
消息驱动机制的形象解释?
接受-发送-处理
ClassWizard产生消息映射所完成的三个内容安排 :
- 在头文件***View.h中声明消息处理函数
afx_msg void OnButtonDown(UNIT nFlags,Cpoint point);
DECLARE_MESSAGE_MAP();
- 在源文件***View.cpp的前面消息映射入口处添加相应的宏
BEGIN_MESSAGE_MAP(C***View,CView)
ON_WM_LBUTTONDOWN()
…
END_MESSAGE_MAP()
- 在***View.cpp文件中写入空的消息处理函数的模板,以便用户填入代码
添加类C***
1、 增加两个文件:头文件C***.h和源文件C***.cpp,这两个文件只是单独的两个文件,与主程序可能没有关联,关联时可以在主程序中包含该类的头文件即可。
2、 由于对话框的代码是以类为木块来设计的,那么在当文档程序中调用对话框,只需要在单文档程序Myclass.cpp源文件上面加上包含类C***的头文件,然后在InitInstance()函数体中的return前面添加两行代码:C*** dlg;dlg.DoModal();即可。
3、具体创建类的方法略
删除类C***步骤
1、在ClassWizard中删除类
2、用delete键“软件”删除类C***对应的.h和.cpp两个文件,取消关联
3、关闭项目,在项目文件夹“硬件”删除类C***对应的.h和.cpp两个文件以及.clw文件
改变按钮标题方法:
1、利用按钮本身的属性对话框修改标题:变量m_MyBtn->SetWindowText(“欢迎”);
2、调用函数:GetDlgItem(IDC_BUTTON1)->SetWindowText(“欢迎”);
ClassWizard创建变量所完成的三个内容安排:
1、在应用类头文件(.h)中添加相关变量的声明
2、在应用类源文件(.cpp)的应用类构造函数中添加变量的初始化代码
3、在应用类源文件(.cpp)的DoDataExchange函数体内添加DDX/DDV代码.进行数据交换
常用控件
1、单选按钮IDC_RADIO:
a) 设置默认选定按钮:CheckRadioButton(IDC_RADIO1,IDC_RADIO4,IDC_RADIO1);
b) 获得选定的单选按钮的ID: int nID = GetCheckedRadioButton(IDC_RADIO1,IDC_RADIO4);
c) 让控件不可用(即变成灰色):GetDlgItem(ID)->EnableWindow(BOOL);
2、 复选框IDC_CHECK:
a) 如果选定了一个框,则其相应的变量为1;
b)
3、 编辑框IDC_EDIT:
a) 其变量的类型有很多:int、char、double…甚至可以是CString
b) 变量类型是前三种的话,那么变量是什么,则编辑框内显示什么;
c) 如果变量是Cstring类型:则显示方法为:m_Edit.Format(“%6.2f”,m);或则m_Ave.LoadString(IDS_STRING);
d) 消息:为编辑框添加EN_CHANGE消息映射
4、 列表框IDC_LIST:
a) 首先定义变量m_List,其类型是Cstring;
b) 列表框显示的是字符串,如果这个字符串代表很多数据,则要将它和其他数据关联;
c) 列表框的项往往用索引来确定,找到索引号,那么就可以找出项的内容,所以要想对项进行操作,第一重要的就是找出它的索引号nIndex,然后就可以调用m_List(实际上是CString)的成员函数来获得根据nIndex来查询项数据、增加项、删除项、查找项等操作;
d) 找出索引号方法:int nIndex = m_List.GetCurSel(),它是整型数据,列表框的第一项索引是从0开始的;
e) 增加项:int nIndex = m_List.AddString(m_strName)
f) 查找项,主要是为了防止重复增加项:m_List.FindString(-1,m_strName)(从头查)
g) 选择项:m_List.SetCurSel(nIdnex);
h) 根据索引号进行操作:
i,删 除 项: m_List.DeleteString(nIdnex)
Ii,获取数据: m_List.GetText(nIndex, m_strName);
SCORE *data=(SCORE *)m_List.GetItemDataPtr(nIndex);
m_List.GetItemData (nIndex,DWORD data);
Iii,关联数据:数据比较多时候,可以预先建立一个数组或则结构体
Int m_List.SetItemDataPtr(nIndex,new SCORE(data));(结构体SCORE)
DOUBLE m_List.SetItemDataPtr(nIndex)
5、 组合框IDC_COMBO
a) 组合框是集编辑框和列表框于一体,所以既可以编辑输入,也可以列表显示;
b) 有列表框的功能,也是根据索引号来增加项,删除项,查找项,还可以用此索引号来关联数据或则数据指针;
c) 组合框的通知消息中最为常用的是:CBN_SELCHANGE (当组合框中的当前选择项将要改变时发送此消息);注意这个消息是为控件本身添加的;
6、 滚动条IDC_SCROLLBAR
a) 基本操作:
设置滚动条范围m_Scroll.SetScrollRange(0,255)
获取滚动条范围void GetScrollRange(lpMinpos, lpMaxpos)
设置滚动条的当前位置m_Scroll.SetScrollPos(m_RValue)
获取滚动条的当前位置int GetScrollPos()
b) 消息:
为对话框添加消息WM_HSCROLL或则WM_VSCROLL,因为滑动条(下面将提到)和滚动条都可以产生WM_HSCROLL或则WM_VSCROLL消息,因此当它们处在同一方向时,就需要添加代码判断是谁产生的消息;
点击滚动条的相应位置就产生相应的消息,见下图
|
|
SB_LINELEFT SB_LINERIGHT SB_PAGELEFT SB_PAGERIGHT |
|
|
|
|
7、 滑动条IDC_SLIDER
- 基本操作:
设置滚动条范围m_Slide.SetRange(0,255)
获取滚动条范围void GetRange(lpMinpos, lpMaxpos)
设置滚动条的当前位置m_ Slide.SetPos(int m_RValue)
获取滚动条的当前位置int GetPos()
设置滑动条控件中的一个刻度线的位置:BOOL SetTic(int nTri)
设置刻度线的疏密程度:void SetTicFreq(int nFre)
删除当前刻度线:void ClearTics(BOOL)
设置滑动条的开始和结束位置:void SetSelection(int nMin,int nMax)
- 消息: 消息代码都来自于WM_HSCROLL或WM_VSCROLL消息
8、 旋转按钮IDC_SPIN
a) 基本操作:
- 设置基数int SetBase( int nBase );
- 设置旋转按钮控件的当前位置和范围int SetPos( int nPos );
void SetRange( int nLower, int nUpper );
- 设置和获取旋转按钮控件的加速度BOOL SetAccel( int nAccel, UDACCEL* pAccel );
b) 通知消息:
旋转按钮控件的通知消息只有一个:UDN_DELTAPOS,它是当控件的当前数值将要改变时向其父窗口发送的
9、 标签控件IDC_TAB
a) 标签控件的基本操作 :…
- i. m_Tab.SetMinTabWidth(80); // 设置标签项的最小宽度
- ii. m_Tab.SetPadding(CSize(12,3)); // 设置标签项和图标周围的间隔
- iii. m_Tab.SetCurSel(0);//设置默认选定项
- iv. m_pTabDlg->Create(IDD_DIALOG3,&m_Tab);//指定IDD_DIALOG3的父窗口是m_Tab指向的窗口
b) 标签控件的通知消息:为控件映射TCN_SELCHANGE消息
c) 为一个新建的Dialog创建一个类的时候,可以用一个指针来指向这个窗口
CTab1Dlg *m_pTab1Dlg;
d) 注意创建的子窗口是无模式对话框m_pTab1Dlg->Create(IDD_DIALOG1,&m_Tab);
10、 消息对话框
a) 最简单的一类对话框,只是用来显示信息的。MFC类库中提供相应的函数实现这样的功能,只要在程序任何地方调用它们。
b) 函数原型:
int AfxMessageBox( LPCTSTR lpszText, UINT nType = MB_OK, UINT nIDHelp = 0 );
int MessageBox( LPCTSTR lpszText, LPCTSTR lpszCaption = NULL, UINT nType = MB_OK );
11、
菜单
- 菜单操作有两种方法:一种是ResourceView标签操作,但是只能进行简单的增加和删除,还有一种是通过编程进行菜单操作
- 菜单的编程控制
a) 基本操作:Cmenu类
l 创建菜单:BOOL CreateMenu( ); // 产生一个空菜单
BOOL CreatePopupMenu( ); // 产生一个空的弹出式子菜单
l 装入菜单:BOOL LoadMenu( LPCTSTR lpszResourceName );
BOOL LoadMenu( UINT nIDResource );
l 添加菜单项:末尾处增加与指定位置添加
BOOL AppendMenu( UINT nFlags, UINT nIDNewItem = 0,LPCTSTR lpszNewItem = NULL );
BOOL AppendMenu( UINT nFlags, UINT nIDNewItem, const CBitmap* pBmp );
BOOL InsertMenu( UINT nPosition, UINT nFlags,UINT nIDNewItem = 0, LPCTSTR lpszNewItem = NULL );
BOOL InsertMenu( UINT nPosition, UINT nFlags, UINT nIDNewItem, const CBitmap* pBmp );
l 删除菜单项:BOOL DeleteMenu( UINT nPosition, UINT nFlags );
一定要调用CWnd::DrawMenuBar使菜单更新
l 获取菜单项:下面的三个CMenu成员函数分别获得菜单的项数、菜单项的ID号以及弹出式子菜单的句柄。
UINT GetMenuItemCount( ) const;该函数用来获得菜单的菜单项数,调用失败后返回-1。
UINT GetMenuItemID( int nPos ) const;该函数用来获得由nPos指定菜单项位置(以0为基数)的菜单项的标识号,若nPos是SEPARATOR,则返回-1。
CMenu* GetSubMenu( int nPos ) const; 该函数获得指定菜单的弹出式菜单的菜单句柄
- 举例说明
- CMenu* pSysMenu = GetMenu(); // 获得主菜单句柄
- CMenu* pSubMenu = pSysMenu->GetSubMenu(1);// 获得第二个子菜单的句柄
- CString StrMenuItem("新的菜单项");
- pSubMenu->AppendMenu(MF_SEPARATOR); // 增加一水平分隔线
- pSubMenu->AppendMenu(MF_STRING,ID_NEW_MENUITEM,StrMenuItem);
快捷菜单
用资源编辑器和MFC库的CMenu::TrackPopupMenu函数创建这样的菜单,CMenu::TrackPopupMenu函数原型如下:
BOOL TrackPopupMenu( UINT nFlags, int x, int y, CWnd* pWnd, LPCRECT lpRect = NULL );
x和y表示菜单的水平坐标和菜单的顶端的垂直坐标。pWnd表示弹出菜单的窗口。lpRect是一个RECT结构或CRect对象指针,表示一个矩形区域,单击这个区域时,弹出菜单不消失。当lpRect为NULL时,若击在菜单外面,菜单立刻消失。
举例:
在CMainFrame类加入WM_CONTEXTMENU消息处理函数,代码。
void CMainFrame::OnContextMenu(CWnd* pWnd, CPoint point)
{
CMenu menu;
menu.LoadMenu(IDR_MYFLOATMENU);
menu.GetSubMenu(0)
->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON, point.x, point.y, this);
}
工具栏
工具栏和菜单相结合的方法:将工具栏按钮的ID号设置的和相应的菜单栏的ID号码一样就行了;
状态栏
AppWizard创建的SDI或MDI应用程序框架中,有一个静态的indicator数组,它是在MainFrm.cpp文件中定义的,被MFC用作状态栏的定义。
1.在状态栏上显示文本
有三种办法可以在状态栏窗格显示文本信息:
(1)调用CWnd::SetWindowText更新信息行窗格(或窗格0)中的文本。由于状态栏也是一种窗口,故在使用时可直接调用。若状态栏变量为m_wndStatusBar,则m_wndStatusBar. SetWindowText(“消息”)语句将在信息行窗格(或窗格0)内显示“消息”字样。
(2)手动处理状态栏的ON_UPDATE_COMMAND_UI更新消息,并在处理函数中调用CCmdUI::SetText函数。
(3)调用CStatusBar::SetPaneText函数更新任何窗格(包括信息行窗格)中的文本。此函数原型描述如下:
BOOL SetPaneText( int nIndex, LPCTSTR lpszNewText, BOOL bUpdate = TRUE );
2.交互对象的更新:
像菜单栏、工具栏这样的就是交互对象,可能是因为它们有相同的ID,功能一样,当一个起作用的时候,另一个的状态要做相应的改变。
为能使交互对象动态更新,MFC通过ClassWizard直接映射交互对象的更新命令消息来实现。自动将用户交互对象的ID号与ON_UPDATE_COMMAND_UI宏相连接并产生处理更新消息的相应函数,此消息处理函数只有一个参数,它是指向CCmdUI对象的指针。CCmdUI 类仅用于ON_UPDATE_COMMAND_UI处理函数,它的成员函数将对菜单项、工具按钮等用户交互对象起作用。
为什么新建的选单不能添加子选单?
SetWindowLong(hWnd,GWL_STYLE,pNewStyle)?
实例:“在列表视图中以四种方式显示当前文件夹中的所有文件“
- 要 求:
1) 用四种不同方式显示文件:“大图标“小图标”“列表视图”“报表视图”;
2) 用快捷键ctrl+shift+X来切换显示方式;
3) 双击图标时候弹出消息对话框,对话框显示文件类型名;
- 关键点:
1) 如何获取当前文件夹中的所有文件;
2) 如何获取各个文件的图标以便添加到与列表控件相关联的图像列表中去;
3) 如何设置报表显示方式中的标题头;
- 解 决:
1) 通过MFC类CfileFind来查询文件;
2) 使用API函数SHGetFileInfo来获取文件信息,包括文件图标;
3) 使用LVCOLUMN结构体来设置标题头;
- 步 骤:
1) 建立列表控件风格切换函数(需要调用函数SetWindowLong(hWnd,GWL_STYLE,pNewStyle)),方便之后的函数调用;
2) 将项目工作区窗口切换到ResourceView页面,打开Accelerator节点下的IDR_MAINFRAME,为其添加一个键盘加速键Ctrl+Shift+X,其ID号为ID_VIEW_CHANGE。用ClassWizard为CEx_ListView类添加ID_VIEW_CHANGE的COMMAND消息映射函数,并添加相应代码(这里的代码里面就要调用相应的风格切换函数);
3) 用ClassWizard为CEx_ListView类添加NM_DBLCLK消息映射函数,并添加相应代码(可根据用户要求来写,本例需要弹出消息对话框,那么需要调用Messagebox());
4) 添加查找文件、关联图标等的代码(在CEx_ListView::OnInitialUpdate中添加代码)
a) 创建图像列表,用来保存文件图标
b) 创建字符串数组类,用来保存文件类型,它无需跟列表控件关联,因为它主要是用来添加不重复的图标的
c) 创建(获取)列表控件“句柄”,用来显示等操作
d) 关联图像列表和列表控件,列表控件中显示的图标都是从图标列表中调取的
e) 查找当前目录下的文件,根据目录依次查找文件并获取文件的信息
f) 获取文件的信息(图标,文件完整名称(含扩展名),文件大小,文件类型,文件最后修改时间)
g) 往字符串数组类中添加文件类型信息
h) (如果文件类型不重复就)往图像列表中添加文件图标信息
i) 设置报表模式显示的表头格式以及列宽
j) 设置文件大小的显示格式
k) 设置文件最后修改时间的显示格式
l) 设置默认显示方式为报表显示
5) 根据报表效果的显示方式来安排程序,报表显示方式如下,可见程序有如下几部分:
总结步骤:
1) 加入List Control控件
2) 为该控件声明一个对象,CListCtrl m_list;使用类向导来做
3) 设置CListCtrl的属性
m_list.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
m_list.SetBkColor(RGB(247,247,255));
m_list.SetTextColor(RGB(0,0,255));
m_list.SetTextBkColor(RGB(247,247,255));
4) 设置列名
m_list.InsertColumn(0, "姓名", LVCFMT_LEFT, 80);
m_list.InsertColumn(1, "现居地", LVCFMT_LEFT, 100);
m_list.InsertColumn(2, "联系电话", LVCFMT_LEFT, 110);
尤其要记得要将控件的类型修改为"Report"类型.
5) 设置各列的内容
m_list.InsertItem(0,"李");
m_list.SetItemText(0,1,"北京");
m_list.SetItemText(0,2,"13111111111");
m_list.InsertItem(1,"张");
m_list.SetItemText(1,1,"上海");
m_list.SetItemText(1,2,"13222222222");
6) 读取数据
m_list.GetItemText(行数, 列数);
7) 每行前有复选框的列表
初始化时使用LVS_EX_CHECKBOXES属性
DWORD dwStyle;
dwStyle = m_list.GetStyle();
dwStyle |= LVS_EX_GRIDLINES |LVS_EX_FULLROWSELECT|LVS_EX_CHECKBOXES ;
m_list.SetExtendedStyle(dwStyle);
设置选中:
m_list.SetItemState (行数,0x2000, LVIS_STATEIMAGEMASK);//设为选中状态
判断是否选中:
m_list.GetItemState(行数,LVIS_STATEIMAGEMASK)==0x2000//选中
切分窗口
A CSplitterWnd is usually embedded in a parent CFrameWnd or CMDIChildWnd object by taking the following steps:
- Embed a CSplitterWnd member variable in the parent frame.
- Override the parent frame’s OnCreateClient member function.
- Call the CreateStatic member function from within the overridden CFrameWnd::OnCreateClient.
怎样设置透明效果
1) 用SetLayedWindowAttributes实现整个窗口的半透明效果
BOOL CDlgTop::OnInitDialog()
{
CDialog::OnInitDialog();
//以下代码是我从别人那里抄来的,主要是使CDlgTop对话框透明
//出处为www.vckbase.com,不用细看其内容
// 添加透明扩展样式
SetWindowLong(this-> GetSafeHwnd(),GWL_EXSTYLE,
GetWindowLong(this-> GetSafeHwnd(),GWL_EXSTYLE)^0x80000);
// 添加库
HINSTANCE hInst = LoadLibrary( "User32.DLL ");
// 读取函数指针
if(hInst)
{
typedef BOOL (WINAPI *MYFUNC)(HWND,COLORREF,BYTE,DWORD);
MYFUNC fun = NULL;
//取得SetLayeredWindowAttributes函数指针
fun=(MYFUNC)GetProcAddress(hInst, "SetLayeredWindowAttributes ");
if(fun)fun(this-> GetSafeHwnd(),0,128,2);
FreeLibrary(hInst);
}
return TRUE;
}
// 函数原型如下:
BOOL SetLayeredWindowAttributes(
HWND hwnd, // 窗口
COLORREF crKey, // 颜色键
BYTE bAlpha, // alpha值
DWORD dwFlags // 透明方法
);
2) 怎样实现窗口的半透明渐变效果
3) Static控件背景透明大法
常用添加dialog的OnCtlColor方法。。。修改代码如下
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
if(nCtlColor==CTLCOLOR_STATIC)
{
pDC->SetBkMode(TRANSPARENT);
pDC->SetTextColor(RGB(255,255,255));
return (HBRUSH)::GetStockObject(NULL_BRUSH);
}
怎样制作电子时钟
CWnd::OnCtlColor
This method is called by the framework when a child control is about to be drawn. Most controls send this message to their parent, usually a dialog box, to prepare the pDC for drawing the control using the correct colors.
用双击事件关闭窗口WM_LBUTTONDCLK
vc实现平滑地关闭窗口?
使窗口居中并且占整个屏幕的90%
BOOL CMainFrame::PreCreateWindow ( CREATESTRUCT& cs)
{
// center window at 90% of full screen
int xSize = ::GetSystemMetrics (SM_CXSCREEN);
int ySize = ::GetSystemMetrics (SM_CYSCREEN);
cs.cx = xSize*9/10;
cs.cy = ySize*9/10;
cs.x = (xSize-cs.cx)/2;
cs.y = (ySize-cs.cy)/2;
return CMainFrame::PreCreateWindow(cs);}
文件操作详解
- 文件的创建
- 文件的读写
- 普通方法:直接使用CFile进行
// 对文件进行读操作
char sRead[2];
CFile mFile(_T("user.txt"),CFile::modeRead);
if(mFile.GetLength()<2)
return;
mFile.Read(sRead,2);
mFile.Close();
// 对文件进行写操作
CFile mFileW(_T("user.txt"),CFile::modeWrite|CFile::modeCreate);
mFileW.Write(sRead,2);
mFileW.Flush();
mFileW.Close();
- 简单方法:使用CArchive
首先使用CFile声明一个对象,然后用这个对象的指针做参数声明一个CArchive对象,我们就可以方便地存储各种复杂的数据类型了。
//对文件进行写操作
CString strTemp;
CFile mfile;
mfile.Open("E:\\201101-201102\\C++项目文件\\ComDlg\\user.txt",
CFile::modeCreate|CFile::modeNoTruncate|CFile::modeWrite);
CArchive ar(&mfile,CArchive::store);
ar<<strTemp;
ar.Close();
mfile.Close();
// 对文件进行读操作
CFile mfilew;
if (mfilew.Open("E:\\201101-201102\\C++项目文件\\ComDlg\\user.txt",CFile::modeRead)==0)
return;
CArchive ar1(&mfilew,CArchive::load);
ar1>>strTemp;
ar1.Close();
mfilew.Close();
- CArchive的<<和>>操作符用于简单数据类型的读写,对于CObject派生类的存 取要使用ReadClass()和WriteClass()还可以进行类的读写,如:
// 存储CAboutDlg类
ar.WriteClass(RUNTIME_CLASS(CAboutDlg));
//读取CAboutDlg类
CRuntimeClass* mRunclass = ar.ReadClass();
//使用CAboutDlg类
CObject* pObject = mRunclass->CreateObject();
((CDialog* )pObject)->DoModal();
在文档区域绘图
- 画笔
创建画笔-选择画笔-绘制图形-恢复画笔
void CMyView::OnDraw( CDC* pDC )
{
CPen newPen( PS_SOLID, 2, RGB(0,0,0) ) );
CPen* oldPen = pDC->SelectObject(&newPen);
pDC->SelectObject( &newPen );
pDC->MoveTo(...);
pDC->LineTo(...);
//pDC->SelectStockObject( BLACK_PEN ); // newPen被分离出来
pDC->SelectObject(oldPen); // 恢复原来画笔
newPen.Detach(); // 将画笔对象与其构造的内容分离,以便能再次构造画笔
}
- 字体
void CMyView::OnDraw( CDC* pDC )
{
CFont font;
LOGFONT lf;
memset(&lf, 0, sizeof(LOGFONT)); // zero out structure
lf.lfHeight = 12; // request a 12-pixel-height font
strcpy(lf.lfFaceName, "Arial"); // request a face name "Arial"
VERIFY(font.CreateFontIndirect(&lf)); // create the font
// Do something with the font just created...
CClientDC dc(this);
CFont* def_font = dc.SelectObject(&font);
dc.TextOut(5, 5, "Hello", 5);
dc.SelectObject(def_font);
// Done with the font. Delete the font object.
font.DeleteObject();
}
在文档区显示位图资源
- 图标
由于位图不能直接显示在实际设备中,因此对于GDI位图的显示则必须遵循下列步骤:
(1) 调用CBitmap类的CreateBitmap、CreateCompatibleBitmap以及 CreateBitmapIndirect函数创建一个适当的位图对象。
(2) 调用CDC::CreateCompatibleDC函数创建一个内存设备环境,以便位图在内 存中保存下来,并与指定设备(窗口设备)环境相兼容;
(3) 调用CDC::SelectObject函数将位图对象选入内存设备环境中;
(4) 调用CDC::BitBlt或CDC::StretchBlt函数将位图复制到实际设备环境中。
(5) 使用之后,恢复原来的内存设备环境。
void CSDITextView::OnDraw(CDC* pDC)
{
CSDITextDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
CBitmap m_bmp;//CObject的派生类
m_bmp.LoadBitmap(IDB_BITMAP1); // 调入位图资源
BITMAP bm;
m_bmp.GetObject(sizeof(BITMAP),&bm);
CDC dcMem; // 定义并创建一个内存设备环境
dcMem.CreateCompatibleDC(pDC);
CBitmap *pOldbmp = dcMem.SelectObject(&m_bmp); // 将位图选入内存设备环境中
pDC->StretchBlt(0,0,bm.bmWidth,bm.bmHeight,&dcMem,0,0,1024,768,SRCCOPY);
// 将位图复制到实际的设备环境中
//用BitBlt函数显示速度比StretchBlt快 StretchBlt可以对图像扩大或则缩小
dcMem.SelectObject(pOldbmp); // 恢复原来的内存设备环境
}
- 光标
BOOL CMainFrame::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
// TODO: Add your message handler code here and/or call default
BOOL bRes = CFrameWnd::OnSetCursor(pWnd, nHitTest, message);
if (nHitTest == HTCLIENT|HTCAPTION|HTBOTTOMLEFT )
{
HCURSOR hCursor;
hCursor = AfxGetApp()->LoadCursor(IDC_CURSOR1);
SetCursor(hCursor);
bRes = TRUE;
}
return bRes;
}
在窗口画线的几种方法
- 利用SDK全局函数实现画线功能
void CDrawLineView::OnLButtonDown(UINT nFlags, CPoint point)
{
m_pOrign = point;
CView::OnLButtonDown(nFlags, point);
}
void CDrawLineView::OnLButtonUp(UINT nFlags, CPoint point)
{
HDC hDC;
hDC = ::GetDC(m_hWnd);
MoveToEx(hDC,m_pOrign.x,m_pOrign.y,NULL);
LineTo(hDC,point.x,point.y);
::ReleaseDC(m_hWnd,hDC);
CView::OnLButtonUp(nFlags, point);
}
- 利用MFC的CDC类实现画线功能
将上面蓝色部分替换成以下代码,实现功能是一样的
CDC* pDC = GetDC();
pDC->MoveTo(m_pOrign);
pDC->LineTo(point);
ReleaseDC(pDC);
- 利用MFC的CClientDC类来实现画图功能
将上面蓝色部分替换成以下代码,实现功能是一样的
CClientDC dc(this);//this指向客户区//换成GetParent()就可以在框架上面画线了
dc.MoveTo(m_pOrign);
dc.LineTo(point);
- 利用MFC的CWindowDC()画线
这样可以绘图到工具栏/菜单栏区域(非客户区)CWindowDC dc(GetParent());
- 在桌面窗口上面画线CWindowDC dc(GetDesktopWindow());
线条的属性
要利用属性,按以下步骤:
创建GDI对象(如画笔工具),用SelectObject()将画笔工具选入设备描述表,绘制完毕恢复画笔
颜色
void CDrawLineView::OnLButtonDown(UINT nFlags, CPoint point)
{
m_pOrign = point;
CView::OnLButtonDown(nFlags, point);
}
void CDrawLineView::OnLButtonUp(UINT nFlags, CPoint point)
{
CPen pen(PS_SOLID,4,RGB(255,0,0));//创建GDI对象
CWindowDC dc(GetDesktopWindow());//
CPen* pOldPen = dc.SelectObject(&pen);//选入设备表
dc.MoveTo(m_pOrign);
dc.LineTo(point);
dc.SelectObject(pOldPen);
CView::OnLButtonUp(nFlags, point);
}
绘制透明的矩形,使它不挡住下面的图形
void CDrawLineView::OnLButtonUp(UINT nFlags, CPoint point)
{
CClientDC dc(this);
CBrush* pBrush = CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
CBrush* pOleBrush = dc.SelectObject(pBrush);
dc.Rectangle(CRect(m_pOrign,point));
dc.SelectObject(pOleBrush);
CView::OnLButtonUp(nFlags, point);
}
绘制连续的线条
m_bDraw用来判断左键是否按下,按下就开始划线,松开就结束这段线。
void CDrawLineView::OnLButtonDown(UINT nFlags, CPoint point)
{
m_bDraw = TRUE;
m_pOrign = point;
CView::OnLButtonDown(nFlags, point);
}
void CDrawLineView::OnLButtonUp(UINT nFlags, CPoint point)
{
m_bDraw = FALSE;
CView::OnLButtonUp(nFlags, point);
}
void CDrawLineView::OnMouseMove(UINT nFlags, CPoint point)
{
CClientDC dc(this);
if(m_bDraw == TRUE)
{
dc.MoveTo(m_pOrign);
dc.LineTo(point);
m_pOrign = point;//修改起点
}
CView::OnMouseMove(nFlags, point);
}
绘制扇形 :只需将以上代码的蓝色部分去掉即可
通过画刷填充在鼠标拖曳的矩形
void CDrawLineView::OnLButtonDown(UINT nFlags, CPoint point)
{
m_pOrign = point;
CView::OnLButtonDown(nFlags, point);
}
void CDrawLineView::OnLButtonUp(UINT nFlags, CPoint point)
{
CBrush bru(RGB(255,1,1));
CClientDC dc(this);
dc.FillRect(CRect(m_pOrign,point),&bru);
CView::OnLButtonUp(nFlags, point);
}
创建文本插入符
int CTextView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
CreateSolidCaret(20,100);//创建20*100大小的插入符
ShowCaret();//显示出来
return 0;
}
添加字符串资源
BOOL LoadString(nID)
字符输入
void CTextView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) //消息WM_CHAR
{
CClientDC dc(this);
TEXTMETRIC tm;
dc.GetTextMetrics(&tm);
if (0x0d == nChar)//回车
{
m_strLine.Empty();
m_ptOrign.y += tm.tmHeight;
}
else if (0x08 == nChar)//退格运用视觉小技巧:删除的文字颜色和背景颜色一样就行了
{
COLORREF clr = dc.SetTextColor(dc.GetBkColor());//返回文本先前的颜色
dc.TextOut(m_ptOrign.x,m_ptOrign.y,m_strLine);
m_strLine = m_strLine.Left(m_strLine.GetLength()-1);
dc.SetTextColor(clr);
}
else
{
m_strLine += nChar;
}
CSize sz = dc.GetTextExtent(m_strLine);//使插入符也跟着移动
CPoint pt;
pt.x = m_ptOrign.x+sz.cx;
pt.y = m_ptOrign.y;
SetCaretPos(pt);//当然插入符的初始位置及大小在OnDraw中已经设置好
dc.TextOut(m_ptOrign.x,m_ptOrign.y,m_strLine);
CView::OnChar(nChar, nRepCnt, nFlags);
}
void CTextView::OnLButtonDown(UINT nFlags, CPoint point) //消息WM_LBUTTONDOWN
{
SetCaretPos(point);
m_strLine.Empty();//新位置清空字符串
m_ptOrign = point;//保存点
CView::OnLButtonDown(nFlags, point);
}
字体设置
卡拉OK字幕变色效果
void CTextView::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
m_nWidth += 5;
CClientDC dc(this);
TEXTMETRIC tm;
dc.GetTextMetrics(&tm);//获得当前字体的字体信息
CString str;
str.LoadString(IDS_STRINGVC);
dc.SetTextColor(RGB(0,255,0));
dc.TextOut(0,200,str);//运行时就输出一行字幕
CRect rect;
rect.left = 0;
rect.top = 200;
rect.right = m_nWidth;
rect.bottom = rect.top + tm.tmHeight;//设置矩形框的大小
dc.SetTextColor(RGB(255,0,0));
dc.DrawText(str,rect,DT_LEFT);//开始从左往右用红色覆盖绿色字幕
rect.top = 150;
rect.bottom = rect.top + tm.tmHeight;
dc.DrawText(str,rect,DT_RIGHT);//字幕从左往右滚动显示
CSize sz = dc.GetTextExtent(str);//获得字符串的宽度和长度
if (m_nWidth > sz.cx)//nWidth大于字符串长度时候
{
m_nWidth = 0;
dc.SetTextColor(RGB(0,255,0));
dc.TextOut(0,200,str);
}
CView::OnTimer(nIDEvent);
}
图形标记菜单
在框架类的OnCreate函数中的return 0;句之前插入一下语句:
m_bitmap.LoadBitmap(IDB_BITMAP1);
GetMenu()->GetSubMenu(0)->SetMenuItemBitmaps(5,MF_BYPOSITION,&m_bitmap,&m_bitmap);
注意此IDB_BITMAP1的尺寸一定要合适,可以用一下方法获得系菜单标记图形的大小:
CString str;
str.Format("x=%d,y=%d",GetSystemMetrics(SM_CXMENUCHECK),
GetSystemMetrics(SM_CYMENUCHECK));
MessageBox(str);
禁用菜单项
移除和装载菜单
SetMenu(NULL);//禁用菜单项
CMenu menu;//装载菜单资源
menu.LoadMenu(IDR_MAINFRAME);
SetMenu(&menu);
MFC菜单命令更新机制
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
……
// TODO: Delete these three lines if you don't want the toolbar to
// be dockable
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
GetMenu()->GetSubMenu(0)->CheckMenuItem(0,MF_BYPOSITION|MF_CHECKED);
GetMenu()->GetSubMenu(0)->CheckMenuItem(ID_FILE_OPEN,MF_BYCOMMAND|MF_CHECKED);
GetMenu()->GetSubMenu(0)->SetDefaultItem(2,TRUE);//粗体显示默认菜单项
GetMenu()->GetSubMenu(0)->SetDefaultItem(ID_FILE_SAVE_AS,FALSE);//粗体显示默认菜单项
GetMenu()->GetSubMenu(0)->EnableMenuItem(6,MF_BYPOSITION|MF_DISABLED|MF_GRAYED);//禁用菜单项
// CString str;
// str.Format("x=%d,y=%d",GetSystemMetrics(SM_CXMENUCHECK),
// GetSystemMetrics(SM_CYMENUCHECK));
// MessageBox(str);
m_bitmap.LoadBitmap(IDB_BITMAP1);
GetMenu()->GetSubMenu(0)->SetMenuItemBitmaps(5,MF_BYPOSITION,&m_bitmap,&m_bitmap);
// SetMenu(NULL);//禁用菜单项
//
// CMenu menu;//装载菜单资源
// menu.LoadMenu(IDR_MAINFRAME);
// SetMenu(&menu);
// menu.Detach();//将菜单句柄和菜单对象分离,因为menu是个局部对象,程序不能自动析构它
return 0;
}
void CMainFrame::OnUpdateEditCut(CCmdUI* pCmdUI)
{
// TODO: Add your command update UI handler code here
if (ID_EDIT_CUT == pCmdUI->m_nID)//用标识符才能够保证菜单项和工具栏一致
{
pCmdUI->Enable(TRUE);
}
}
快捷菜单
void CMenuView::OnRButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CMenu menu;
VERIFY(menu.LoadMenu(IDR_MENU1));
CMenu* pPopup = menu.GetSubMenu(0);
ClientToScreen(&point);
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y,
this);
CView::OnRButtonDown(nFlags, point);
}
动态菜单操作
添加
插入
删除
举例:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
……
// TODO: Delete these three lines if you don't want the toolbar to
// be dockable
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
CMenu menu;
menu.CreateMenu();
GetMenu()->AppendMenu(MF_POPUP,(UINT)menu.m_hMenu,"Test");//添加菜单项目
GetMenu()->InsertMenu(1,MF_POPUP|MF_BYPOSITION,(UINT)menu.m_hMenu,"test1");//插入菜单项目
menu.AppendMenu(MF_STRING,IDM_HELLO,"Hello");//在刚插入的弹出式菜单下面添加菜单项111
menu.AppendMenu(MF_STRING,112,"ByeBye");//在刚插入的弹出式菜单下面添加菜单项112
menu.AppendMenu(MF_STRING,113,"MyTest");//在刚插入的弹出式菜单下面添加菜单项113
GetMenu()->GetSubMenu(0)->AppendMenu(MF_STRING,114,"Append");//在子菜单下面添加菜单项目114
GetMenu()->GetSubMenu(0)->InsertMenu(ID_FILE_OPEN,MF_BYCOMMAND|MF_STRING,115,"Insert");
//在文件子菜单下面添加菜单项目115
// GetMenu()->GetSubMenu(0)->DeleteMenu(115,MF_BYCOMMAND);//删除文件子菜单下面的115菜单项目
menu.Detach();//防止出现问题
return 0;
}
添加虚函数实现消息的截获,了解消息路由机制
BOOL CMainFrame::OnCommand(WPARAM wParam, LPARAM lParam)
{
// TODO: Add your specialized code here and/or call the base class
int MenuCmdID = LOWORD(wParam);//wParam的低两位字节是消息对象的ID号
CMenu4View* pView = (CMenu4View* )GetActiveView();//在框架类获得视图类的对象
if (MenuCmdID >= IDM_PHONE1 && MenuCmdID < IDM_PHONE1+pView->m_strArray.GetSize())
{
MessageBox("框架截获消息");//通过此消息可以知道消息的路由过程
CClientDC dc(pView);
dc.TextOut(0,0,pView->m_strArray.GetAt(MenuCmdID-IDM_PHONE1));
}
return CFrameWnd::OnCommand(wParam, lParam);
// return TRUE; 消息将不会传送给视图类
}
电话薄
void CMenu4View::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: Add your message handler code here and/or call default
CClientDC dc(this);
if (0x0d == nChar)
{
if (0 == ++m_nIndex)
{
m_Menu.CreatePopupMenu();
GetParent()->GetMenu()->AppendMenu(MF_POPUP,(UINT)m_Menu.m_hMenu,"PhoneBook");
GetParent()->DrawMenuBar();
}
m_Menu.AppendMenu(MF_STRING,IDM_PHONE1+m_nIndex,m_strLine.Left(m_strLine.Find(' ')));
m_strArray.Add(m_strLine);
m_strLine.Empty();
Invalidate(TRUE);
}
else
{
m_strLine += nChar;
dc.TextOut(0,0,m_strLine);
}
// Invalidate();
CView::OnChar(nChar, nRepCnt, nFlags);
}
void CMenu4View::OnPhone1()
{
// TODO: Add your command handler code here
CClientDC dc(this);
dc.TextOut(0,0,m_strArray.GetAt(0));
}
void CMenu4View::OnPhone2()
{
// TODO: Add your command handler code here
CClientDC dc(this);
dc.TextOut(0,0,m_strArray.GetAt(1));
}
void CMenu4View::OnPhone3()
{
// TODO: Add your command handler code here
CClientDC dc(this);
dc.TextOut(0,0,m_strArray.GetAt(2));
}
void CMenu4View::OnPhone4()
{
// TODO: Add your command handler code here
CClientDC dc(this);
dc.TextOut(0,0,m_strArray.GetAt(3));
}
错误解决
此类错误是头文件除了问题,导致某某类没有被定义就被调用了,只要在该文件之前加上调用相应头文件即可。
非模式对话框的创建
动态创建按钮
静态文本默认是不发送消息的
每一个控件都有指向其窗口的句柄和和hWnd
GetDlgItem(nID)->hWnd
m_Edit1.hWnd
访问控件的七种方法
对话空的伸缩与扩展功能
void CMyDlg::OnButton2()
{
CString str;
static CRect rectLarge;
static CRect rectSmall;
if(rectLarge.IsRectNull())
{
CRect rectSepertor;
GetWindowRect(&rectLarge);
GetDlgItem(IDC_SEPERATOR)->GetWindowRect(&rectSepertor);
rectSmall.left = rectLarge.left;
rectSmall.top = rectLarge.top;
rectSmall.right = rectLarge.right;
rectSmall.bottom = rectSepertor.bottom;
}
if (GetDlgItemText(IDC_BUTTON2,str),str == "收缩<<")
{
SetDlgItemText(IDC_BUTTON2,"扩展>>"); SetWindowPos(NULL,0,0,rectSmall.Width(),rectSmall.Height(),SWP_NOMOVE|SWP_NOZORDER);
}
else
{
SetDlgItemText(IDC_BUTTON2,"收缩<<");
SetWindowPos(NULL,0,0,rectLarge.Width(),rectLarge.Height(),SWP_NOMOVE|SWP_NOZORDER);
}
}
输入焦点的转换(按回车键实现在编辑框之间转换)
“逃跑”按钮的实现
创建属性页
一个属性表单有多个属性页组成
创建属性表
属性表不是派生于CDialog,它和对话框类相似,也可以用DOModal()来调用
向导的创建
修改应用程序外观
在程序创建之前修改:在CMainFrame的ProCreateWindow函数中添加代码
HWND CreateWindowEx(DWORD dwExStyle, LPCTSTR lpClassName, LPCTSTR lpWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam);
typedef struct tagCREATESTRUCT
{LPVOID lpCreateParams; HINSTANCE hInstance; HMENU hMenu; HWND hwndParent; int cy; int cx; int y; int x; LONG style; LPCTSTR lpszName;LPCTSTR lpszClass; DWORD dwExStyle; } CREATESTRUCT, *LPCREATESTRUCT;
lpCreateParams
Contains additional data which may be used to create the window. If the window is being created as a result of a call to the CreateWindow or CreateWindowEx function, this member contains the value of the lpParam parameter specified in the function call.
If the window being created is an MDI window, this member contains a pointer to an MDICREATESTRUCT structure.
Windows NT/2000/XP: If the window is being created from a dialog template, this member is the address of a SHORT value that specifies the size, in bytes, of the window creation data. The value is immediately followed by the creation data. For more information, see the following Remarks section.
hInstance
Handle to the module that owns the new window.
hMenu
Handle to the menu to be used by the new window.
hwndParent
Handle to the parent window, if the window is a child window. If the window is owned, this member identifies the owner window. If the window is not a child or owned window, this member is NULL.
cy
Specifies the height of the new window, in pixels.
cx
Specifies the width of the new window, in pixels.
y
Specifies the y-coordinate of the upper left corner of the new window. If the new window is a child window, coordinates are relative to the parent window. Otherwise, the coordinates are relative to the screen origin.
x
Specifies the x-coordinate of the upper left corner of the new window. If the new window is a child window, coordinates are relative to the parent window. Otherwise, the coordinates are relative to the screen origin.
style
Specifies the style for the new window.
WS_BORDER Creates a window that has a thin-line border.
WS_CAPTION Creates a window that has a title bar (includes the WS_BORDER style).
WS_CHILD Creates a child window. This style cannot be used with the WS_POPUP style.
WS_CHILDWINDOW Same as the WS_CHILD style.
WS_CLIPCHILDREN Excludes the area occupied by child windows when drawing occurs within the parent window. This style is used when creating the parent window.
WS_CLIPSIBLINGS Clips child windows relative to each other; that is, when a particular child window receives a WM_PAINT message, the WS_CLIPSIBLINGS style clips all other overlapping child windows out of the region of the child window to be updated. If WS_CLIPSIBLINGS is not specified and child windows overlap, it is possible, when drawing within the client area of a child window, to draw within the client area of a neighboring child window.
WS_DISABLED Creates a window that is initially disabled. A disabled window cannot receive input from the user.
WS_DLGFRAME Creates a window that has a border of a style typically used with dialog boxes. A window with this style cannot have a title bar.
WS_GROUP Specifies the first control of a group of controls. The group consists of this first control and all controls defined after it, up to the next control with the WS_GROUP style. The first control in each group usually has the WS_TABSTOP style so that the user can move from group to group. The user can subsequently change the keyboard focus from one control in the group to the next control in the group by using the direction keys.
WS_HSCROLL Creates a window that has a horizontal scroll bar.
WS_ICONIC Creates a window that is initially minimized. Same as the WS_MINIMIZE style.
WS_MAXIMIZE Creates a window that is initially maximized.
WS_MAXIMIZEBOX Creates a window that has a Maximize button. Cannot be combined with the WS_EX_CONTEXTHELP style.
WS_MINIMIZE Creates a window that is initially minimized. Same as the WS_ICONIC style.
WS_MINIMIZEBOX Creates a window that has a Minimize button. Cannot be combined with the WS_EX_CONTEXTHELP style.
WS_OVERLAPPED Creates an overlapped window. An overlapped window has a title bar and a border. Same as the WS_TILED style.
WS_OVERLAPPEDWINDOW Creates an overlapped window with the WS_OVERLAPPED, WS_CAPTION, WS_SYSMENU, WS_THICKFRAME, WS_MINIMIZEBOX, and WS_MAXIMIZEBOX styles. Same as the WS_TILEDWINDOW style.
WS_POPUP Creates a pop-up window. This style cannot be used with the WS_CHILD style.
WS_POPUPWINDOW Creates a pop-up window with WS_BORDER, WS_POPUP, and WS_SYSMENU styles. The WS_CAPTION and WS_POPUPWINDOW styles must be combined to make the window menu visible.
WS_SIZEBOX Creates a window that has a sizing border. Same as the WS_THICKFRAME style.
WS_SYSMENU Creates a window that has a Close (X) button in the non-client area.
WS_TABSTOP Specifies a control that can receive the keyboard focus when the user presses the TAB key. Pressing the TAB key changes the keyboard focus to the next control with the WS_TABSTOP style.
WS_THICKFRAME Creates a window that has a sizing border. Same as the WS_SIZEBOX style.
WS_TILED Creates an overlapped window. An overlapped window has a title bar and a border. Same as the WS_OVERLAPPED style.
WS_TILEDWINDOW Creates an overlapped window with the WS_OVERLAPPED, WS_CAPTION, WS_SYSMENU, WS_THICKFRAME, WS_MINIMIZEBOX, and WS_MAXIMIZEBOX styles. Same as the WS_OVERLAPPEDWINDOW style.
WS_VISIBLE Creates a window that is initially visible.
WS_VSCROLL Creates a window that has a vertical scroll bar.
lpszName
Pointer to a null-terminated string that specifies the name of the new window.
lpszClass
Pointer to a null-terminated string that specifies the class name of the new window.
dwExStyle
Specifies the extended window style for the new window.
WS_EX_ACCEPTFILES Specifies that a window created with this style accepts drag-drop files.
WS_EX_APPWINDOW Forces a top-level window onto the taskbar when the window is visible.
WS_EX_CLIENTEDGE Specifies that a window has a border with a sunken edge.
WS_EX_DLGMODALFRAME Creates a window that has a double border; the window can, optionally, be created with a title bar by specifying the WS_CAPTION style in the dwStyle parameter.
WS_EX_LEFT Creates a window that has generic “left-aligned” properties. This is the default.
WS_EX_LEFTSCROLLBAR If the shell language is Hebrew, Arabic, or another language that supports reading order alignment, the vertical scroll bar (if present) is to the left of the client area. For other languages, the style is ignored.
WS_EX_LTRREADING The window text is displayed using left-to-right reading-order properties. This is the default.
WS_EX_MDICHILD Creates an MDI child window.
WS_EX_NOACTIVATE A top-level window created with this style cannot be activated. If a child window has this style, tapping it does not cause its top-level parent to be activated. A window that has this style receives stylus events, but neither it nor its child windows can get the focus. Supported in Windows CE versions 2.0 and later.
WS_EX_NOANIMATION A window created with this style does not show animated exploding and imploding rectangles, and does not have a button on the taskbar. Supported in Windows CE versions 2.0 and later.
WS_EX_NOPARENTNOTIFY Specifies that a child window created with this style does not send the WM_PARENTNOTIFY message to its parent window when it is created or destroyed.
WS_EX_OVERLAPPEDWINDOW Combines the WS_EX_CLIENTEDGE and WS_EX_WINDOWEDGE styles.
WS_EX_PALETTEWINDOW Combines the WS_EX_WINDOWEDGE, WS_EX_TOOLWINDOW, and WS_EX_TOPMOST styles.
WS_EX_RIGHT The window has generic “right-aligned” properties. This depends on the window class. This style has an effect only if the shell language is Hebrew, Arabic, or another language that supports reading-order alignment; otherwise, the style is ignored.
WS_EX_RIGHTSCROLLBAR Vertical scroll bar (if present) is to the right of the client area. This is the default.
WS_EX_RTLREADING If the shell language is Hebrew, Arabic, or another language that supports reading-order alignment, the window text is displayed using right-to-left reading-order properties. For other languages, the style is ignored.
WS_EX_STATICEDGE Creates a window with a three-dimensional border style intended to be used for items that do not accept user input.
WS_EX_TOOLWINDOW Creates a tool window; that is, a window intended to be used as a floating toolbar. A tool window has a title bar that is shorter than a normal title bar, and the window title is drawn using a smaller font. A tool window does not appear in the taskbar or in the dialog that appears when the user presses ALT+TAB. If a tool window has a system menu, its icon is not displayed on the title bar. However, you can display the system menu by right-clicking or by typing ALT+SPACE.
WS_EX_TOPMOST Specifies that a window created with this style should be placed above all non-topmost windows and should stay above them, even when the window is deactivated. To add or remove this style, use the SetWindowPos function.
WS_EX_TRANSPARENT Specifies that a window created with this style should not be painted until siblings beneath the window (that were created by the same thread) have been painted. The window appears transparent because the bits of underlying sibling windows have already been painted.
To achieve transparency without these restrictions, use the SetWindowRgn function.
WS_EX_WINDOWEDGE Specifies that a window has a border with a raised edge.
窗口创建之后修改:在OnCreate()函数当中添加SetWindowLong()代码
GetWindowLong(HWND hWnd,int nIndex)可以获得当前窗口的风格
修改窗口光标,图标,背景
通过SetClassLong() 重置窗口所属窗口类的WNDCLASSEX(WNDCLASS结构的扩展),改变光标和背景的代码放在视图类的OnCreate函数中,改变图标则放在框架类的OnCreate中
SetClassLong(m_hWnd,GCL_HBRBACKGROUND,(LONG)GetStockObject(BLACK_BRUSH));
SetClassLong(m_hWnd,GCL_HCURSOR,(LONG)LoadCursor(NULL,IDC_CROSS));
注册窗口类两种方法:
一:
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
cs.cx = 300;//应用程序宽度
cs.cy = 300;//应用程序长度
cs.style &= ~FWS_ADDTOTITLE;//修改应用程序标题必须去掉此风格
cs.lpszName = "Chen Sifan";
WNDCLASS wndcls;
wndcls.cbClsExtra = 0;
wndcls.cbWndExtra = 0;
wndcls.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wndcls.hCursor = LoadCursor(NULL,IDC_HELP);
wndcls.hIcon = LoadIcon(NULL,IDI_ERROR);
wndcls.hInstance = AfxGetInstanceHandle();
wndcls.lpfnWndProc = ::DefWindowProc;
wndcls.lpszClassName = "sifan.org";
wndcls.lpszMenuName = NULL;
wndcls.style = CS_HREDRAW|CS_VREDRAW;
RegisterClass(&wndcls);
cs.lpszClass = "sifan.org";//只是改变图标
return TRUE;
}
BOOL CStyleView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
cs.lpszClass = "sifan.org";//主要是改变光标和背景
return CView::PreCreateWindow(cs);
}
二:
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
cs.lpszClass = AfxRegisterWndClass(CS_VREDRAW|CS_HREDRAW,0,0,LoadIcon(NULL,IDI_WARNING));
return TRUE;
}
BOOL CStyleView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW,LoadCursor(NULL,IDC_CROSS)
,(HBRUSH)GetStockObject(BLACK_BRUSH),0);
return CView::PreCreateWindow(cs);
}
动态改变应用程序图标
extern CStyleApp theApp;
//LoadIcon的第一个参数要是一个应用程序句柄,第二个是把一个图标ID转换成一个字符串资源
m_hIcon[0] =LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDI_ICON1));
m_hIcon[1] =LoadIcon(theApp.m_hInstance,MAKEINTRESOURCE(IDI_ICON2));//全局变量的应用必须先声明
m_hIcon[2] =LoadIcon(AfxGetApp()->m_hInstance,MAKEINTRESOURCE(IDI_ICON3));//全局函数
SetTimer(1,1000,NULL);
void CMainFrame::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
static int nIndex = 0;
SetClassLong(m_hWnd,GCL_HICON,(LONG)m_hIcon[nIndex]);
nIndex = ++nIndex%3; //很巧
CFrameWnd::OnTimer(nIDEvent);
}
工具栏
第二个是框架类的EnableDocking,是为了让主框架窗口可以被停靠;
代码如下:
void CMainFrame::OnViewNewToolbar()
{
// TODO: Add your command handler code here
// if (m_newToolBar.IsWindowVisible())
// {
// m_newToolBar.ShowWindow(SW_HIDE);
// }
// else
// {
// m_newToolBar.ShowWindow(SW_SHOW);
// }
// RecalcLayout(TRUE);//重新调整控制条的位置,默认是真
// DockControlBar(&m_newToolBar);//重新让工具条停靠在框架窗口的边缘
//用一个函数可以替换以上全部代码,还可以让工具栏在消失的位置显示出来
ShowControlBar(&m_newToolBar,!m_newToolBar.IsVisible(),FALSE);
}
为菜单栏添加复选标记
pCmdUI->SetCheck(m_newToolBar.IsWindowVisible());
时间
状态栏编程
进度栏编程
void CMainFrame::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
CRect rect;
m_wndStatusBar.GetItemRect(2,&rect);
if (!m_progress.m_hWnd)
{
m_progress.Create(WS_CHILD|WS_VISIBLE|PBS_SMOOTH,rect,&m_wndStatusBar,1111);
}
else
{
m_progress.MoveWindow(rect);
}
m_progress.SetPos(50);
// Do not call CFrameWnd::OnPaint() for painting messages
}
四种方法在状态栏第一个窗口显示鼠标的当前位置
首先确定是为视图类添加WM_MOUSEMOVE消息
其次捕获鼠标的坐标并且格式化
第三获取父窗口即框架类窗口的句柄,GetParent()获取的是CWnd指针,故要将其强制转换为CMainFrame
void CStyleView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CString strMouse;
strMouse.Format("X=%d,Y=%d",point.x,point.y);
//调用CStatusBar的成员函数将文本放在第一个窗口
((CMainFrame*)GetParent())->m_wndStatusBar.SetWindowText(strMouse);
//调用CFrameWnd的成员函数将文本放在第一个窗口
((CMainFrame*)GetParent())->SetMessageText(strMouse);
//通过CMainFrame ::GetMessageBar来获取状态栏的指针来调用SetWindowText将文本放在第一个窗口
((CMainFrame*)GetParent())->GetMessageBar()->SetWindowText(strMouse);
//通过CWnd::GetDescendantWindow来获取状态栏的指针来调用SetWindowText将文本放在第一个窗口
GetParent()->GetDescendantWindow(AFX_IDW_STATUS_BAR)->SetWindowText(strMouse);
CView::OnMouseMove(nFlags, point);
}
为应用程序添加启动画面
设置颜色对话框默认颜色
常见错误2
设置字体
常见错误3
示例区域
void CSetting::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
CPen pen(m_nLineWidth,m_nLineStyle,m_clr);
dc.SelectObject(&pen);
CRect rect;
GetDlgItem(IDC_SAMPLE)->GetWindowRect(&rect);//IDC_SAMPLE为组框的ID,通过她来获得示例区域
ScreenToClient(&rect);
dc.MoveTo(rect.left+20,rect.top+rect.Height()/2);
dc.LineTo(rect.right-20,rect.top+rect.Height()/2);
UpdateData();
// Do not call CDialog::OnPaint() for painting messages
}
改变对话框控件的背景及字体颜色
HBRUSH CSetting::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
return m_brush;// m_brush.CreateSolidBrush(RGB(0,255,0));
}
仅仅改变个别控件和字体颜色
HBRUSH CSetting::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
// TODO: Change any attributes of the DC here
if (pWnd->GetDlgCtrlID() == IDC_LINE_STYLE)
{
pDC->SetTextColor(RGB(0,0,255));
pDC->SetBkMode(TRANSPARENT);
//控件上面有字,字体有阴影,此句就是将字体背景设置为透明,这样就可以看见控件颜色了
return m_brush;
}
if (pWnd->GetDlgCtrlID() == IDC_LINE_WIDTH_EDIT)
{
pDC->SetTextColor(RGB(0,0,255));
pDC->SetBkMode(TRANSPARENT);
pDC->SetBkColor(RGB(0,0,255));
return m_brush;
}
return hbr;
// TODO: Return a different brush if the default is not desired
}
改变控件上面的字体
if (pWnd->GetDlgCtrlID() == IDC_TEXT)
{
pDC->SelectObject(&m_font);
pDC->SetTextColor(RGB(0,0,255));
}
改变按钮控件的背景和文本颜色
位图的显示
窗口的绘制过程:清除背景BOOL CGraphicView::OnEraseBkgnd(CDC* pDC),重绘制窗口(也会调用OnDraw函数,因此也可以将代码放到OnDraw函数中去);
只是在OnDraw当中编写的话,每当窗口尺寸变化的时候,就会先清除窗口,因此此种方法的效果是闪烁性比较明显。
BOOL CGraphicView::OnEraseBkgnd(CDC* pDC)
{
// TODO: Add your message handler code here and/or call default
CBitmap bitMap;
bitMap.LoadBitmap(IDB_BITMAP1);
BITMAP bmp;
bitMap.GetBitmap(&bmp);
CDC pCompatiableDC;
pCompatiableDC.CreateCompatibleDC(pDC);//兼容DC
pCompatiableDC.SelectObject(&bitMap);
CRect rect;
GetClientRect(&rect);
// pDC->BitBlt(0,0,rect.Width(),rect.Height(),&pCompatiableDC,0,0,SRCCOPY);//1:1复制
pDC->StretchBlt(0,0,rect.Width(),rect.Height(),&pCompatiableDC,0,0
,bmp.bmWidth,bmp.bmHeight,SRCCOPY);//压缩源图片显示
return TRUE;//为TRUE表示不再清楚窗口背景
}
一、图形的保存和重绘(huì)
1,为视图类新建一个私有的CPtrArray数据类型,用来保存绘图的三要素:起点,终点,类型
2,重绘窗口的时候会调用OnDraw函数
void CGraphicView::OnDraw(CDC* pDC)
{
CGraphicDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
CBrush* pBrush = CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
pDC->SelectObject(&pBrush);
for (int i=0;i<m_ptrArray.GetSize();i++)
{
switch(((CGraph*)m_ptrArray.GetAt(i))->m_nDrawType)
{
case 1:
pDC->SetPixel(((CGraph*)m_ptrArray.GetAt(i))->m_nEndPoint,RGB(0,0,0));
break;
case 2:
pDC->MoveTo(((CGraph*)m_ptrArray.GetAt(i))->m_nOriginPoint);
pDC->LineTo(((CGraph*)m_ptrArray.GetAt(i))->m_nEndPoint);
break;
case 3:
pDC->Rectangle(CRect(
((CGraph*)m_ptrArray.GetAt(i))->m_nOriginPoint,
((CGraph*)m_ptrArray.GetAt(i))->m_nEndPoint));
break;
case 4:
pDC->Ellipse(CRect(
((CGraph*)m_ptrArray.GetAt(i))->m_nOriginPoint,
((CGraph*)m_ptrArray.GetAt(i))->m_nEndPoint)
);
break;
}
}
}
3,在OnButtonUp函数里面加入以下代码,将每一个图形添加到CPtrArray当中去
CGraph* pGraph =new CGraph(m_nDrawType,m_nOriginPoint,point);//new均是在堆中定义的
m_ptrArray.Add(pGraph);
OnDraw和OnPaint函数
窗口滚动功能的实现
让视图基类为CScrollView,两种方式:1,在应用程序创建的第六步修改基类
2,若程序已经创建了,那么只需要将应用程序视图类的头文件和源文件中的
CView改成CScrollView类
错误4
图形错位现象
在OnDraw函数中添加一下代码:
OnPrepareDC(&dc);
dc.DPtoLP(&m_nOriginPoint);
dc.DPtoLP(&point);
二、用元文件保存图形
元文件用来保存图形,代码如下:
void CGraphicView::OnDraw(CDC* pDC)
{
CGraphicDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
HMETAFILE hMetaFile;
hMetaFile = m_dcMetaFile.Close();//没想到close()函数也能够用来获取句柄
pDC->PlayMetaFile(hMetaFile);
m_dcMetaFile.Create();//在内存中创建,用来播放之前绘制的图像
m_dcMetaFile.PlayMetaFile(hMetaFile);//显示前面绘制的图像
DeleteMetaFile(hMetaFile);
}
void CGraphicView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CClientDC dc(this);
CPen pen(m_nLineStyle,m_nLineWidth,m_clr);
// dc.SelectObject(&pen);
m_dcMetaFile.SelectObject(&pen);
CBrush* pBrush = CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
// dc.SelectObject(&pBrush);
m_dcMetaFile.SelectObject(&pen);
switch (m_nDrawType)
{
case 1:
// dc.SetPixel(point,m_clr);
m_dcMetaFile.SetPixel(point,m_clr);
break;
case 2:
// dc.MoveTo(m_nOriginPoint);
m_dcMetaFile.MoveTo(m_nOriginPoint);
// dc.LineTo(point);
m_dcMetaFile.LineTo(point);
break;
case 3:
// dc.Rectangle(CRect(m_nOriginPoint,point));
m_dcMetaFile.Rectangle(CRect(m_nOriginPoint,point));
break;
case 4:
// dc.Ellipse(CRect(m_nOriginPoint,point));
m_dcMetaFile.Ellipse(CRect(m_nOriginPoint,point));
break;
}
// OnPrepareDC(&dc);
// dc.DPtoLP(&m_nOriginPoint);
// dc.DPtoLP(&point);
// CGraph* pGraph =new CGraph(m_nDrawType,m_nOriginPoint,point);//new均是在堆中定义的
// m_ptrArray.Add(pGraph);
CScrollView::OnLButtonUp(nFlags, point);
}
将元文件保存到磁盘,用[文件]子菜单下的[打开]打开它,用[保存]保存它
保存
void CGraphicView::OnFileSave()
{
// TODO: Add your command handler code here
HMETAFILE hMetaFile;//定义一个句柄变量
hMetaFile = m_dcMetaFile.Close();//获取句柄
CopyMetaFile(hMetaFile,"meta.wmf");//对元文件来说,通常用wmf格式保存它到磁盘文件WindowsMetaFile
m_dcMetaFile.Create();//创建一个元文件,以供下一次绘图使用
DeleteMetaFile(hMetaFile);//释放句柄
}
打开
void CGraphicView::OnFileOpen()
{
// TODO: Add your command handler code here
HMETAFILE hMetaFile;//定义一个句柄变量
hMetaFile = GetMetaFile("meta.wmf");//获取句柄
m_dcMetaFile.PlayMetaFile(hMetaFile);
DeleteMetaFile(hMetaFile);//释放句柄
Invalidate();//窗口重绘,调用OnDraw函数
}
三、兼容DC(设备描述表)保存图形和重绘
void CGraphicView::OnDraw(CDC* pDC)
{
CGraphicDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
//用兼容DC保存图像
CRect rect;
GetClientRect(&rect);
pDC->BitBlt(0,0,rect.Width(),rect.Height(),&m_dcCompatibale,0,0,SRCCOPY);
}
void CGraphicView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CClientDC dc(this);
CBrush* pBrush = CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
if (!m_dcCompatibale.m_hDC)
{
m_dcCompatibale.CreateCompatibleDC(&dc);
CRect rect;
GetClientRect(rect);
CBitmap bitmap;
bitmap.CreateCompatibleBitmap(&dc,rect.Width(),rect.Height());
m_dcCompatibale.SelectObject(&bitmap);
m_dcCompatibale.BitBlt(0,0,rect.Width(),rect.Height(),&dc,0,0,SRCCOPY);
m_dcCompatibale.SelectObject(pBrush);
}
switch (m_nDrawType)
{
case 1:
m_dcCompatibale.SetPixel(point,m_clr);
break;
case 2:
m_dcCompatibale.MoveTo(m_nOriginPoint);
m_dcCompatibale.LineTo(point);
break;
case 3:
m_dcCompatibale.Rectangle(CRect(m_nOriginPoint,point));
break;
case 4:
m_dcCompatibale.Ellipse(CRect(m_nOriginPoint,point));
break;
}
CScrollView::OnLButtonUp(nFlags, point);
}
文件操作
写入
void CFileView::OnFileWrite()
{
// TODO: Add your command handler code here
FILE* pFile = fopen("1.txt","w");
CString str = "http:\\\\www.sunxin.org";
// CString str1 = "weclome";
fwrite(str,1,strlen(str),pFile);//将字符串写入文件缓冲区
fseek(pFile,0,SEEK_SET);//在文件开始出插入,替换Http
fwrite(" ftp",1,strlen(" ftp"),pFile);
// fwrite(str1,1,strlen(str1),pFile);//将字符串写入文件缓冲区
// fclose(pFile);//关闭文件,将缓冲区的内容写到文件当中
//如果没有这句话,将会导致内容不能立即写入文件中
fflush(pFile);//实现在不关闭文件的情况下将缓冲区的内容写如文件,提高效率(刷新缓冲区内容哦个)
}
读取
void CFileView::OnFileRead()
{
// TODO: Add your command handler code here
FILE *pFile = fopen("1.txt","r");
char ch[100];
fread(ch,1,100,pFile);
fclose(pFile);
MessageBox(ch);
}
错误5
向字符串末尾添加“\0”
1 利用数组给最后一个元素赋值为‘\0’
void CFileView::OnFileWrite()
{
FILE* pFile = fopen("1.txt","w");
char buf[22] = "http:\\\\www.sunxin.org";
buf[21] = '\0';
fwrite(buf,1,22,pFile);
fclose(pFile);
}
2 读的时候用memset函数先将数组初始化为全0
void CFileView::OnFileRead()
{
// TODO: Add your command handler code here
FILE *pFile = fopen("1.txt","r");
char ch[100];
memset(ch,0,100);
fread(ch,1,100,pFile);
fclose(pFile);
MessageBox(ch);
}
3 用ftell来获取文件长度,获取之后用rewind来将指针移动到文件开头
void CFileView::OnFileRead()
{
// TODO: Add your command handler code here
FILE *pFile = fopen("1.txt","r");
char* pBuf;
fseek(pFile,0,SEEK_END);
int len = ftell(pFile);//获得长度
pBuf = new char[len+1];
rewind(pFile);//将文件指针移动到文件开头
fread(pBuf,1,len,pFile);
pBuf[len] = 0;
fclose(pFile);
MessageBox(pBuf);
}
文本文件和二进制文件差异
itoa函数:把一个整型数据转换成字符形式
Win32 文件操作
void CFileView::OnFileWrite()
{
//win32 文件操作
//定义一个句柄变量
HANDLE hFile;
hFile = CreateFile("2.txt",GENERIC_WRITE,0,NULL,CREATE_NEW,
FILE_ATTRIBUTE_NORMAL,NULL);//创建文件
DWORD dwWrites;//接收实际接受的字节数
WriteFile(hFile,"win32 file operator",strlen("win32 file operator"),
&dwWrites,NULL);//写入数据
CloseHandle(hFile);//关闭句柄
}
void CFileView::OnFileRead()
{
//win32文件操作
HANDLE hFile;//创建句柄对象
hFile = CreateFile("2.txt",GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
char ch[100];
DWORD dwReads;//接受读取的字节数
ReadFile(hFile,ch,100,&dwReads,NULL);//读取文件
ch[dwReads] = 0;//设置结束标志
CloseHandle(hFile);//关闭句柄
MessageBox(ch);
}
往注册表中写入东西(win32 API函数和CWinApp函数WriteProfileString区别)
// ::WriteProfileString("http:\\\\www.sunxin.org","admin","zhangshan");Win32 函数 写到win.ini当中去
WriteProfileString("http:www.sunxin.org","admin","zhangshan");//CWinApp函数写到注册表
CString str;
// ::GetProfileString("http:\\\\www.sunxin.org","admin","lisi",str.GetBuffer(100),100);
str = GetProfileString("http:\\\\www.sunxin.org","admin");//获取注册表中的信息
AfxMessageBox(str);
注册表API操作
创建键
打开键
写入注册表
读取注册表
注册表示例:
void CFileView::OnRegWrite()
{
// TODO: Add your command handler code here
HKEY hKey;
RegCreateKey(HKEY_LOCAL_MACHINE,"Software\\http://www.sunxin.org\\admin",&hKey);
RegSetValue(hKey,NULL,REG_SZ,"zhangshan",strlen("zhangshan"));
DWORD dwage = 30;
//写入一个非REG_SZ类型的数据,需要调用以下函数,第五个参数是数据的值,需要强制转换
RegSetValueEx(hKey,"Age",0,REG_DWORD,(const byte*)&dwage,4);
RegCloseKey(hKey);
}
void CFileView::OnRegRead()
{
// // TODO: Add your command handler code here
// LONG lValue;
// //第一次调用得到要读取的字符串的长度
// RegQueryValue(HKEY_LOCAL_MACHINE,"Software\\http://www.sunxin.org\\admin",NULL,&lValue);
// char* pBuf = new char[lValue];
// //第二次调用根据长度获取数据
// RegQueryValue(HKEY_LOCAL_MACHINE,"Software\\http://www.sunxin.org\\admin",pBuf,&lValue);
// MessageBox(pBuf);
HKEY hKey;
//打开指定的注册表项
RegOpenKey(HKEY_LOCAL_MACHINE,"Software\\http://www.sunxin.org\\admin",&hKey);
DWORD dwType;
DWORD dwValue;
DWORD dwAge;
//读取其它类型的数据
RegQueryValueEx(hKey,"Age",0,&dwType,(LPBYTE)&dwAge,&dwValue);
CString str;
str.Format("Age = %d",dwValue);
MessageBox(str);
}
文档与串行化
代码:
void CGraphicView::OnFileRead()//对象的读取顺序和写入顺序必须一致
{
// TODO: Add your command handler code here
// 构造CFile对象
CFile file("ar.txt",CFile::modeRead);
//构造存档对象
CArchive ar(&file,CArchive::load);//打开操作
int i;
char ch;
float f;
CString str;
CString strResult;
ar>>i>>ch>>f>>str;//读取数据
strResult.Format("%d,%c,%f,%s",i,ch,f,str);//数据格式化
MessageBox(strResult);
}
void CGraphicView::OnFileWrite()
{
// TODO: Add your command handler code here
// 构造CFile对象
CFile file("ar.txt",CFile::modeCreate|CFile::modeWrite);
//构造CArchive存档对象
CArchive ar(&file,CArchive::store);//保存操作
int i = 4;
char ch = 'a';
float f =1.3f;
CString str("www.sunxin.org");
//保存数据
ar<<i<<ch<<f<<str;
}
查看文档模版的字符串:
文档
实现类对串行化的支持
void CGraph::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
ar<<m_nDrawType<<m_nOriginPoint<<m_nEndPoint;
}
else
{
ar>>m_nDrawType>>m_nOriginPoint>>m_nEndPoint;
}
}
void CGraph::Draw(CDC *pDC)
{
CBrush* pBrush = CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));//穿件透明画刷
CBrush* pOldbrush = pDC->SelectObject(pBrush);
switch(m_nDrawType)
{
case 1:
pDC->SetPixel(m_nEndPoint,RGB(0,0,0));
break;
case 2:
pDC->MoveTo(m_nOriginPoint);
pDC->LineTo(m_nEndPoint);
break;
case 3:
pDC->Rectangle(CRect(m_nOriginPoint,m_nEndPoint));
break;
case 4:
pDC->Ellipse(CRect(m_nOriginPoint,m_nEndPoint));
break;
}
pDC->SelectObject(pOldbrush);
}
错误6
要求在设计可串行化的类时,在其内部确定需要串行化的数据。
CObject本书就是串行化类,因此可以直接用CObject类来实现数据的设计和显示
1、在void CGraphicDoc::Serialize(CArchive& ar)当中添加一下代码
pView->m_obArray.Serialize(ar);//直接利用CObject类本身就是可串行化类的特点,直接用一句话实现串行化数据
2、在void CGraphicView::OnDraw(CDC* pDC)中添加一下代码
int nCount = m_obArray.GetSize();
for (int i=0;i<nCount;i++)
{
((CGraph*)m_obArray.GetAt(i))->Draw(pDC);
}
知识点
文档的销毁
*******RemoveAt错误7
void CGraphicDoc::DeleteContents()
{
// TODO: Add your specialized code here and/or call the base class
POSITION pos = GetFirstViewPosition();
CGraphicView* pView = (CGraphicView*)GetNextView(pos);
int nCount = pView->m_obArray.GetSize();
for (int i=0;i<nCount;i++)//注意不要用GetSize函数作为条件,因为删除指针数据时的内存大小时刻在变
{
delete pView->m_obArray.GetAt(i);//delete释放指针指向的堆内存,而CObArray中保存的是指针
// pView->m_obArray.RemoveAt(i);//删除m_obArray当中保存的指针数据//出现内存泄露
}
pView->m_obArray.RemoveAll();//等指针指向的堆内存全部删除之后再删除全部的指针数据
CDocument::DeleteContents();
}
网络编程
计算机通信
条件:对方IP,通信协议,端口号;
一台电脑会有很多个网络程序在运行,要实现与其中一个应用程序通信必须指定该网络应用程序的地址;那么IP相当于总机地址,端口号相当于分机地址;
Windows socket是网络编程的一种简单的方法
它是应用程序和网络驱动程序之间的桥梁;
应用程序把数据传给Socket,Socket再把数据交给驱动程序,驱动程序再把数据发送出去;
计算机从网络上收到与该Socket绑定的IP地址和端口号相关的数据后,由驱动程序交给Socket,应用程序便可从Scoket提取接收到的数据了;
ISO/OSI七层参考模型
(Open System Interconnection)
TCP/IP模型
协议端口(Protocol port)
端口用一个整数型标识符来表示,即端口号;
端口号与协议相关;
端口号使用一个16位的数字来表示,范围是0~65535;
1024以下的端口号留给预定义服务,我们编写网络应用程序的时候,为程序指定1024以上的端口号;
套接字(Socket)
套接字类型
网络字节顺序
客户机/主机服务模式
基于TCp(面向连接)的Socket编程
基于UDP(面向无连接)的Socket编程
套接字编程需要额一些函数
WSAStart 函数 :加载套接字库和确定Socket版本
Socket函数
Bind函数
Liten函数
Accept函数
Send函数
Recv函数
Connect函数
Rectfrom函数
Sendto函数
Htons和htonl函数
TCP建立工程方法
服务器程序
#include <Winsock2.h>
#include <Stdio.h>
void main()
{
//加载套接字库
WORD wVisionRequested;//保存WinSock库的版本
WSADATA wsaData;
int err;
wVisionRequested = MAKEWORD(1,1);//请求版本号的WORD值
err = WSAStartup(wVisionRequested,&wsaData);//加载套接字库
if (err != 0)//如果返回值不为0 ,则直接退出
{
return;
}
if (LOBYTE(wsaData.wVersion) != 1||HIBYTE(wsaData.wVersion != 1))//验证版本号
{
WSACleanup();
return;
}
//创建套接字
SOCKET sockSrv = socket(AF_INET,SOCK_STREAM,0);//创建的是流式套接字,自动选择协议
//将套接字绑定到本机地址和端口上
SOCKADDR_IN addrSrv;//定义一个SOCKADDR_IN变量,作为套接字的本地地址信息
//完成对SOCKADDR_IN的赋值
addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//将主机地址信息32位u_Long转换为网络地址信息
addrSrv.sin_family = AF_INET;//地址家族
addrSrv.sin_port = htons(6000);//端口号为6000,并将两个字节16位的信息u_short转换成网络地址信息
bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
//将套接字设置为监听模式,准备接收用户请求
listen(sockSrv,5);//第一个是套接字,第二个是等待连接队列的最大长度
SOCKADDR_IN add_Client;//定义一个地址及诶够提,用来接收用户地址信息
int len = sizeof(SOCKADDR);
while (1)
{
// 等待用户请求到来,当请求到来后,接收连接请求,返回一个新的对应于此次连接的套接字
SOCKET sockConn = accept(sockSrv,(SOCKADDR*)&add_Client,&len);//sockConn用来保存新的套接字,而先前的套接字任继续监听连接请求
char sendBuf[100];//定义一个数组,用于保存要发送的数据
//ntol函数将一个in_addr的结构类型转换为点分十进制格式的IP地址字符串
sprintf(sendBuf,"Welcome %s to http://www.sunxin.org",inet_ntoa(add_Client.sin_addr));
//发送数据
send(sockConn,sendBuf,100,0);
char recvBuf[100];
//接收数据
recv(sockConn,recvBuf,100,0);
// 打印数据
printf("%s\n",recvBuf);
//关闭套接字
closesocket(sockConn);
}
}
客户端程序
#include <Winsock2.h>
#include <Stdio.h>
void main()
{
//加载套接字库
WORD wVisionRequested;//保存WinSock库的版本
WSADATA wsaData;
int err;
wVisionRequested = MAKEWORD(1,1);//请求版本号的WORD值
err = WSAStartup(wVisionRequested,&wsaData);//加载套接字库
wVisionRequested = MAKEWORD(1,1);//请求版本号的WORD值
err = WSAStartup(wVisionRequested,&wsaData);//加载套接字库
if (err != 0)//如果返回值不为0 ,则直接退出
{
return;
}
if (LOBYTE(wsaData.wVersion) != 1||HIBYTE(wsaData.wVersion != 1))//验证版本号
{
WSACleanup();
return;
}
//创建套接字
SOCKET sockClient = socket(AF_INET,SOCK_STREAM,0);//创建的是流式套接字,自动选择协议
SOCKADDR_IN addrSrv;//定义一个SOCKADDR_IN变量,作为套接字的本地地址信息
//完成对SOCKADDR_IN的赋值
//设定服务器端的地址,127.0.0.1是本地回路地址,不管机器有无网卡都可以使用这个IP地址
//往往用这个IP地址在本地机器上面测试
addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//将其转换为u_Long类型
addrSrv.sin_family = AF_INET;//地址家族
addrSrv.sin_port = htons(6000);//端口号为服务器等待请求信号的那个端口
//向服务器发出请求,第二个是设定连接服务器的地址信息,第三个是指定服务器端地址长度
//对于客户端来说,它不需要绑定,可以直接连接服务器
connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
//接收数据
char recvBuf[100];
recv(sockClient,recvBuf,100,0);
printf("%s\n",recvBuf);
//发送数据
//+1是为了在最后加上一个‘\0’,表示字符串结束
send(sockClient,"This is Client message.",strlen("This is Client message.")+1,0);
//关闭套接字
closesocket(sockClient);
WSACleanup();
}
运行结果如下:
UDP建立工程
//UdpSrc.cpp
#include <Winsock2.h>
#include <Stdio.h>
void main()
{
//加载套接字库
WORD wVisionRequested;//保存WinSock库的版本
WSADATA wsaData;
int err;
wVisionRequested = MAKEWORD(1,1);//请求版本号的WORD值
err = WSAStartup(wVisionRequested,&wsaData);//加载套接字库
if (err != 0)//如果返回值不为0 ,则直接退出
{
return;
}
if (LOBYTE(wsaData.wVersion) != 1||HIBYTE(wsaData.wVersion != 1))//验证版本号
{
WSACleanup();
return;
}
//创建套接字
SOCKET sockSrv = socket(AF_INET,SOCK_DGRAM,0);//创建的是数据报式套接字,自动选择协议
//将套接字绑定到本机地址和端口上
SOCKADDR_IN addrSrv;//定义一个SOCKADDR_IN变量,作为套接字的本地地址信息
//完成对SOCKADDR_IN的赋值
addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//将主机地址信息32位u_Long转换为网络地址信息
addrSrv.sin_family = AF_INET;//地址家族
addrSrv.sin_port = htons(6000);//端口号为6000,并将两个字节16位的信息u_short转换成网络地址信息
// 绑定套接字
bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
//等待并接收数据
SOCKADDR_IN add_Client;//定义一个地址,用来接收用户地址信息
int len = sizeof(SOCKADDR);
char recvBuf[100];//定义一个数组,用于保存要接收的数据
recvfrom(sockSrv,recvBuf,100,0,(SOCKADDR*)&add_Client,&len);
printf("%s\n",recvBuf);
//关闭套接字
closesocket(sockSrv);
WSACleanup();
}
//UdpClient.cpp
#include <Winsock2.h>
#include <Stdio.h>
void main()
{
//加载套接字库
WORD wVisionRequested;//保存WinSock库的版本
WSADATA wsaData;
int err;
wVisionRequested = MAKEWORD(1,1);//请求版本号的WORD值
err = WSAStartup(wVisionRequested,&wsaData);//加载套接字库
if (err != 0)//如果返回值不为0 ,则直接退出
{
return;
}
if (LOBYTE(wsaData.wVersion) != 1||HIBYTE(wsaData.wVersion != 1))//验证版本号
{
WSACleanup();
return;
}
//创建套接字
SOCKET sockSrv = socket(AF_INET,SOCK_DGRAM,0);//创建的是流式套接字,自动选择协议
SOCKADDR_IN addrSrv;//定义一个SOCKADDR_IN变量,作为套接字的本地地址信息
addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
addrSrv.sin_family = AF_INET;//地址家族
addrSrv.sin_port = htons(6000);//端口号为6000,并将两个字节16位的信息u_short转换成网络地址信息
//发送数据
sendto(sockSrv,"This is a client message.",strlen("This is a client message.")+1
,0,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));//addrSrv为目标套接字地址
//关闭套接字
closesocket(sockSrv);
WSACleanup();
}
基于UDP的简单聊天程序
//NetSrv.cpp
#include <Winsock2.h>
#include <Stdio.h>
void main()
{
//加载套接字库
WORD wVisionRequested;//保存WinSock库的版本
WSADATA wsaData;
int err;
wVisionRequested = MAKEWORD(1,1);//请求版本号的WORD值
err = WSAStartup(wVisionRequested,&wsaData);//加载套接字库
if (err != 0)//如果返回值不为0 ,则直接退出
{
return;
}
if (LOBYTE(wsaData.wVersion) != 1||HIBYTE(wsaData.wVersion != 1))//验证版本号
{
WSACleanup();
return;
}
//创建套接字,并且将套接字绑定到本机地址和端口上
SOCKET sockSrv = socket(AF_INET,SOCK_DGRAM,0);
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(6000);
// 绑定套接字
bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
char recvBuf[100];
char sendBuf[100];
char tempBuf[200];
SOCKADDR_IN addrClient;
int len = sizeof(SOCKADDR);
while (1)
{
//等待并且接收数据
recvfrom(sockSrv,recvBuf,100,0,(SOCKADDR*)&addrClient,&len);
if ('q' == recvBuf[0])
{
sendto(sockSrv,"q",strlen("q")+1,0,(SOCKADDR*)&addrClient,len);
printf("Chat end!\n");
break;
}
sprintf(tempBuf,"%s say : %s",inet_ntoa(addrClient.sin_addr),recvBuf);
printf("%s\n",tempBuf);
//发送数据
printf("Please input data : \n");
gets(sendBuf);
sendto(sockSrv,sendBuf,strlen(sendBuf)+1,0,(SOCKADDR*)&addrClient,len);
}
closesocket(sockSrv);
WSACleanup();
}
//NetClient.cpp
#include <Winsock2.h>
#include <Stdio.h>
void main()
{
//加载套接字库
WORD wVisionRequested;//保存WinSock库的版本
WSADATA wsaData;
int err;
wVisionRequested = MAKEWORD(1,1);//请求版本号的WORD值
err = WSAStartup(wVisionRequested,&wsaData);//加载套接字库
if (err != 0)//如果返回值不为0 ,则直接退出
{
return;
}
if (LOBYTE(wsaData.wVersion) != 1||HIBYTE(wsaData.wVersion != 1))//验证版本号
{
WSACleanup();
return;
}
//创建套接字,并且将套接字绑定到本机地址和端口上
SOCKET sockSrv = socket(AF_INET,SOCK_DGRAM,0);
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(6000);
// 绑定套接字
bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
char recvBuf[100];
char sendBuf[100];
char tempBuf[200];
int len = sizeof(SOCKADDR);
while (1)
{
//发送数据
printf("Please Input Data : \n");
gets(sendBuf);
sendto(sockSrv,sendBuf,strlen(sendBuf)+1,0,(SOCKADDR*)&addrSrv,len);
//等待并且接收数据
recvfrom(sockSrv,recvBuf,100,0,(SOCKADDR*)&addrSrv,&len);
if ('q' == recvBuf[0])
{
sendto(sockSrv,"q",strlen("q")+1,0,(SOCKADDR*)&addrSrv,len);
printf("Chat end!\n");
break;
}
sprintf(tempBuf,"%s say : %s",inet_ntoa(addrSrv.sin_addr),recvBuf);
printf("%s\n",tempBuf);
}
closesocket(sockSrv);
WSACleanup();
}
运行结果:
多线程
程序、进程、线程
程序:计算机指令的集合,是一文件的形式存储在磁盘上面的;
进程:一个正在运行的程序的实例,是一个程序在其自身地址空间的一次执行活动;
线程:真正完成代码的执行;线程只有一个内核对象和一个线程栈,占用内存少;
所以说一个程序对应多个进程;进程是线程的容器;进程是线程的执行环境;
线程创建函数Create Thread
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
DWORD dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId);
举例
举例1:简单
#include <WINDOWS.H>//需要访问windows API 函数,因此许加入此头文件
#include <IOSTREAM.H>
DWORD WINAPI Fun1Pro(LPVOID lpParameter);
void main()//主线程
{
HANDLE hThread1;
hThread1 = CreateThread(NULL,0,Fun1Pro,NULL,0,NULL);
CloseHandle(hThread1);//这里并不是终止新创建的线程,而是不再需要线程句柄
cout<<"Main thread is running..."<<endl;
}
DWORD WINAPI Fun1Pro(LPVOID lpParameter)
{
cout<<"Thread1 is running..."<<endl;
return 0;
}
错误8
代码
//MultiThread.cpp
#include <WINDOWS.H>//需要访问windows API 函数,因此许加入此头文件
#include <IOSTREAM.H>
DWORD WINAPI Fun1Pro(LPVOID lpParameter);
int nIndex = 0;
void main()//主线程
{
HANDLE hThread1;
hThread1 = CreateThread(NULL,0,Fun1Pro,NULL,0,NULL);
CloseHandle(hThread1);//这里并不是终止新创建的线程,而是不再需要线程句柄
// Sleep(10); //让主线程睡眠10ms,睡眠期间好让线程1执行
while (nIndex++<1000)
cout<<"Main thread is running..."<<endl;
}
DWORD WINAPI Fun1Pro(LPVOID lpParameter)
{
while (nIndex++<1000) //验证线程是交替运行的,运用的是时间片技术
cout<<"Thread1 is running..."<<endl;
// int i = 0;
// while (++i)//计算计算机的运行效率
// {
// cout<<i<<".Thread1 is running..."<<endl;
// }
return 0;
}
举例2:火车票
代码:
#include <WINDOWS.H>//需要访问windows API 函数,因此许加入此头文件
#include <IOSTREAM.H>
DWORD WINAPI Fun1Pro(LPVOID lpParameter);
DWORD WINAPI Fun2Pro(LPVOID lpParameter);
int nIndex = 0;
int nTickets = 100;
void main()//主线程
{
HANDLE hThread1;
HANDLE hThread2;
hThread1 = CreateThread(NULL,0,Fun1Pro,NULL,0,NULL);
hThread2 = CreateThread(NULL,0,Fun2Pro,NULL,0,NULL);
CloseHandle(hThread1);
CloseHandle(hThread2);
Sleep(4000);
}
DWORD WINAPI Fun1Pro(LPVOID lpParameter)
{
while (TRUE)
{
if (nTickets>0)
cout<<"Thread1 sells tickets : "<<nTickets--<<endl;
else
break;
}
return 0;
}
DWORD WINAPI Fun2Pro(LPVOID lpParameter)
{
while (TRUE)
{
if (nTickets>0)
cout<<"Thread2 sells tickets : "<<nTickets--<<endl;
else
break;
}
return 0;
}
错误9
利用互斥对象实现线程同步(采用匿名互斥对象的方法)
1、 首先定义全局互斥对象,我叫公共房间的钥匙
2、 创建互斥对象 将钥匙放在房间门上
3、 在子线程当中添加主动请求信号函数,拿到钥匙进入房间
4、 在子线程当中释放互斥对象,走出房间,将钥匙归位
5、 值得注意的是,对于互斥对象:谁拥有谁释放
1、 HANDLE hMutex;
2、 hMutex = CreateMutex(NULL,FALSE,NULL);//创建匿名互斥对象
3、 WaitForSingleObject(hMutex,INFINITE);
4、 ReleaseMutex(hMutex);
CreateMutex
ReleaseMutex
此函数在调用之前会先判断该线程ID与当前拥有互斥对象的线程ID是否一致,一致就释放。
WaitForSingleObject
保证应用程序只有一个实例运行(采用命名互斥对象的方法)
hMutex = CreateMutex(NULL,TRUE,"tickets");
if (hMutex)
{
if (ERROR_ALREADY_EXISTS == GetLastError())
{
cout<<"Only one thread can run..."<<endl;
return;
}
}
WaitForSingleObject(hMutex,INFINITE);
ReleaseMutex(hMutex);
ReleaseMutex(hMutex);
网络聊天室程序
MFC加载套接字库AfxSocketInit()
所有与窗口有关的类都有一个数据成员m_hWnd
完全面向对象采用静态成员函数和静态成员变量
线程同步的另外两种方法
事件对象
CreateEvent()创建事件对象
SetEvent()设置对象状态
ResetEvent()重置对象
错误9
关键代码段
1、InitiaLizeCriticalSection()创建关键代码段
2、Enter CriticalSection()
3、Leave CriticalSection()
4、Delete CriticalSection()
互斥对象、事件对象、关键代码段的比较
基于消息的异步套接字
Windows套接字在两种模式上面执行I/O操作:阻塞模式和非阻塞模式
阻塞模式和非阻塞模式的区别
Windows Sock相关函数
WSAAsyncselect()
WSAEnumProtocols()
WSAStartup()
WSACleanup()
WSASocket()
WSARecvFrom()
WSASendTo()
进程间通信
剪切板
OpenClipboard打开剪切板
EmptyClipboard清空
SetClipboradData放置数据
GlobalAlloc
GetClipboardData
匿名管道
CreatePipe
CreatProcess
创建子进程的注意事项
命名管道
不仅可以在本机上的实现两个进程之间的通信,还可以跨网络实现两个进程之间的通信;
创建命名管道时可以指定使用权限的用户;
命名管道是围绕Windows文件系统设计的一种机制,采用“命名管道文件系统(NPFS)”接口;
它实际上建立了一个客户机/服务器通信系统;
它只能在Windows NT或Windows 2000上创建;
他提供了两种基本通信模式:字节模式和消息模式;
CreateNamedPipe
Connect
ConnectNamedPipe()
CreateFile()
WaitNamedPipe()
油槽
她是基于广播通信体系设计出来的,它采用无连接的不可靠的数据传输;
一对多的单项通信;可以基于此制作一个网络会议通知系统;
油槽实现代码非常简单,而采用SOCKET编程则相比之下太复杂;
它是一种单项通信机制,创建油槽的服务器进程读取数据,打开油槽的客户机进程写入数据;
CreateMailslot()
四种方式比较
AcitiveX控件
它相当于一个服务器应用程序,它依赖某个容器应用程序;
ActiveX控件四种属性
发行版本
总结
动态链接库
动态库和静态库
两种加载动态链接库的方式
隐式链接
动态加载
Dumpbin命令查看Dll文件
让Dll导出函数
错误10
搜索动态链接库的目录顺序
Depends工具 查看动态链接库和可执行程序,主要是查看他依赖哪些动态链接库
动态库的创建并且导出函数
//dlll.h
_declspec(dllexport) int add(int a,int b)
{
return a+b;
}
_declspec(dllexport) int subtract(int a,int b)
{
return a-b;
}
//Dlll.h
_declspec(dllimport) int add(int a,int b);
_declspec(dllimport) int subtract(int a,int b);
#include "..\Dlll\Dlll.h"//使用动态库
动态库的改造,使其能够被客户端和自己本省都能够使用
#ifdef DLLL_API
#else
#define DLLL_API _declspec(dllimport)
#endif
DLLL_API int add(int a,int b);
DLLL_API int subtract(int a,int b);
#define DLLL_API _declspec(dllexport)
#include "Dlll.h"
int add(int a,int b)
{
return a+b;
}
int subtract(int a,int b)
{
return a-b;
}
从Dll中导出C++类
动态库函数名字改编问题
名字没有改编 |
动态加载动态库LoadLibrary()
void CDllTestDlg::OnBtnAdd()
{
// TODO: Add your control notification handler code here
HINSTANCE hInst;//定义一个实例句柄对象
hInst = LoadLibrary("Dlll.dll");//动态加载动态库
typedef int (*ADDPROC)(int a,int b);//定义函数指针类型
ADDPROC Add = (ADDPROC)GetProcAddress(hInst,"add");//获取dll的函数地址
if (!Add)
{
MessageBox("获取函数地址失败");
return;
}
CString str;
str.Format("5+3=%d",Add(5,3));
MessageBox(str);
}
void CDllTestDlg::OnBtnSub()
{
// TODO: Add your control notification handler code here
HINSTANCE hInst;//定义一个实例句柄对象
hInst = LoadLibrary("Dlll.dll");//动态加载动态库
typedef int (*ADDPROC)(int a,int b);//定义函数指针类型
ADDPROC Sub = (ADDPROC)GetProcAddress(hInst,"subtract");//获取dll的函数地址
if (!Sub)
{
MessageBox("获取函数地址失败");
return;
}
CString str;
str.Format("5-3=%d",Sub(5,3));
MessageBox(str);
}
/************************************************************************/
/* 该dll文件自己是不能够运行的,必须要有某个客户程序加载这个dll,然后调用
SetHook函数,调用SetWindowsHookEx函数,安装钩子,这样就可以加载全局钩子了*/
/************************************************************************/
#include <WINDOWS.H>
/*_declspec(dllexport) void SetHook();*/
HHOOK g_hMouse = NULL;
//鼠标钩子过程
LRESULT CALLBACK MouseProc(int nCode,WPARAM wParam,LPARAM lParam)
{
return 1;//返回非0值表示鼠标消息已经处理了
}
//鼠标钩子安装
void SetHook()
{
g_hMouse = SetWindowsHookEx(WH_MOUSE,MouseProc,GetModuleHandle("HOOK"),0);
//第四个参数为0,表示与运行在同一桌面所有进程相关
//第三个参数指定安装钩子过程所在的Dll模块句柄,返回给HOOk.dll
}