孙鑫VC++学习笔记(转载至程序员之家--虎非龙)[11--15]

第11课 1.创建4个菜单,为其添加消息响应,用成员变量保存绘画类型。添加LButtonDown和Up消息。 2.当窗口重绘时,如果想再显示原先画的数据,则需要保存数据。为此创建一个新类来记录绘画类型和两个点。 class CGraph { public: CPoint m_ptOrigin;//起点 CPoint m_ptEnd;//终点 UINT m_nDrawType;//绘画类型 CGraph(); CGraph(UINT m_nDrawType,CPoint m_ptOrigin,CPoint m_ptEnd);//此为构造函数。 virtual ~CGraph();

}; 然后在void CGraphicView::OnLButtonUp(UINT nFlags, CPoint point)中加入如下代码 //CGraph graph(m_nDrawType,m_ptOrigin,point);//不能用局部变量 //m_ptrArray.Add(&graph);//加入这种指针数组中 /* OnPrepareDC(&dc);//这个函数中可以重新设置窗口原点,对于滚动条中,保存数据前要调用此函数 dc.DPtoLP(&m_ptOrigin);//将设备坐标转换为逻辑坐标 dc.DPtoLP(&point);// CGraph *pGraph=new CGraph(m_nDrawType,m_ptOrigin,point);//在堆中创建新的对象 m_ptrArray.Add(pGraph);*///加入到指针数组中 在GraphicView.h中有如下代码 CPtrArray m_ptrArray; 在OnDraw中重画时调出数据 for(int i=0;i<m_ptrArray.GetSize();i++) 3.在CView::OnPaint()调用了OnDraw(),但在void CGraphicView::OnPaint()中MFC的Wizard没有调用OnDraw(),要注意这个区别。如果你此时想调用,必须手动添加代码。 OnDraw(&dc); 4.让窗口具有滚动条的功能。 第1.将CGraphicView的头文件中的CView全部替换成CSrollView 第2.添加如下的代码 void CGraphicView::OnInitialUpdate() { CScrollView::OnInitialUpdate(); // TOD Add your specialized code here and/or call the base class SetScrollSizes(MM_TEXT,CSize(800,600));//设置映射模式,设定窗口大小。OK! } 5.坐标系的转换,此处不再详细介绍,需要时请查阅相关资料。 6.解决重绘时线跑到上面的问题。为什么会错位?因为逻辑坐标和设备坐标没有对应起来。 解决方法: 在OnLButtonDown画完图后,保存之前。调用 /* OnPrepareDC(&dc);//重新设置逻辑坐标的原点!!! dc.DPtoLP(&m_ptOrigin);//设备坐标转化为逻辑坐标 dc.DPtoLP(&point); CGraph *pGraph=new CGraph(m_nDrawType,m_ptOrigin,point); m_ptrArray.Add(pGraph);*/ 7.另外两种方法来保存数据。 一种是用CMetaFileDC 另一种是利用兼容DC,重绘时利用 pDC->BitBlt(0,0,rect.Width(),rect.Height(),&m_dcCompatible,0,0,SRCCOPY); 将兼容DC的图拷贝到屏幕DC上去。 此处不再详细介绍这两种方法,因为介绍多了容易搞晕。呵呵

 

 

