友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!阅读过程发现任何错误请告诉我们,谢谢!! 报告错误
喜书网 返回本书目录 我的书架 我的书签 TXT全本下载 进入书吧 加入书签

C语言实例教程(PDF格式)-第23章

按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!




这里我们假设对该工程命名为SdkDemo1,而事实上这完全取决于你的 

意愿。这个过程已经在本书的第一章中作为介绍,这里就不再重复说 

明了。  



2。  选择Project菜单下的Add  To  Project|New。。。命令,向工程中添 

加一个C++    Source  File  (C++源文件),可以将该文件命名为 

winmain。cpp,不需要键入扩展名,Microsoft  Developer  Studio在 

创建文件时会 自动加上。cpp的后缀名。这个过程也已经在第一章中作 

过介绍。阅读过该章内容的读者不应感到陌生。然后在Wordspace窗 

口的FileView 中双击文件名winmain。cpp  (在依赖于你在前面过程中 

的设定),输入下面的源代码即可。  



如果已将源代码输入为C++源文件 (以。cpp为后缀名的文件),则可以 

使用Project|Add To Project|Files。。。将其添加到工程中。  



                                         



               图3。2 示例程序SdkDemo1的运行结果  



3。  单击Build菜单下的Build  SdkDemo1。exe或Build  All或按下快捷 

键F7   (如果未对该快捷键做过 自定义操作的话)或单击Build或Build  

Minibar工具条上的   按钮,编译并创建可执行文件SdkDemo1。exe, 

运行该可执行文件 (从Developer  Studio中或资源管理器均可),将得 

到如图3。2所示的结果。  



前面已经不只一次说到过,使用这种方式编写的应用程序使用调试和 

维护的难度很大。这个问题是使用直接使用SDK编程的固有总是。但 

是,我们还是有办法可以使得该程序的结构更紧凑和更集中一些,从 

而改善代码的可读性,也使得它更接近于使用SDK编写的真正的Win32 

应用程序。  


…………………………………………………………Page 142……………………………………………………………

通过分析应用程序,我们发现,在上面的程序代码中,WinMain函数 

的代码显得有些过分臃肿,解决总是的办法就是将这些代码分离为单 

个的函数,这样,我们就可以得到更实用的基本SDK应用程序框架, 

当然,相对于MFC所提供的应用程序框架来说,我们的这个应用程序 

框架几乎不值一提,但是,它的确是要比前面的示例程序好多了。  



经过修改的代码如下:  



#include   



// 函数原型  



int WINAPI WinMain(HINSTANCE;HINSTANCE;LPSTR;int);  



LRESULT WINAPI WndProc(HWND;UINT;WPARAM;LPARAM);  



BOOL InitApplication(HINSTANCE);  



BOOL InitInstance(HINSTANCE;int);  



// WinMain 函数  



int WINAPI WinMain (HINSTANCE hInstance;  



HINSTANCE hPrevInstance;  



LPSTR lpCmdLine;  



int nCmdShow)  



{  



if (!hPrevInstance)  



if (!InitApplication(hInstance))  



return FALSE;  



if (!InitInstance(hInstance;SW_SHOW))  



return FALSE;  



MSG msg; // 窗口消息  



// 开始消息循环  



while (GetMessage(&msg;NULL;0;0))  



{  


…………………………………………………………Page 143……………………………………………………………

TranslateMessage(&msg);  



DispatchMessage(&msg);  



}  



return msg。wParam;  



}  



// WndProc 主窗口过程  



LRESULT WINAPI WndProc (HWND hWnd;  



UINT msg;  



WPARAM wParam;  



LPARAM lParam)  



{  



HDC hdc;  



RECT rc;  



HPEN hPen;hPenOld;  



HBRUSH hBrush;hBrushOld;  



switch (msg)  



{  



case WM_PAINT:  



hdc=GetDC(hWnd);  



GetClientRect(hWnd;&rc);  



hPen=CreatePen(PS_SOLID;0;RGB(0;0;0));  



hBrush=CreateHatchBrush(HS_DIAGCROSS;RGB(0;0;0));  



hPenOld=SelectObject(hdc;hPen);  



hBrushOld=SelectObject(hdc;hBrush);  



Ellipse(hdc;rc。left;rc。top;rc。right;rc。bottom);  



SelectObject(hdc;hPenOld);  


…………………………………………………………Page 144……………………………………………………………

SelectObject(hdc;hBrushOld);  



ReleaseDC(hWnd;hdc);  



break;  



case WM_DESTROY:  



PostQuitMessage(0);  



break;  



default:  



break;  



}  



return DefWindowProc(hWnd;msg;wParam;lParam);  



}  



BOOL InitApplication(HINSTANCE hInstance)  



{  



WNDCLASS wc; // 窗口类  



// 填充窗口类信息  



wc。style=CS_HREDRAW|CS_VREDRAW;  



wc。lpfnWndProc=WndProc;  



wc。cbClsExtra=0;  



wc。cbWndExtra=0;  



wc。hInstance=hInstance;  



wc。hIcon=LoadIcon(NULL;IDI_APPLICATION);  



wc。hCursor=LoadCursor(NULL;IDC_ARROW);  



wc。hbrBackground=GetStockObject(WHITE_BRUSH);  



wc。lpszMenuName=NULL;  



wc。lpszClassName=〃SdkDemo2〃;  



// 注册窗口类  


…………………………………………………………Page 145……………………………………………………………

return RegisterClass(&wc);  



}  



