??xml version="1.0" encoding="utf-8" standalone="yes"?> 注意在Winsock 2发布之后Q重叠I/O仍可在Windows NT和Windows 2000q两个操作系l中Q随R e a d F i l e和Wr i t e F i l e两个函数使用。但是,Windows 95和Windows 98均不具备q一功能。考虑到应用程序的跨^台兼定w题,同时考虑到性能斚w的因素,应尽量避免用Wi n 3 2的R e a d F i l e和Wr i t e F i l e函数Q分别换以W S A R e c v和W S A S e n d函数。本节只打算讲述通过新的Winsock 2函数Q来使用重叠I/O模型?br />要想在一个套接字上用重叠I / O模型Q首先必M用W S A _ F L A G _ O V E R L A P P E Dq个标志Q创Z个套接字。如下所C: s = WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED); typedef struct WSAOVERLAPPED p|后,由l p c b Tr a n s f e r参数指向的g会进行更斎ͼ而且我们的应用程序应调用W S A G e t L a s t E r r o r函数Q调查到底是何种原因造成了调用失败?br />在程序清? - 7中,我们向大安qC如何~制一个简单的服务器应用,令其在一个套接字上对重叠I / O操作q行理Q程序完全利用了前述的事仉知机制。对该程序采用的~程步骤ȝ如下Q?br />1) 创徏一个套接字Q开始在指定的端口上监听q接h?br />2) 接受一个进入的q接h?br />3) 为接受的套接字新Z个W S A O V E R L A P P E Dl构Qƈl构分配一个事件对象句柄?br />也将事g对象句柄分配l一个事件数l,以便E后由W S AWa i t F o r M u l t i p l e E v e n t s函数使用?br />4) 在套接字上投递一个异步W S A R e c vhQ指定参CؓW S A O V E R L A P P E Dl构?br />注意函数通常会以p|告终Q返回S O C K E T _ E R R O R错误状态W S A _ I O _ P E N D I N GQI/O操作未完成Q?br />5) 使用步骤3 )的事件数l,调用W S AWa i t F o r M u l t i p l e E v e n t s函数Qƈ{待与重叠调用关联在一L事gq入“已传信”状态(换言之,{待那个事g的“触发”)?br />6) WSAWa i t F o r M u l t i p l e E v e n t s函数完成后,针对事g数组Q调用W S A R e s e t E v e n tQ重设事Ӟ函数Q从而重设事件对象,q对完成的重叠请求进行处理?br />7) 使用W S A G e t O v e r l a p p e d R e s u l t函数Q判断重叠调用的q回状态是什么?br />8) 在套接字上投递另一个重叠W S A R e c vh?br />9) 重复步骤5 ) ~ 8 )?br />q个例子极易扩展Q提供对多个套接字的支持。方法是代码的重叠I / O处理部分U至一个独立的U程内,让主应用E序U程为附加的q接h提供服务?br />E序清单8-7 采用事g机制的简单重叠I / O处理CZ
在Wi n s o c k中,相比我们q今为止解释q的其他所有I / O模型Q重叠I / OQOverlapped I/OQ?br />模型使应用程序能辑ֈ更佳的系l性能。重叠模型的基本设计原理便是让应用程序用一个重叠的数据l构Q一ơ投递一个或多个Winsock I/Oh。针寚w些提交的hQ在它们完成之后Q应用程序可为它们提供服务。该模型适用于除Windows CE之外的各UWi n d o w sq_?br />模型的M设计以Wi n 3 2重叠I / O机制为基。那个机制可通过R e a d F i l e和Wr i t e F i l e两个函数Q针对设备执行I / O操作?br />最开始的时候,Wi n s o c k重叠I / O模型只能应用于Windows NT操作pȝ上运行的Wi n s o c k1 . 1应用E序。作为应用程序,它可针对一个套接字句柄Q调用R e a d F i l e以及Wr i t e F i l eQ同时指定一个重叠式l构Q稍后详qͼQ从而利用这个模型。自Winsock 2发布开始,重叠I / O便已集成到新的Wi n s o c k函数中,比如W S A S e n d和W S A R e c v。这样一来,重叠I / O模型便能适用于安装了Winsock 2的所有Wi n d o w sq_?/p>
创徏套接字的时候,假如使用的是s o c k e t函数Q而非W S A S o c k e t函数Q那么会默认讄W S A _ F L A G _ O V E R L A P P E D标志。成功徏好一个套接字Q同时将其与一个本地接口绑定到一起后Q便可开始进行重叠I / O 操作Q方法是调用下述的Wi n s o c k 函数Q同时指定一?br />W S A O V E R L A P P E Dl构Q可选)Q?br />?W S A S e n d
?W S A S e n d To
?W S A R e c v
?W S A R e c v F r o m
?W S A I o c t l
?A c c e p t E x
?Tr n a s m i t F i l e
大家现在或许已经知道Q其中每个函数都与一个套接字上数据的发送、数据接收以及连接的接受有关。因此,q些zd可能会花极少的时间才能完成。这正是每个函数都可接受一个W S A O V E R L A P P E Dl构作ؓ参数的原因。若随一个W S A O V E R L A P P E Dl构一赯用这些函敎ͼ函数会立卛_成ƈq回Q无论套接字是否设ؓ锁定模式Q本章开头已详细讲过了)。它
们依赖于W S A O V E R L A P P E Dl构来返回一个I / Oh的返回?br />主要有两个方法可用来理一个重叠I / Oh的完成:我们的应用程序可{待“事件对象通知”,亦可通过“完成例E”,对已l完成的h加以处理。上面列出的函数Q?A c c e p t E x除外Q还有另一个常用的参数Q?br />l p C o m p l e t i o n R O U T I N E。该参数指定的是一个可选的指针Q指向一个完成例E函敎ͼ在重叠请求完成后调用。接下去Q我们将探讨事g通知Ҏ。在本章E后Q还会介l如何用可选的完成例程Q代替事Ӟ对完成的重叠h加以处理?br />1. 事g通知
重叠I / O的事仉知Ҏ要求Wi n 3 2事g对象与W S A O V E R L A P P E Dl构兌在一赗若使用一个W S A O V E R L A P P E Dl构Q发出像W S A S e n d和W S A R e c vq样的I / O调用Q它们会立即q回?br />通常Q大家会发现q些I / O 调用会以p|告终Q返回S O C K E T _ E R R O R 。用W S A G e t L a s t E r r o r函数Q便可获得与错误状态有关的一个报告。这个错误状态意味着I / O操作正在q行。稍后的某个旉Q我们的应用E序需要等候与W S A O V E R L A P P E Dl构对应的事件对象,了解一个重叠I / OL何时完成。W S A O V E R L A P P E Dl构在一个重叠I / Oh的初始化Q及其后l的完成之间Q提供了一U沟通或通信机制。下面是q个l构的定义:
{
DWORD Internal;
DWORD InternalHigh;
DWORD Offset;
DWORD OffsetHigh;
WSAEVENT hEvent;
}WSAOVERLAPPED,FAR *LPWSAOVERLPPED;
其中QI n t e r n a l、I n t e r n a l H i g h、O ff s e t和O ff s e t H i g h字段均由pȝ在内部用,不应由应用程序直接进行处理或使用。而另一斚wQ?h E v e n t字段有点儿特D,它允许应用程序将一个事件对象句柄同一个套接字兌h。大家可能会觉得奇怪,如何一个事件对象句柄分配给该字D呢Q正如我们早先在W S A E v e n t S e l e c t模型中讲q的那样Q可用W S A C r e a t e E v e n t函数来创Z个事件对象句柄。一旦创建好一个事件句柄,单地重叠结构的h E v e n t字段分配l事件句柄,再用重叠结构,调用一个Wi n s o c k函数卛_Q比如W S A S e n d或W S A R e c v?br />一个重叠I / Oh最l完成后Q我们的应用E序要负责取回重叠I / O操作的结果。一个重叠请求操作最l完成之后,在事仉知Ҏ中, Wi n s o c k会更改与一个W S A O V E R L A P P E Dl构对应的一个事件对象的事g传信状态,其从“未传信”变成“已传信”。由于一个事件对象已分配lW S A O V E R L A P P E Dl构Q所以只需单地调用W S AWa i t F o r M u l t i p l e E v e n t s函数Q从而判断出一个重叠I / O调用在什么时候完成。该函数已在我们前面讲述WSAEventSelect I/O模型时介l过了。W S AWa i t F o r M u l t i p l e E v e n t s函数会等候一D规定的旉Q等待一个或多个事g对象q入“已传信”状态。在此再ơ提醒大家注意: W S AWa i t F o r M u l t i p l e E v e n t s函数一?br />最多只能等? 4个事件对象。发Cơ重叠请求完成之后,接着需要调用W S A G e t O v e r l a p p e dR e s u l tQ取得重叠结构)函数Q判断那个重叠调用到底是成功Q还是失败。该函数的定义如下:
BOOL WSAGetOverlappedResult(
SOCKET s,
LPWSAOVERLAPPED lpOverlapped,
LPWORD lpcbTransfer,
BOOL fWait,
LPWORD lpdwFlags
);
其中Q?s参数用于指定在重叠操作开始的时候,与之对应的那个套接字。l p O v e r l a p p e d参数是一个指针,对应于在重叠操作开始时Q指定的那个W S A O V E R L A P P E D l构?br />l p c b Tr a n s f e r参数也是一个指针,对应一个D W O R DQ双字)变量Q负责接收一ơ重叠发送或接收操作实际传输的字节数。f Wa i t参数用于军_函数是否应该{待一ơ待冻I未决Q的重叠操作完成。若f Wa i t设ؓT R U EQ那么除非操作完成,否则函数不会q回Q若设ؓFA L S EQ而且操作仍然处于“待决”状态,那么W S A G e t O v e r l a p p e d R e s u l t函数会返回FA L S E|同时q回一个W S A _ I O _ I N C O M P L E T EQI / O操作未完成)错误。但我们目前的情况来说Q由于需要等候重叠操作的一个已传信事g完成Q所以该参数无论采用什么设|,都没有Q何效果?br />最后一个参数是l p d w F l a g sQ它对应于一个指针,指向一个D W O R DQ双字)Q负责接收结果标志(假如原先的重叠调用是用W S A R e c v或W S A R e c v F r o m函数发出的)?br />如W S A G e t O v e r l a p p e d R e s u l t函数调用成功Q返回值就是T R U E。这意味着我们的重叠I / O操作已成功完成,而且由l p c b Tr a n s f e r参数指向的值已q行了更新。若q回值是FA L S EQ那么可能是׃qCQ何一U原因造成的:
?重叠I / O操作仍处在“待决”状态?br />?重叠操作已经完成Q但含有错误?br />?重叠操作的完成状态不可判冻I因ؓ在提供给W S A G e t O v e r l a p p e d R e s u l t函数的一个或
多个参数中,存在着错误?/p>
]]>
Wi n s o c k提供了另一个有用的异步I / O模型。和W S A A s y n c S e l e c t模型cM的是Q它也允许应用程序在一个或多个套接字上Q接收以事g为基的网l事仉知。对于表8 - 3ȝ的、由W S A A s y n c S e l e c t模型采用的网l事件来_它们均可原封不动地移植到新模型。在用新模型开发的应用E序中,也能接收和处理所有那些事件。该模型最主要的差别在于网l事件会投递至一个事件对象句柄,而非投递至一个窗口例E?br />事g通知
事g通知模型要求我们的应用程序针Ҏ用的每一个套接字Q首先创Z个事件对象。创建方法是调用W S A C r e a t e E v e n t函数Q它的定义如下:
WSAEVENT WSACreateEvent(void);
W S A C r e a t e E v e n t函数的返回值很单,是一个创建好的事件对象句柄。事件对象句柄到手后Q接下来必须其与某个套接字兌在一P同时注册自己感兴的|络事gcdQ如? - 3所C。要做到q一点,Ҏ是调用W S A E v e n t S e l e c t函数Q对它的定义如下Q?/p>
int WSAEventSelect(
SOCKET s,
WSAEVENT hEventObject,
long lNetwordEvents
);
其中Q?s参数代表自己感兴的套接字。h E v e n t O b j e c t参数指定要与套接字关联在一L 事g对象—用W S A C r e a t e E v e n t取得的那一个。而最后一个参数l N e t w o r k E v e n t sQ则对应一个“位掩码”,用于指定应用E序感兴的各种|络事gcd的一个组合(如表8 - 3所C)。要惌知对q些事gcd的详l说明,请参考早先讨的WSAAsyncSelect I/O模型?br />为W S A E v e n t S e l e c t创徏的事件拥有两U工作状态,以及两种工作模式。其中,两种工作状态分别是“已传信”(s i g n a l e dQ和“未传信”(n o n s i g n a l e dQ。工作模式则包括“h工重䏀(manual resetQ和“自动重䏀(auto resetQ。W S A C r e a t e E v e n t最开始在一U未传信的工作状态中Qƈ用一Uh工重设模式,来创Z件句柄。随着|络事g触发了与一个套接字兌?br />一L事g对象Q工作状态便会从“未传信”{变成“已传信”。由于事件对象是在一Uh工重设模式中创徏的,所以在完成了一个I / Oh的处理之后,我们的应用程序需要负责将工作状态从已传信更改ؓ未传信。要做到q一点,可调用W S A R e s e t E v e n t函数Q对它的定义如下Q?/p>
BOOL WSAResetEvent(WSAEVENT hEvent);
该函数唯一的参C是一个事件句柄;Z调用是成功还是失败,会分别返回T R U E或FA L S E。应用程序完成了对一个事件对象的处理后,便应调用W S A C l o s e E v e n t函数Q释攄事g句柄使用的系l资源。对W S A C l o s e E v e n t函数的定义如下:
BOOL WSACloseEvent(WSAEVENT hEvent);
该函C要拿一个事件句柄作己唯一的参敎ͼq会在成功后q回T R U EQ失败后q回FA L S E?br />一个套接字同一个事件对象句柄关联在一起后Q应用程序便可开始I / O处理Q方法是{待|络事g触发事g对象句柄的工作状态。W S AWa i t F o r M u l t i p l e E v e n t s函数的设计宗旨便是用来等待一个或多个事g对象句柄Qƈ在事先指定的一个或所有句柄进入“已传信”状态后Q或在超q了一个规定的旉周期后,立即q回。下面是W S AWa i t F o r M u l t i p l e E v e n t s函数的定义:
DWORD WSAWaitForMultipleEvents(
DWORD cEvent,
const WSAEVENT FAR * lphEvents,
BOOL fWaitAll,
DWORD dwTimeout,
BOOL fAlertable
);
其中Q?c E v e n t s和l p h E v e n t s参数定义了由W S A E V E N T对象构成的一个数l。在q个数组中,c E v e n t s指定的是事g对象的数量,而l p h E v e n t s对应的是一个指针,用于直接引用该数l?br />要注意的是, W S AWa i t F o r M u l t i p l e E v e n t s只能支持由W S A _ M A X I M U M _ WA I T _ E V E N T S对象规定的一个最大|在此定义? 4个。因此,针对发出W S AWa i t F o r M u l t i p l e E v e n t s调用的每个线E,该I / O模型一ơ最多都只能支持6 4个套接字。假如想让这个模型同时管理不? 4个套
接字Q必d建额外的工作者线E,以便{待更多的事件对象。f Wa i t A l l 参数指定了W S AWa i t F o r M u l t i p l e E v e n t s如何{待在事件数l中的对象。若设ؓT R U EQ那么只有等l p h E v e n t s数组内包含的所有事件对象都已进入“已传信”状态,函数才会q回Q但若设为FA L S EQQ何一个事件对象进入“已传信”状态,函数׃q回。就后一U情冉|_q回值指Z到底是哪个事件对象造成了函数的q回。通常Q应用程序应该参数设ؓFA L S EQ?br />一ơ只Z个套接字事g提供服务。d w Ti m e o u t参数规定了W S AWa i t F o r M u l t i p l e E v e n t s最多可{待一个网l事件发生有多长旉Q以毫秒为单位,q是一“超时”设定。超q规定的旉Q函数就会立卌回,即由f Wa i t A l l参数规定的条件尚未满也如此。如时gؓ0Q函C指定的事g对象的状态,q立卌回。这样一来,应用E序实际便可实现对事件对
象的“轮询”。但考虑到它Ҏ能造成的媄响,q是应尽量避免将时D?。假如没有等待处理的事gQ?W S AWa i t F o r M u l t i p l e E v e n t s便会q回W S A _ WA I T _ T I M E O U T。如d w s Ti m e o u t设ؓW S A _ I N F I N I T EQ永q等待)Q那么只有在一个网l事件传信了一个事件对象后Q函数才
会返回。最后一个参数是f A l e r t a b l eQ在我们使用W S A E v e n t S e l e c t模型的时候,它是可以忽略的,且应设ؓFA L S E。该参数主要用于在重叠式I / O模型中,在完成例E的处理q程中用?br />本章后面q会Ҏ详述?/p>
若W S AWa i t F o r M u l t i p l e E v e n t s收到一个事件对象的|络事g通知Q便会返回一个|指出造成函数q回的事件对象。这样一来,我们的应用程序便可引用事件数l中已传信的事gQƈ索与那个事g对应的套接字Q判断到底是在哪个套接字上,发生了什么网l事件类型?br />对事件数l中的事件进行引用时Q应该用W S AWa i t F o r M u l t i p l e E v e n t s的返回|减去预定义值W S A _ WA I T _ E V E N T _ 0Q得到具体的引用|即烦引位|)。如下例所C:
Index = WSAWaitForMultipleEvents(...);
MyEvent = EventArray[Index - WSA_WAIT_EVENT_0];
知道了造成|络事g的套接字后,接下来可调用W S A E n u m N e t w o r k E v e n t s函数Q调查发生了什么类型的|络事g。该函数定义如下Q?/p>
int WSAEnumNetworkEvents(
SOCKET s,
WSAEVENT hEventObject,
LPWSANETWORKEVENTS lpNetworkEvents
);
s参数对应于造成了网l事件的套接字。h E v e n t O b j e c t参数则是可选的Q它指定了一个事件句柄,对应于打重讄那个事g对象。由于我们的事g对象处在一个“已传信”状态,所以可它传入Qo其自动成为“未传信”状态。如果不想用h E v e n t O b j e c t参数来重设事Ӟ那么可用W S A R e s e t E v e n t 函数Q?该函数早先已l讨了。最后一个参数是l p N e t w o r k E v e n t sQ代表一个指针,指向W S A N E T W O R K E V E N T Sl构Q用于接收套接字上发
生的|络事gcd以及可能出现的Q何错误代码。下面是W S A N E T W O R K E V E N T Sl构的定义:
typedef struct _WSANETWORKEVENTS
{
long lNetworkEvents;
int iErrorCode[FD_MAX_EVENTS];
}WSANETWORKEVENTS,FAR * LPWSANETWORKEVENTS;
l N e t w o r k E v e n t s参数指定了一个|对应于套接字上发生的所有网l事件类型(参见? - 3Q?br />注意一个事件进入传信状态时Q可能会同时发生多个|络事gcd。例如,一个繁?br />的服务器应用可能同时收到FD_READ和FD_WRITE通知?br />i E r r o r C o d e参数指定的是一个错误代码数l,同l N e t w o r k E v e n t s中的事g兌在一赗针Ҏ个网l事件类型,都存在着一个特D的事g索引Q名字与事gcd的名字类|只是要在事g名字后面d一个?_ B I T”后~字串卛_。例如,对F D _ R E A D事gcd来说Qi E r r o r C o d e数组的烦引标识符便是F D _ R E A D _ B I T。下qC码片断对此进行了阐释Q针对F D _ R E A D事gQ:
if(NetWorkEvents.lNetworkEvents & FD_READ)
{
if(NetWorkEvents.iErrorCode[FD_READ_BIT] != 0)
{
printf("FD_READ FAILED with error %d\n",NetWorkEvents.iErrorCode[FD_READ_BIT]);
}
}
完成了对W S A N E T W O R K E V E N T Sl构中的事g的处理之后,我们的应用程序应在所有可用的套接字上Ql等待更多的|络事g。在E序清单8 - 6中,我们阐释了如何用W S A E v e n t S e l e c tq种I / O模型Q来开发一个服务器应用Q同时对事g对象q行理。这个程序主要着g开发一个基本的服务器应用要涉及到的步骤Qo其同时负责一个或多个套接字的理?/p>
完成了对W S A N E T W O R K E V E N T Sl构中的事g的处理之后,我们的应用程序应在所有可用的套接字上Ql等待更多的|络事g。在E序清单8 - 6中,我们阐释了如何用W S A E v e n t S e l e c tq种I / O模型Q来开发一个服务器应用Q同时对事g对象q行理。这个程序主要着g开发一个基本的服务器应用要涉及到的步骤Qo其同时负责一个或多个套接字的理?br />E序清单8-6 采用WSAEventSelect I/O模型的示范服务器源代?/p>
Windows
支持两种cd的应用程序。一U是Z囑Ş用户界面Q?/span>
GUI
Q的应用E序Q另一U是Z控制台用L面(
CUI
Q的应用E序?/span>
(
两者间可以怺转化
,
没有明确的界?/span>
,
是说可以让
CUI
E序中可以有
Dialog
界面{?/span>
,
?/span>
GUI
界面中也可以?/span>
console
来输Z?/span>
)
对于一个应用程?span lang="EN-US" twffan="done">:
一
操作pȝ实际上先调用的是C / C + +q行期启动函数。该函数负责?span lang="EN-US" twffan="done">C / C + +q行期库q行初始化,q样Q就可以调用m a l l o c ?span lang="EN-US" twffan="done">f r e e 之类的函数。它q能够确保已l声明的M全局对象和静?span lang="EN-US" twffan="done">C + +对象能够在代码执行以前正地创徏。链接程序负责在它连接可执行文g旉择相应?span lang="EN-US" twffan="done">C / C + +q行期启动函数。如果设定了/ S U B S Y S T E M : W I N D O W S 链接E序开养I?么该链接E序期望扑ֈ一?span lang="EN-US" twffan="done">Wi n M a i n ?span lang="EN-US" twffan="done">w Wi n m a i n函数。如果这两个函数都不存在Q链接程序便q回一?span lang="EN-US" twffan="done">?/span>未{换的外部W号?/span>的错误消 息。否则,它可以分别选择Wi n M a i n C RT S t a r t u p 函数?span lang="EN-US" twffan="done">w Wi n M a i n C RT S t a r t u p 函数?span lang="EN-US" twffan="done">
启动函数的功能归U_下:
? 索指向新q程的完整命令行的指针?/span>
? 索指向新q程的环境变量的指针?/span>
? ?/font> C / C + + q行期的全局变量q行初始化。如果包含了 S t d L i b . h 文gQ代码就能访问这些变量。表 4 - 1 列出了这些变量?/span>
? ?/font> C q行期内存单元分配函敎ͼ m a l l o c ?/font> c a l l o c Q和其他低层输入 / 输出例程使用的内存栈q行初始化?/span>
?
为所有全局和静?/font>
C + +
cd象调用构造函数?/span>
?/font> 当所有这些初始化操作完成后, C / C + + 启动函数p用应用程序的q入点函数。如果编写了一?/font> w Wi n M a i n 函数Q它以下面的Ş式被调用 Q?/span>
GetStartupInfo(&StartupInfo); int nMainRetVal = wWinMain(GetMjduleHandle(NULL), NULL, pszCommandLineUnicode, (StartupInfo.dwFlags & STARTF_USESHOWWINDOW) ? StartupInfo.wShowWindow:SW_SHOWDEFAULT);
?/p>
当进入点函数q回Ӟ启动函数便调?/span>
C
q行期的
e x i t
函数Q将q回|
n M a i n R e t Va l
Q传递给它?/span>
E x i t
函数负责下面的操作:
?
调用?/span>
_onexit
函数的调用而注册的M函数?/span>
?
为所有全局的和静态的
C++
cd象调用析构函数?/span>
?
调用操作pȝ?/span>
ExitProcess
函数Q将
nMainRetVal
传递给它。这使得该操作系l能够撤消进Eƈ讄它的
e x i t
代码?/span>
附录
:
各种应用E序的进入点及对应的启动函数
应用E序cd |
q入?span lang="EN-US" twffan="done"> |
嵌入可执行文件的启动函数 |
需?span lang="EN-US" twffan="done">ANSI字符和字W串?span lang="EN-US" twffan="done">GUI应用E序 |
WinMain |
WinMainCRTStartup |
需?span lang="EN-US" twffan="done">Unicode字符和字W串?span lang="EN-US" twffan="done">GUI应用E序 |
wWinMainw |
WinMainCRTStartup |
需?span lang="EN-US" twffan="done">ANSI字符和字W串?span lang="EN-US" twffan="done">CUI应用E序 |
main |
mainCRTStartup |
需?span lang="EN-US" twffan="done">Unicode字符和字W串?span lang="EN-US" twffan="done">CUI应用E序 |
wmain |
wmainCRTStartup |
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case ... ... case ... ... } return DefWindowProc (hwnd, message, wParam, lParam) ; } |
#include "stdafx.h" #include Qwindows.hQ?BR> //一、消息处理函?BR>//参数:H口句柄Q消息,消息参数Q消息参?BR>LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { //处理感兴的消息 switch (message) { case WM_DESTROY: //当用户关闭窗口,H口销毁,E序需l束Q发退出消息,以退出消息@?BR> PostQuitMessage (0) ; return 0 ; } //其他消息交给ql提供的~省处理函数 return ::DefWindowProc (hwnd, message, wParam, lParam) ; } //二、应用程序主函数 //参数:实例句柄、前一个实例的句柄、命令行参数、窗口显C方?BR>int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { //1.注册H口c?BR> static TCHAR szAppName[] = TEXT ("HelloWin") ; //H口cdU?BR> //定制"H口c?l构 WNDCLASS wndclass ; wndclass.style = CS_HREDRAW | CS_VREDRAW ; wndclass.lpfnWndProc = WndProc ; //兌消息处理函数 wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInstance ; //实例句柄 wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; //图标 wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; //光标 wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH); //d wndclass.lpszMenuName = NULL ; wndclass.lpszClassName = szAppName; //cdU?BR> //注册 if (!ReGISterClass (&wndclass)) { MessageBox (NULL, TEXT ("RegisterClass Fail!"), szAppName, MB_ICONERROR) ; return 0 ; } //建立H口 HWND hwnd ; hwnd = CreateWindow (szAppName, //H口cdU?BR> TEXT ("The Hello Program"), //H口标题 WS_OVERLAPPEDWINDOW, //H口风格 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, //实例句柄 NULL); ShowWindow (hwnd, iCmdShow) ; UpdateWindow (hwnd) ; //消息循环 MSG msg ; while (GetMessage (&msg, NULL, 0, 0)) //从消息队列中取消? { TranslateMessage (&msg) ; //转换消息 DispatchMessage (&msg) ; //z֏消息 } return msg.wParam ; } |