第12课 文件操作 1.常量指针与指针常量的区分 char ch[5]="lisi"; const char *pStr=ch;//const在*之前,表明指针指向的内容为常量,即为常量指针 char * const pStr=ch;//const在*之后,表明指针的地址不能改变,即为指针常量 明白? 2.对文件读写的三种方法 1.C中 FILE *pFile=fopen("1.txt","w"); fwrite("http://www.sunxin.org",1,strlen("http://www.sunxin.org"),pFile); //fseek(pFile,0,SEEK_SET); //fwrite("ftp:",1,strlen("ftp:"),pFile); //fwrite("http://www.sunxin.org",1,strlen("http://www.sunxin.org"),pFile); fclose(pFile);*/ //fflush(pFile); 2.C++中 /* ofstream ofs("4.txt"); ofs.write("http://www.sunxin.org",strlen("http://www.sunxin.org")); ofs.close();*/ 要包括头文件 "fstream.h" 3.MFC中 用CFile类,哈哈!简单好用 CFileDialog fileDlg(FALSE); fileDlg.m_ofn.lpstrTitle="我的文件保存对话框"; fileDlg.m_ofn.lpstrFilter="Text Files(*.txt)/0*.txt/0All Files(*.*)/0*.*/0/0"; fileDlg.m_ofn.lpstrDefExt="txt"; if(IDOK==fileDlg.DoModal()) { CFile file(fileDlg.GetFileName(),CFile::modeCreate | CFile::modeWrite); file.Write("http://www.sunxin.org",strlen("http://www.sunxin.org")); file.Close(); } 4.利用win32 API函数 CreateFile(),及WriteFile() 4.注册表读写 1.对win.ini的读写 //::WriteProfileString("http://www.sunxin.org","admin","zhangsan"); /* CString str; ::GetProfileString("http://www.sunxin.org","admin","lisi", str.GetBuffer(100),100); AfxMessageBox(str);*/ 2.注册表的读写 HKEY hKey; DWORD dwAge=30; RegCreateKey(HKEY_LOCAL_MACHINE,"Software//http://www.sunxin.org//admin",&hKey); RegSetValue(hKey,NULL,REG_SZ,"zhangsan",strlen("zhangsan")); RegSetValueEx(hKey,"age",0,REG_DWORD,(CONST BYTE*)&dwAge,4); RegCloseKey(hKey);以上是写入 代码比较简单,不再详细介绍。本笔记也不是为介绍函数而存在的。嘿嘿

 

 

 

第13课 文档与串行化 1.CArchive在菜单打开保存时的代码 CFile file("1.txt",CFile::modeCreate | CFile::modeWrite); CArchive ar(&file,CArchive::store); int i=4; char ch='a'; float f=1.3f; CString str("http://www.sunxin.org"); ar<<i<<ch<<f<<str;以上是保存,打开略 2.文档-视类结构简介 OnNewDocument在程序启动时被调用,此时可设置文档标题,也可以在String Table的IDR_MAINFRAME的第二个"/"后改变文档的标题。须了解的7个字符串的用途,见PPT。 在WinAPP的InitInstance()中完成DOC,View,MainFrame的归一。 当点击系统的打开和新建菜单时,有一系列的步骤,孙鑫老师给我们跟踪了代码的调用过程,此段跟踪我们略过。但我们要牢记住:CWinAPP负责管理文档管理器,文档管理器有一个指针链表,且来保存文档模板的指针,文档模板指针管理三个类DOC,VIEW,MAINFRAME,使其为某文件对象服务。 3.利用CArchive来保存一个类的对象,此类必须支持串行化,需要5个步骤。 a.让类从CObject派生; b.覆盖Serialize()函数,在其中完成保存和读取功能; c.在.h中加入 DECLARE_SERIAL(CGraph); d.在。cpp中加入IMPLEMENT_SERIAL(CGraph, CObject, 1 ); e.定义一个不带参数的构造函数。 保存绘画数据到文件的简单过程 a.在CGraph中增加一个画图的成员函数,其实不增加也行。可以在View中完成相应功能。 b.增加四个画图菜单,菜单可以从11课的代码中拷贝。 c.在View中增加LButtonDown和UP的响应,在UP中画图,在DOWN中保存点 d.利用CObArray集合类来保存绘画数据 e.在CGraphicDOC::Serialize()中保存和读取数据 f.然后在OnDraw中重绘。 4.新建和打开文档时,要注意销毁原来的数据。在DOC的DeleteContents虚函数中是好时机。代码如下 int nCount; nCount=m_obArray.GetSize(); /*for(int i=0;i<nCount;i++) { delete m_obArray.GetAt(i);//释放指针指向的内存空间 //m_obArray.RemoveAt(i);//移除链表中的元素。嘿嘿,别搞错了。但在此处不能这样用,会导致非法操作。要用下面的方法沙 } m_obArray.RemoveAll();*/ while(nCount--) { delete m_obArray.GetAt(nCount); m_obArray.RemoveAt(nCount); }

 

 

第14课 网络编程 1.TCP流式套接字的编程步骤 在使用之前须链接库函数:工程->设置->Link->输入ws2_32.lib,OK! 服务器端程序: 1、加载套接字库 2、创建套接字(socket)。 3、将套接字绑定到一个本地地址和端口上(bind)。 4、将套接字设为监听模式,准备接收客户请求(listen)。 5、等待客户请求到来;当请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept)。 6、用返回的套接字和客户端进行通信(send/recv)。 7、返回,等待另一客户请求。 8、关闭套接字。 客户端程序: 1、加载套接字库 2、创建套接字(socket)。 3、向服务器发出连接请求(connect)。 4、和服务器端进行通信(send/recv)。 5、关闭套接字。 服务器端代码如下: #include <Winsock2.h>//加裁头文件 #include <stdio.h>//加载标准输入输出头文件