BOOL InitInstance(HINSTANCE hInstance;int nCmdShow)  



{  



HWND hWnd; // 主窗口句柄  



// 创建应用程序主窗口  



hWnd=CreateWindow (〃SdkDemo2〃; // 窗口类名  



〃经过修改的第一个Win32 SDK应用程序〃; // 窗口标题  



WS_OVERLAPPEDWINDOW; // 窗口样式  



CW_USEDEFAULT; // 初始化 x 坐标  



CW_USEDEFAULT; // 初始化 y 坐标  



CW_USEDEFAULT; // 初始化窗口宽度  



CW_USEDEFAULT; // 初始化窗口高度  



NULL; // 父窗口句柄  



NULL; // 窗口菜单句柄  



hInstance; // 程序实例句柄  



NULL); // 创建参数  



if (!hWnd)  



return FALSE;  



// 显示窗口  



ShowWindow(hWnd;SW_SHOW);  



// 更新主窗口客户区  



UpdateWindow(hWnd);  



return TRUE;  



}  



由于上面的代码只是将前面的代码的结构作了一下调整,并没有引入 


…………………………………………………………Page 146……………………………………………………………

新的API函数和其它编程内容,因此为了节省篇幅,我们这里对该代 

码不再进行讲解,至于其与SdkDemo1的代码相比的优越性,由读者自 

己将两段代码对比后得出。  



            第四节 32位编程的特点  



本节假定用户是刚接触32位Windows编程的新手,那么,有必要将一 

些相关的概念术语弄清楚,同时,也要把Windows 95、Windows NT和 

16位的Windows   3。x相区别开来。这些最重要的概念包括进程和线程 

的管理以及新的32位平坦内存模式。  



在介绍32位内存管理之前,我们有必要介绍一下进程和线程这两个术 

语。  



进程是装入内存中正在执行的应用程序,进程包括私有的虚拟地址空 

间、代码、数据及其它操作系统资源,如文件、管道以及对该进程可 

见的同步对象等。进程包括了一个或多个在进程上下文内运行的线 

程。  



线程是操作系统分配CPU时间的基本实体。线程可以执行应用程序代 

码的任何部分,包括当前正在被其它线程执行的那些。同一进程的所 

有线程共享同样的虚拟地址空间、全局变量和操作系统资源。  



在一个应用程序中,可以包括一个或多个进程,每个进程由一个或多 

个线程构成。  



线程通过 “休眠”(sleeping,暂停所有执行并等待)的方法,来做到 

与进程中的其它线程所同步。在线程休眠前,必须告诉Windows,该 

线程将等待某一事件的发生。当该事件发生时,Windows发给线程一 

个唤醒调用,线程继续执行。也就是说,线程与事件一起被同步,除 

此之外,也可以由特殊的同步对象来进行线程的同步。这些同步对象 

包括:  



 l 互斥 不受控制的或随意的线程访问在多线程应用程序中可能会引 

  起很大的问题。这里所说的互斥是一小须代码,它时刻采取对共 

  享数据的独 占控制以执行代码。互斥常被应用于多进程的同步数 

  据存取。  



 l 信号量 信号量与互斥相似,但是互斥只允许在同一时刻一个线程 

  访问它的数据,而信号量允许多个线程在同一时刻访问它的数 

  据。Win32不知道哪一个线程拥有信号量,它只保证信号量使用的 

  资源量。  


…………………………………………………………Page 147……………………………………………………………

  l 临界区 临界区对象也和互斥相似,但它仅被属于单个进程的线程 

   使用。临界区对象提供非常有效的同步模式,同互斥一样,每次 

   在同一时间内只有一个线程可以访问临界区对象。  



  l 事件 事件对象用于许多实例中去通知休眠的线程所等待的事件已 

   经发生,事件告诉线程何时去执行某一个给定的任务,并可以使 

   多线程流平滑。  



将所有的这些同步对象应用于控制数据访问使得线程同步成为可能, 

否则,如果一个线程改变了另一个线程正在读的数据,将有可能导致 

很大的麻烦。  



在Win32环境下,每个运行的在进程内的线程还可以为它自己的特定 

线程数据分配内存,通过Win32提供的线程本地存储 (TLS)API,应用 

程序可以建立动态的特定线程数据,在运行时这些数据联系在一起。  



本书将在专门的章节中讨论线程和进程的问题。  



下面我们来看在32位应用程序地址空间中的内存分配和内存管理。  



常见的内存分配可以划分为两类:帧分配 (frame  allocation)和堆分 

配 (heap   allocation)。两者的主要区别在于帧分配通常和实际的内 

存块打交道,而堆分配在一般情况下则使用指向内存块的指针,并 

且,帧对象在超过其作用域时会被自动的删除,而程序员必须显式的 

删除在堆上分配的对象。  



在帧上分配内存的这种说法来源于 “堆栈帧”(stack   frame)这个名 

词,堆栈帧在每当函数被调用时创建,它是一块用来暂时保存函数参 

数以及在函数中定义的局部变量的内存区域。帧变量通常被称作自动 
返回目录 上一页 下一页 回到顶部 0 0
未阅读完?加入书签已便下次继续阅读!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!