void main() { WORD wVersionRequested;//版本号 WSADATA wsaData; int err; wVersionRequested = MAKEWORD( 1, 1 );//1.1版本的套接字 err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) { return; }//加载套接字库,加裁失败则返回

if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) { WSACleanup( ); return; }//如果不是1.1的则退出 SOCKET sockSrv=socket(AF_INET,SOCK_STREAM,0);//创建套接字(socket)。

SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);//转换Unsigned short为网络字节序的格式 addrSrv.sin_family=AF_INET; addrSrv.sin_port=htons(6000);

bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR)); //将套接字绑定到一个本地地址和端口上(bind) listen(sockSrv,5);//将套接字设为监听模式,准备接收客户请求(listen)。

SOCKADDR_IN addrClient;//定义地址族 int len=sizeof(SOCKADDR);//初始化这个参数,这个参数必须被初始化

while(1) { SOCKET sockConn=accept(sockSrv,(SOCKADDR*)&addrClient,&len);accept的第三个参数一定要有初始值。 //等待客户请求到来;当请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept)。 //此时程序在此发生阻塞 char sendBuf[100]; sprintf(sendBuf,"Welcome %s to http://www.sunxin.org", inet_ntoa(addrClient.sin_addr)); //用返回的套接字和客户端进行通信(send/recv)。 send(sockConn,sendBuf,strlen(sendBuf)+1,0); char recvBuf[100]; recv(sockConn,recvBuf,100,0); printf("%s/n",recvBuf); closesocket(sockConn);//关闭套接字。等待另一个用户请求 } }

客户端代码如下: #include <Winsock2.h> #include <stdio.h>

void main() { WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD( 1, 1 ); err = WSAStartup( wVersionRequested, &wsaData );加载套接字库 if ( err != 0 ) { return; }

if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) { WSACleanup( ); return; } SOCKET sockClient=socket(AF_INET,SOCK_STREAM,0);创建套接字(socket)。

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); connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));向服务器发出连接请求(connect)。

char recvBuf[100];和服务器端进行通信(send/recv)。 recv(sockClient,recvBuf,100,0); printf("%s/n",recvBuf); send(sockClient,"This is lisi",strlen("This is lisi")+1,0);

closesocket(sockClient);关闭套接字。 WSACleanup();//必须调用这个函数清除参数 }

2.UDP型套接字。 服务器端(接收端)程序: 1、创建套接字(socket)。 2、将套接字绑定到一个本地地址和端口上(bind)。 3、等待接收数据(recvfrom)。 4、关闭套接字。 客户端(发送端)程序: 1、创建套接字(socket)。 2、向服务器发送数据(sendto)。 3、关闭套接字。 服务器端代码: #include <Winsock2.h> #include <stdio.h>

void main() { WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD( 1, 1 ); err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 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));

SOCKADDR_IN addrClient; int len=sizeof(SOCKADDR); char recvBuf[100];

recvfrom(sockSrv,recvBuf,100,0,(SOCKADDR*)&addrClient,&len); printf("%s/n",recvBuf); closesocket(sockSrv); WSACleanup(); }

客户端代码: #include <Winsock2.h> #include <stdio.h>

void main() { WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD( 1, 1 ); err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) { return; }

if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) { WSACleanup( ); return; }

SOCKET sockClient=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);

sendto(sockClient,"Hello",strlen("Hello")+1,0, (SOCKADDR*)&addrSrv,sizeof(SOCKADDR)); closesocket(sockClient); WSACleanup(); } UDP的不再加注释了。因为它比TCP的简单多了。 3.基于字符界面的聊天程序,用的是UDP式套接字。代码略。 4.如何添加新的工程? 首先选择中Build工具栏,然后在工程管理器上点击右键,选择增加新的工程即可。

 

 

 

第15课多线程与网络编程 1.多线程介绍,略 2.一个简单的多线程程序 MSND中参数[in]和[out]的含义要注意 #include <windows.h> #include <iostream.h>

DWORD WINAPI Fun1Proc( LPVOID lpParameter // thread data );

DWORD WINAPI Fun2Proc( LPVOID lpParameter // thread data ); int index=0; int tickets=100; HANDLE hMutex;互斥对象的句柄 void main() { HANDLE hThread1; HANDLE hThread2; hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);创建线程1 hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);创建线程2 CloseHandle(hThread1);关闭线程的句柄,为什么要关闭?它将线程的使用计数减1 CloseHandle(hThread2);这样当线程结束时,线程内核对象被释放,否则只有当进程结束,才释放线程的内核对象 /*while(index++<1000) cout<<"main thread is running"<<endl;*/ //hMutex=CreateMutex(NULL,TRUE,NULL);将第二个参数设为true后,互斥对象的计数加1 hMutex=CreateMutex(NULL,TRUE,"tickets");此段代码可以让系统只一份实例在运行! if(hMutex) { if(ERROR_ALREADY_EXISTS==GetLastError()) { cout<<"only instance can run!"<<endl; return; } } WaitForSingleObject(hMutex,INFINITE);此代码也将互斥对象的计数加1 ReleaseMutex(hMutex);所以要释放两次互斥对象 ReleaseMutex(hMutex); Sleep(4000);睡眠4000毫秒 // Sleep(10); }

DWORD WINAPI Fun1Proc( LPVOID lpParameter // thread data ) { /*while(index++<1000) cout<<"thread1 is running"<<endl;*/ /*while(TRUE) { //ReleaseMutex(hMutex); WaitForSingleObject(hMutex,INFINITE);等待互斥对象的到来,到来后将互斥对象的计数加1 if(tickets>0) { Sleep(1); cout<<"thread1 sell ticket : "<<tickets--<<endl; } else break; ReleaseMutex(hMutex);释放互斥对象,将其计数减1,这样可以保证,这两句话之间 的代码!的执行连续性! }*/

WaitForSingleObject(hMutex,INFINITE); cout<<"thread1 is running"<<endl; return 0; }

DWORD WINAPI Fun2Proc( LPVOID lpParameter // thread data ) { /*while(TRUE) { //ReleaseMutex(hMutex); WaitForSingleObject(hMutex,INFINITE); if(tickets>0) { Sleep(1); cout<<"thread2 sell ticket : "<<tickets--<<endl; } else break; ReleaseMutex(hMutex); }*/ WaitForSingleObject(hMutex,INFINITE); cout<<"thread2 is running"<<endl; return 0; }

3.多线程聊天程序 1.加载套接字库在InitInstance()中,调用AfxSocketInit(),此时可以不加载库文件,但要加入Afxsock.h"头文件 2.在CChatDlg中创建成员变量m_socket,然后增加一个成员函数,IniSocket(),在其中完成m_socket的初始化和绑定。在OnInitDialog中调用InitSocket完成初始化工作。 3.定义一个结构体,包含两个参数,sock和hwnd,在OnInitDialog()中初始化这个结构体的对象。 4.创建一个线程,CreateThread(),须将线程函数RecvProc定义为静态的或者全局函数。 ::PostMessage()完成将收到的数据发送给对话框。用自定义的消息,自定义的消息如何写?以前说过,参考下面的代码。注意要将EDitBox的MultiLine属性选上。 在ChatDlg.h中#define WM_RECVDATA WM_USER+1 afx_msg void OnRecvData(WPARAM wParam,LPARAM lParam); 在ChatDlg.cpp中 ON_MESSAGE(WM_RECVDATA,OnRecvData) 然后实现这个函数 void CChatDlg::OnRecvData(WPARAM wParam,LPARAM lParam) { CString str=(char*)lParam; CString strTemp; GetDlgItemText(IDC_EDIT_RECV,strTemp); str+="/r/n"; str+=strTemp; SetDlgItemText(IDC_EDIT_RECV,str); } 最后在DWORD WINAPI CChatDlg::RecvProc(LPVOID lpParameter) 中调用 ::PostMessage(hwnd,WM_RECVDATA,0,(LPARAM)tempBuf); //不能用SendMessage() 4.对发送按纽的响应代码: void CChatDlg::OnBtnSend() { // TOD Add your control notification handler code here DWORD dwIP; ((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1))->GetAddress(dwIP);

SOCKADDR_IN addrTo; addrTo.sin_family=AF_INET; addrTo.sin_port=htons(6000); addrTo.sin_addr.S_un.S_addr=htonl(dwIP);

CString strSend; GetDlgItemText(IDC_EDIT_SEND,strSend); sendto(m_socket,strSend,strSend.GetLength()+1,0, (SOCKADDR*)&addrTo,sizeof(SOCKADDR)); SetDlgItemText(IDC_EDIT_SEND,""); }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值