(一)Windows API串口通信編程概述 Windows環(huán)境下的串口編程與DOS環(huán)境下的串口編程有很大不同,。Windows環(huán)境下的編程的最大特征之一就是設(shè)備無關(guān)性,它通過設(shè)備驅(qū)動程序?qū)?/span>Windows應(yīng)用程序同不同的外部設(shè)備隔離,。Windows封裝了Windows的通信機制,,這種方式稱為通信API,Windows程序可以利用Windows通信API進(jìn)行編程,,不用對硬件直接進(jìn)行操作,。這種體系被稱為Windows開放式服務(wù)體系(WOSA,Windows Open Services Architectures),。 早期的Windows3.x與Windows 9x/NT/2000的通信API有很大不同,在16位的串行通信程序中,,一般使用16位的Windows API通信函數(shù),。為使大家對串口通信有一全面的理解,下面簡單介紹一下16位的Windows API通信函數(shù): (1) 打開和關(guān)閉串口 OpenComm()打開串口資源,,并指定輸入,、輸出緩沖區(qū)的大小(以字節(jié)計),; CloseComm()關(guān)閉串口,; 例: int idComDev; idComdev=OpenComm(“COM1”,1024,,512),; CloseComm(idComDev); (2) 初始化串口 BuildCommDCB()、setCommState()填寫設(shè)備控制塊DCB,,然后對已打開的串口進(jìn)行參數(shù)配置,,例: DCB dcb; BuildCommDCB(〝COM1:2400,n,8,1〞,&dcb); SetCommState(&dcb); (3) 對串口進(jìn)行讀寫 ReadComm、WriteComm()對串口進(jìn)行讀寫操作,,即數(shù)據(jù)的接收和發(fā)送,。例: char *m_pReceive; int count; ReadComm(idComDev,m_pReceive,count);
Char wr[30]; int count2; WriteComm(idComDev,wr,count2); 通過對以上的描述我們可以看出,16位以下的串口通信程序最大的特點就在于串口等外部設(shè)備的操作有自己特有的API函數(shù),。 Windows 9x/NT/2000中的API一般都支持32位的操作,,因此又稱為Win32API。為了在上述系統(tǒng)中實現(xiàn)串行數(shù)據(jù)傳送,,可以使用Win32通信API,。Win32通信API基本上是一個串行端口API,不是很適合于局域網(wǎng)(LAN)通信,。雖然在線路上發(fā)送數(shù)據(jù)之前,,LAN通常將數(shù)據(jù)位串行化,這和窗口或調(diào)制解調(diào)器發(fā)送數(shù)據(jù)之前所作的工作一模一樣,,但局域網(wǎng)使用的線路的位數(shù)通常比串口少,,而且還使用與串口協(xié)議很少有類似之處的訪問、路由,、安全性和糾錯協(xié)議,。局域網(wǎng)通信所需要的協(xié)議層使得Win32通信API對于這些應(yīng)用來說很不理想。因此,,在網(wǎng)絡(luò)通信和連接方面,,TCP/IP協(xié)議要比Win32通信API更適合一些。 Windows操作系統(tǒng)是一個可搶占式的操作系統(tǒng),,所以Windows應(yīng)用程序常常有被別的程序搶占時間片的可能,因此Win32通信API也 不能用于實時通信。實時通信的質(zhì)量與時間密切相關(guān),。例如,數(shù)字化音頻數(shù)據(jù)是實時數(shù)據(jù),,因為話音的質(zhì)量依賴于播放它的速率。在錄制音頻時,,它就以某個速度被 數(shù)字化了,,該速度就是人們所熟知的采樣速率。聲音必須以相同的采樣率重放,,否則聽起來就會太慢或太快,。實際中的視頻播放,也不是實時播放,,那僅僅是存放在 緩沖中的那部分?jǐn)?shù)據(jù),。因此,不需要許多協(xié)議層的交互式,、非實時的通信可以采用Win32通信API來實現(xiàn),。Win32通信API把串口操作(以及并口等)和文件操作統(tǒng)一起來了,使用類似的操作來實現(xiàn),。
(二) Windows串口通信相關(guān)API函數(shù) “工欲善其事,,必先利其器”,這一節(jié)將從使用的角度出發(fā),,對和串口通信相關(guān)的32位的Windows API函數(shù)進(jìn)行介紹,力圖使你們對其有個全面,、準(zhǔn)確的認(rèn)識,。
2.1 打開和關(guān)閉串口 1. 打開串口 在32位的Windows系統(tǒng)中,串口和其它通信設(shè)備是作為文件處理的,。串口的打開,、關(guān)閉、讀取和寫入所用的函數(shù)與操作文件的函數(shù)完全一致,。 通信會話以調(diào)用CreateFile()開始,。CreateFile()為讀訪問、寫訪問或讀寫訪問“打開”串口,。按照Windows的通常做法,,CreateFile()返回一個句柄,隨后在打開的端口的操作中使用CreateFile()函數(shù)非常復(fù)雜,,復(fù)雜性的原因之一是它是通用的,。可以使用CreateFile打開已存在的文件,,創(chuàng)建新文件和打開根本就不是文件的設(shè)備,,例如串口,、并口和調(diào)制解調(diào)器。CreateFile()函數(shù)聲明如下: HANDLE CreateFile( LPCTSTR lpszName, DWORD fdwAccess, DWORD fdwShareMode, LPSECURITY_ATTRIBUTES lpsa, DWORD fdwCreate, DWORD fdwAttrsAndFlags, HANDLE hTemplateFile ) CreateFile函數(shù)中的參數(shù)解釋如下: ·lpszName:指定要打開的串口邏輯名,,用字符串表示,,如“COM1”和“COM2”分別表示串口1和串口2。 ·fdwAccess:用來指定串口訪問的類型,。與文件一樣,,串口也是可以被打開以供讀取、寫入或者兩者兼有,。 GENERIC_READ位讀取訪問打開端口,,GENERIC_READ位寫訪問打開端口。這兩個常數(shù)定義如下: const GENERIC_READ = 0x80000000h; const GENERIC_WRITE = 0x40000000h; 用戶可以用邏輯操作將這兩個標(biāo)識符連接起來,,為讀/寫訪問權(quán)限打開端口,。因為大部分串口通信都是雙向的,因此常常在設(shè)置中將兩個標(biāo)識符連接起來使用,。如: fdwAccess = GENERIC_READ | GENERIC_WRITE; ·fdwShareMode:指定該端口的共享屬性,。該參數(shù)是為那些由許多應(yīng)用程序共享的文件提供的。對于不能共享的串口,,它必須設(shè)置為0,。這就是文件與通信設(shè)備之間的主要差異之一。如果在當(dāng)前的應(yīng)用程序調(diào)用CreateFile()時,,另一個應(yīng)用程序已經(jīng)打開了串口,,該函數(shù)就會返回錯誤代碼,原因是兩個應(yīng)用程序不能共享一個端口,。然而,,同一個應(yīng)用程序的多個線程可以共享由CreateFile()返回的端口句柄,并且根據(jù)安全性屬性設(shè)置,,該句柄可以被打開端口的應(yīng)用程序的子程序所繼承,。 ·Ipsa:引用安全性屬性結(jié)構(gòu)(SECURITY_ARRTIBUTES),該結(jié)構(gòu)定義了一些屬性,,例如通信句柄如何被打開端口的應(yīng)用程序的子程序所繼承,。將該參數(shù)設(shè)置為NULL將為該端口分配缺省的安全性屬性。子應(yīng)用程序所繼承的缺省屬性是該端口不能被繼承的,。 安全屬性結(jié)構(gòu)SECURITY_ARRTIBUTES結(jié)構(gòu)聲明如下: typedef struct_SECURITY_ARRTIBUTE { DWORD nLength; LPVOID lpSecurityDescriptor; BOOL bInheritHandle; } SECURITY_ARRTIBUTE; SECURITY_ARRTIBUTES結(jié)構(gòu)成員nLength指明該結(jié)構(gòu)的長度,,lpSecurityDescriptor指向一個安全描述字符,bInheritHandle表明句柄是否能被繼承,。 ·fdwCreate:指定如果CreateFile()正在被已有的文件調(diào)用時應(yīng)采取的動作,。因為串口總是存在,fdwCreate必須設(shè)置成OPEN_EXISTING,。該標(biāo)志告訴Windows不用企圖創(chuàng)建新端口,,而是打開已經(jīng)存在的端口,。OPEN_EXISTING常數(shù)定義為: const OPEN_EXISTING = 3; ·fdwAttrsAndFlags:描述了端口的各種屬性。對于文件來說,,有可能具有很多屬性,,但對于串口,唯一有意義的設(shè)置是FILE_FLAG_OVERLAPPED,。當(dāng)創(chuàng)建時指定該設(shè)置,,端口I/O可以在后臺進(jìn)行(后臺I/O也叫異步I/O)。FILE_FLAG_OVERLAPPED常數(shù)定義如下: const FILE_FLAG_OVERLAPPED = 0x40000000h ·hTemplateFile:指向模板文件的句柄,,當(dāng)端口處于打開狀態(tài)時,,不使用該參數(shù),因而必須置成0,。 調(diào)用CreateFile()函數(shù)打開COM1串口操作的例子如下所示: HANDLE hCom; DWORD dwError;
hCom=CreateFile(“COM1”, // 文件名 GENERIC_READ | GENERIC_WRITE, // 允許讀和寫 0, // 獨占方式 NULL, OPEN_EXISTING, // 打開而不是創(chuàng)建 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, // 重疊方式 NULL ); if(hCom = = INVALID_HANDLE_VALUE) { dwError=GetLastError(); // 處理錯誤 } 一旦端口處于打開狀態(tài),,就可以分配一個發(fā)送緩沖區(qū)和接收緩沖區(qū),并且通過調(diào)用SetupComm()實現(xiàn)其它初始化工作,。也可以不調(diào)用SetupComm()函數(shù),,Windows系統(tǒng)也會分配缺省的發(fā)送和接收緩沖區(qū),并且初始化端口,。但為了保證緩沖區(qū)的大小與實際需要的一致,,最好還是調(diào)用該函數(shù)。SetupComm()函數(shù)聲明如下: BOOL SetupComm( HANDLE hFile, // 通信設(shè)備句柄 DWORD dwInQueue, // 輸入緩沖區(qū)大小 DWORD dwOutQueue // 輸出緩沖區(qū)大小 ); SetupComm()函數(shù)中各項含義說明如下: ·hFile: 由GreatFile()返回的指向已打開端口的句柄,。 ·dwInQueue和dwOutQueue: 接收緩沖區(qū)的大小和發(fā)送緩沖區(qū)的大小,。這兩個定義并非是實際的緩沖區(qū)的大小,指定的大小僅僅是“推薦的”大小,,而Windows可以隨意分配任意大小的緩沖區(qū),。Windows設(shè)備驅(qū)動程序可以獲得這兩個數(shù)據(jù),并不直接分配大小,,而使用來優(yōu)化性能和避免緩沖區(qū)超限。 注意:當(dāng)使用CreateFile()函數(shù)打開串口時:為實現(xiàn)調(diào)制解調(diào)器的排他性訪問,,共享標(biāo)識必須設(shè)為零,;創(chuàng)建標(biāo)識必須設(shè)為OPEN_EXISTING;模板句柄必須置為空,。 2. 關(guān)閉串口 關(guān)閉串口比打開串口簡單得多,,只需要調(diào)用CloseHandle()函數(shù)關(guān)閉由CreateHandle()函數(shù)返回得句柄即可。 CloseHandle函數(shù)聲明如下: BOOL CloseHandle( HANDLE hObject // 需關(guān)閉的設(shè)備句柄 ); 使用串口時一般要關(guān)閉它,,如果忘記關(guān)閉串口,,串口就會始終處于打開狀態(tài),其它應(yīng)用程序就不能打開并使用串口了,。
2.2 串口配置和串口屬性 Windows 9x/NT/2000中配置串口提供了比Windows的早期版本更為強大的功能,,當(dāng)然相應(yīng)也更加復(fù)雜,。CreateFile函數(shù)打開串口后,系統(tǒng)將根據(jù)上次打開串口時設(shè)置的值來初始化串口,,可以集成上次打開操作后的數(shù)值,,包括設(shè)備控制塊(DCB)和超時控制結(jié)構(gòu)(COMMTIMEOUTS)。如果是首次打開串口,,Windows操作系統(tǒng)就會使用缺省的配置,。 1. 串口配置 Windows 9x/NT/2000使用GetCommState()函數(shù)獲取串口的當(dāng)前配置,使用SetCommState()重新分配串口資源的各個參數(shù),。 GetCommState()函數(shù)聲明如下: BOOL GetCommState( HANDLE hFile, // 通信設(shè)備句柄 LPDCB lpDCB // 指向device-control block structure的指針 ); 其中的參數(shù)說明如下: ·hFile:由CreateFile()函數(shù)返回的指向已打開串口的句柄,。 ·lpDCB:一個非常重要的結(jié)構(gòu)—設(shè)備控制塊DCB ( Device Control Block )。 DCB結(jié)構(gòu)的主要參數(shù)說明如下: ·DCBLength: 一字節(jié)為單位指定的DCB結(jié)構(gòu)的大小,。 ·Baudrate: 用于指定串口設(shè)備通信的數(shù)據(jù)傳輸速率,,它可以是實際的數(shù)據(jù)傳輸速率數(shù)值,也可以是下列數(shù)據(jù)之一:CBR_110, CBR_19200, CBR_300, CBR_38400, CBR_600, CBR_56000, CBR_1200, CBR_57600, CBR_2400, CBR_115200, CBR_4800, CBR_12800, CBR_9600, CBR_25600, CBR_14400,。 ·fBinary: 指定是否允許二進(jìn)制,。Win32API不支持非二進(jìn)制傳輸,因此這個參數(shù)必須設(shè)置為TRUE,,如果設(shè)置為FALSE則不能正常工作,。 ·fParity: 指定是否允許奇偶校驗,如果這個參數(shù)設(shè)置為TRUE,,則執(zhí)行奇偶校驗并報告錯誤信息,。 ·fOutxCtsFlow: 指定CTS是否用于檢測發(fā)送流控制。當(dāng)該成員為TRUE,,而CTS為OFF時,,發(fā)送將被掛起,直到CTS置ON,。 ·fOutxDsrFlow: 指定DSR是否用于檢測發(fā)送流控制,,當(dāng)該成員為TRUE,而DSR為OFF時,,發(fā)送將被掛起,,直到DSR置ON。 ·fDtrControl: 指定DTR流量控制,,可以是表1中的任一值,。 表1 DTR流量控制
·fDsrSensitivity: 指定通信驅(qū)動程序?qū)?/span>DTR信號線是否敏感,如果該位置設(shè)為TRUE時,,DSR信號為OFF,,接收的任何字節(jié)將被忽略。 ·fTXContinueOnXoff: 指定當(dāng)接收緩沖區(qū)已滿,,并且驅(qū)動程序已經(jīng)發(fā)送出XoffChar字符時發(fā)送是否停止,。當(dāng)該成員為TRUE時,在接收緩沖區(qū)內(nèi)接收到了緩沖區(qū)已滿的字節(jié)XoffLim,,并且驅(qū)動程序已經(jīng)發(fā)送出XoffChar字符終止接收字節(jié)之后,,發(fā)送繼續(xù)進(jìn)行。該成員為FALSE時,,接收緩沖區(qū)接收到代表緩沖區(qū)已空的字節(jié)XonLim,,并且驅(qū)動程序已經(jīng)發(fā)送出恢復(fù)發(fā)送的XonChar字符后,發(fā)送可以繼續(xù)進(jìn)行,。 ·fOutX: 該成員為TRUE時,,接收到XoffChar之后停止發(fā)送,接收到XonChar之后發(fā)送將重新開始,。 ·fInX: 該成員為TRUE時,,接收緩沖區(qū)內(nèi)接收到代表緩沖區(qū)滿的字節(jié)XoffLim之后,,XoffChar發(fā)送出去,,接收緩沖區(qū)接收到代表緩沖區(qū)已空的字節(jié)XonLim之后,XonChar發(fā)送出去,。 ·fErrorChar: 當(dāng)該成員為TRUE,,并且fParity為TRUE時,就會用ErrorChar成員指定的字符來代替奇偶校驗錯誤的接收字符,。 ·fNull: 指明是否丟棄接收到的NULL( ASCII 0 )字符,該成員為TRUE時,,接收時去掉空(零值)字節(jié),;反之則不丟棄,。 表2 RTS 流量控制
·fRtsControl: 指定 RTS 流量控制,可以取表2中的值,。0值和DTR_CONTROL_HANDSHAKE等價。 ·fAbortOnError: 如果發(fā)送錯誤,,指定是否可以終止讀,、寫操作。如果該位為TRUE,,當(dāng)發(fā)生錯誤時,,驅(qū)動程序以出錯狀態(tài)終止所有的讀寫操作。只有當(dāng)應(yīng)用程序調(diào)用ClearCommError()函數(shù)處理后,,串口才能接收隨后的通信操作,。 ·fDummy2: 保留的位,沒有使用,。 ·wReserved:沒有使用,,必須為零。 ·XonLim: 指定在XOFF字符發(fā)送之前接收到緩沖區(qū)中可允許的最小字節(jié)數(shù),。 ·XoffLim: 指定在XOFF字符發(fā)送之前緩沖區(qū)中可允許的最小可用字節(jié)數(shù) ·ByteSize: 指定端口當(dāng)前使用的數(shù)據(jù)位數(shù),。 ·Parity: 指定端口當(dāng)前使用的奇偶校驗方法。它的可能值如表3所示,。 ·StopBits: 指定串口當(dāng)前使用的停止位數(shù),,可能值如表4所示。 表3 奇偶校驗方法
表4 停止位數(shù)描述
·XonChar: 指明發(fā)送和接收的XON字符值,,它表明允許繼續(xù)傳輸,。 ·XoffChar: 指明發(fā)送和接收的XOFF字符值,它表示暫停數(shù)據(jù)傳輸,。 ·ErrorChar: 本字符用來代替接收到的奇偶校驗發(fā)生錯誤的字符,。 ·EofChar: 用來表示數(shù)據(jù)的結(jié)束。 ·EvtChar: 事件字符。當(dāng)接收到此字符的時候,,會產(chǎn)生一個事件,。 ·wReserved1: 保留的位,沒有使用,。 如果GetCommState()函數(shù)調(diào)用成功,,則返回值不為零。若函數(shù)調(diào)用失敗,,則返回值為零,,如果想得到進(jìn)一步的錯誤信息,可以調(diào)用GetLastError()函數(shù)來獲取,。 GetLastError()函數(shù)也是Win32API函數(shù),,它的聲明如下: DWORD GetLastError(VOID); 如果應(yīng)用程序只需要修改一部分配置的時候,可以通過GetCommState()函數(shù)獲得當(dāng)前的DCB結(jié)構(gòu),,然后更改DCB結(jié)構(gòu)中的參數(shù),,調(diào)用SetCommState()函數(shù)配置修改過的DCB來配置端口。SetCommState()函數(shù)聲明如下: BOOL SetCommState ( HANDLE hFile, // 已打開的串口的句柄 LPDCB lpDCB // 指向DCB結(jié)構(gòu)的指針 ); SetCommState()函數(shù)的第一參數(shù)hFile是由CreateFile()函數(shù)返回的已打開的串口的句柄,,第二個參數(shù)也是指向DCB結(jié)構(gòu)的,。如果函數(shù)調(diào)用成功,,則返回值不為零,;若函數(shù)調(diào)用失敗,則返回值為零,。出錯時可以調(diào)用GetLastError()函數(shù)獲得進(jìn)一步的出錯信息,。SetCommState()函數(shù)調(diào)用的DCB結(jié)構(gòu)中的XonChar等價于XoffChar成員,則SetCommState()函數(shù)會調(diào)用失敗,。 DCB最經(jīng)常改變的參數(shù)是數(shù)據(jù)傳輸速率,、奇偶校驗的方法以及數(shù)據(jù)位和停止位數(shù)。Windows為改變這些設(shè)置提供了BuildCommDCB函數(shù),,函數(shù)聲明如下: BOOL BuildCommDCB( LPCTSTR lpDef, // 設(shè)置的字符串 LPDCB lpDCB // 指向DCB結(jié)構(gòu)的指針 ); BuildCommDCB()參數(shù)包含新設(shè)置的字符串和一個DCB結(jié)構(gòu)的參數(shù),,該設(shè)置將提供給DCB結(jié)構(gòu),。新設(shè)置的字符串與DOS系統(tǒng)或者Windows NT/2000系統(tǒng)中的Mode命令格式相同。如: baud=1200 parity=N data=8 stop=1 這條語句將數(shù)據(jù)傳輸速率設(shè)置為1200bits/s,,關(guān)閉奇偶校驗,,數(shù)據(jù)位數(shù)設(shè)為8,停止位數(shù)設(shè)為1,。與在DOS或Windows NT/2000系統(tǒng)中一樣,,該字符串不包括串口的名稱,實際上這個函數(shù)并不改變端口的設(shè)置,,因此沒有必要標(biāo)識該串口,,當(dāng)然這個串口必須是有效的串口,。新的設(shè)置只是簡單地拷貝到已提供好的DCB結(jié)構(gòu)中,,要使新設(shè)置生效,還必須調(diào)用SetCommState()函數(shù),。BuildCommDCB()支持老的和新的各種版本的Mode命令,,缺省情況下,BuildCommDCB()函數(shù)禁止XON/XOFF和硬件流的控制,。如果使用硬件流控制,,則必須設(shè)置DCB結(jié)構(gòu)的各個成員的值,。如果這個函數(shù)調(diào)用成功,,則返回值不為零。如果想得到進(jìn)一步的錯誤信息,,可以調(diào)用GetLastError()函數(shù)來獲取,。 2. 緩沖區(qū)控制 Win32通信API除了提供SetupComm()函數(shù)實現(xiàn)初始化的緩沖區(qū)控制外,還提供了PurgeComm()函數(shù)和FlushFileBuffers()函數(shù)來進(jìn)行緩沖區(qū)操作,。 PurgeComm()函數(shù)的聲明如下: BOOL PurgeComm( HANDLE hFile, // 返回的句柄 DWORD dwFlags // 執(zhí)行的動作 ); 參數(shù)hFile指向由CreateFile函數(shù)返回的句柄,,dwFlags表示執(zhí)行的動作,這個參數(shù)可以是表表5中的任一個,。參數(shù)hFile指向由CreateFile函數(shù)返回的句柄,,可以調(diào)用GetLastError()函數(shù)獲得進(jìn)一步的錯誤信息。 表5 停止位數(shù)和奇偶校驗位
由上面的敘述可以看出,,PurgeComm()函數(shù)可以在讀寫操作的同時,清空緩沖區(qū),。當(dāng)應(yīng)用程序在讀寫操作時調(diào)用PurgeComm()函數(shù),,不能保證緩沖區(qū)內(nèi)的所有字符都被發(fā)送。如果要保證緩沖區(qū)的所有字符都被發(fā)送,應(yīng)該調(diào)用FlushFileBuffer()函數(shù),。該函數(shù)只受流量控制的支配,,不受超時控制的支配,它在所有的寫操作完成后才返回,。 FlushFileBuffers()的函數(shù)聲明如下: BOOL FlushFileBuffers( HANDLE hFile // 函數(shù)打開的句柄 ); 參數(shù)hFile指向由CreateFile函數(shù)打開的句柄,,如果該函數(shù)調(diào)用成功,則返回值不為零,;若函數(shù)調(diào)用失敗,,則返回值為零。出錯時可以調(diào)用GetLastError()函數(shù)獲得進(jìn)一步的出錯信息,。
2.3 讀寫串口 利用Win32通信API讀寫串口時,,既可以同步執(zhí)行,也可以重疊(異步)執(zhí)行,。在同步執(zhí)行時,,函數(shù)直到操作完成后才返回。這意味著在同步執(zhí)行時線程會被阻塞,,從而導(dǎo)致效率降低,。在重疊執(zhí)行時,即使操作還未完成,,調(diào)用的函數(shù)也會立即返回,。費時的I/O操作在后臺進(jìn)行,這樣線程就可以做其它工作,。例如,,線程可以在不同的句柄上同時執(zhí)行I/O操作,,甚至可以在同一句柄上同時進(jìn)行讀寫操作,。“重疊”一詞的含義就在于此,。 1. 讀串口操作 程序可以使用Win32API ReadFile()函數(shù)或者ReadFileEx()函數(shù)從串口中讀取數(shù)據(jù),。ReadFile()函數(shù)對同步或異步操作都支持,而ReadFileEx()只支持異步操作,。這兩個函數(shù)都受到函數(shù)是否異步操作,、超時操作等有關(guān)參數(shù)的影響和限定。 ReadFile()函數(shù)聲明如下: BOOL ReadFile( HANDLE hFile, // 指向標(biāo)識的句柄 LPVOID lpBuffer, // 指向一個緩沖區(qū) DWORD nNumberOfBytesToRead, // 讀取的字節(jié)數(shù) LPDWORD lpNumberOfBytesRead, // 指向調(diào)用該函數(shù)讀出的字節(jié)數(shù) LPOVERLAPPED lpOverlapped // 一個OVERLAPPED的結(jié)構(gòu) ); 其中主要參數(shù)介紹如下: ·hFile:指向標(biāo)識的句柄,。對串口來說,,就是由CreateFile函數(shù)返回的句柄。該句柄必須擁有GENERIC_READ的權(quán)限,。 ·lpBuffer:指向一個緩沖區(qū),,該緩沖區(qū)主要用來存放從串口設(shè)備中讀取的數(shù)據(jù)。 ·nNumberOfBytesToRead:指定要從串口設(shè)備讀取的字節(jié)數(shù)。 ·lpNumberOfBytesRead:指向調(diào)用該函數(shù)讀出的字節(jié)數(shù),。ReadFile()在讀操作前,,首先將其設(shè)置為0。Windows NT/2000中當(dāng)lpOverlapped沒有設(shè)置時,,lpNumberOfBytesRead必須設(shè)置,。當(dāng)lpOverlapped設(shè)置時,lpNumberOfBytesRead可以不設(shè)置,。這是可以調(diào)用GetOverlappedResult()函數(shù)獲取實際的讀取數(shù)值,。Windows 9x中這個參數(shù)一定要設(shè)置。 ·lpOverlapped:是一個OVERLAPPED的結(jié)構(gòu),,該結(jié)構(gòu)將在后面介紹,。如果hFile以FILE_FLAG_OVERLAPPED方式常見,則需要此結(jié)構(gòu),;否則,,不需要此結(jié)構(gòu)。 需要注意的是如果該函數(shù)因為超時而返回,,那么返回值是TRUE,。參數(shù)lpOverlapped 在操作時應(yīng)該指向一個OVERLAPPED的結(jié)構(gòu),如果該參數(shù)為NULL ,,那么函數(shù)將進(jìn)行同步操作,,而不管句柄是否是由 FILE_FLAG_OVERLAPPED 標(biāo)志建立的。當(dāng)ReadFile 返回FALSE時,,不一定就是操作失敗,,線程應(yīng)該調(diào)用GetLastError函數(shù)分析返回的結(jié)果。例如,,在重疊操作時如果操作還未完成函數(shù)返回,,那么函數(shù)就返回FALSE,而且GetLastError函數(shù)返回ERROR_IO_PENDING,。 2. 寫串口操作 可以使用Win32API函數(shù)WriteFile() 或者WriteFileEx()向串口中寫數(shù)據(jù),。WriteFile()函數(shù)對同步或異步操作都支持,而WriteFileEx()只支持異步操作,。這兩個函數(shù)都受到函數(shù)是否異步操作,、超時操作等有關(guān)參數(shù)的影響和限定。 WriteFile()函數(shù)聲明如下: BOOL WriteFile( HANDLE hFile, // 指向標(biāo)識的句柄 LPCVOID lpBuffer, // 指向一個緩沖區(qū) DWORD nNumberOfBytesToWrite, // 指定要向串口設(shè)備寫入的字節(jié)數(shù) LPDWORD lpNumberOfBytesWritten, // 指向調(diào)用該函數(shù)已寫入的字節(jié)數(shù) LPOVERLAPPED lpOverlapped // 一個OVERLAPPED的結(jié)構(gòu) ); 其中主要參數(shù)介紹如下: ·hFile:指向標(biāo)識的句柄,。對串口來說,,就是由CreateFile函數(shù)返回的句柄。該句柄必須擁有GENERIC_WRITE的權(quán)限,。 ·lpBuffer:指向一個緩沖區(qū),,該緩沖區(qū)主要用來存放待寫入串口設(shè)備的數(shù)據(jù),。 ·nNumberOfBytesToWrite:指定要向串口設(shè)備寫入的字節(jié)數(shù)。 ·lpNumberOfBytesWritten:指向調(diào)用該函數(shù)已寫入的字節(jié)數(shù),。WriteFile()在寫操作前,,首先將其設(shè)置為0。Windows NT/2000中當(dāng)lpOverlapped沒有設(shè)置時,,lpNumberOfBytesWritten必須設(shè)置,。當(dāng)lpOverlapped設(shè)置時,,lpNumberOfBytesWritten可以不設(shè)置。這是可以調(diào)用GetOverlappedResult()函數(shù)獲取實際的讀取數(shù)值。Windows 9x中這個參數(shù)一定要設(shè)置,。 ·lpOverlapped:是一個OVERLAPPED的結(jié)構(gòu),,該結(jié)構(gòu)將在后面介紹,。如果hFile以FILE_FLAG_OVERLAPPED方式常見,,則需要此結(jié)構(gòu);否則,,不需要此結(jié)構(gòu),。 如果函數(shù)調(diào)用成功,則返回值不為零,;若函數(shù)調(diào)用失敗,,則返回值為零。調(diào)用GetLastError()函數(shù)可以獲得進(jìn)一步的出錯信息,。 3. 異步I/O操作 異步(重疊)I/O操作是指應(yīng)用程序可以在后臺讀或者寫數(shù)據(jù),,而在前臺做其它事情,例如,,用程序可以在開始時對10000個數(shù)據(jù)進(jìn)行讀或?qū)?/span>操作,,然后返回執(zhí)行其它的操作;在讀寫完成后,,Windows就會產(chǎn)生一個信號,,應(yīng)用程序得到這個信號,便可以進(jìn)行其它的讀寫操作,。 要使用OVERLAPPED的結(jié)構(gòu),,CreateFile()函數(shù)的dwFlagsAndAttributes參數(shù)必須設(shè)為FILE_FLAG_OVERLAPPED標(biāo)識,,讀寫串口函數(shù)必須指定OVERLAPPED結(jié)構(gòu),。異步I/O操作在Windows中使用廣泛。 OVERLAPPED結(jié)構(gòu)類型聲明如下: typedef struct_OVERLAPPED { // 0 DWORD Internal; DWORD InteralHigh; DWORD Offset; DWORD OffsetHigh; HANDLE hEvent; } OVERLAPPED; 其中主要參數(shù)如下: ·Internal:操作系統(tǒng)保留,,指出一個和系統(tǒng)相關(guān)的狀態(tài),。當(dāng)GetOverlappedResult()函數(shù)返回時,如果將擴展信息設(shè)置為 ERROR_IO_PENDING,,該參數(shù)有效,。 ·InteralHigh:操作系統(tǒng)保留,,指出發(fā)送或接收的數(shù)據(jù)長度,當(dāng)GetOverlappedResult()函數(shù)返回值不為0時,,該參數(shù)有效,。 ·Offset和OffsetHigh:指明文件傳送的開始位置和字節(jié)偏移量的高位字。當(dāng)進(jìn)行端口操作時,,這兩個參數(shù)被忽略,。 ·hEvent:指定一個I/O操作完成后觸發(fā)的事件(信號)。在調(diào)用讀寫函數(shù)進(jìn)行I/O操作之前,,必須設(shè)置該參數(shù),。 在設(shè)置了異步I/O操作后,I/O操作和函數(shù)返回有以下兩種情況: 1 函數(shù)返回時I/O操作已經(jīng)完成:此時結(jié)果好像是同步執(zhí)行的,,但實際上這是異步執(zhí)行的結(jié)果,。 2 函數(shù)返回時I/O操作還沒完成:此時一方面,函數(shù)返回值為零,,并且GetLastError()函數(shù)返回ERROR_IO_PENDING,;另一方面,系統(tǒng)把OVERLAPPED中的信號事件設(shè)為無信號狀態(tài),。當(dāng)I/O操作完成時,,系統(tǒng)要把它設(shè)置為信號狀態(tài)。 異步I/O操作可以由GetOverlappedResult()函數(shù)來獲取結(jié)果,,也可以使用Windows信號函數(shù)來處理,。GetOverlappedResult()函數(shù)可聲明為: BOOL GetOverlappedResult( HANDLE hFile, LPOVERLAPPED lpOverlapped, LPDWORD lpNumberOfBytesTransferred, BOOL bWait ); 其中主要參數(shù)介紹如下: ·hFile:標(biāo)識通信句柄,它應(yīng)該和開始調(diào)用重疊結(jié)構(gòu)的ReadFile,、WriteFile,、WaitCommEvent函數(shù)的參數(shù)一致。 ·lpOverlapped:在啟動異步操作時指定的OVERLAPPED結(jié)構(gòu),。 ·lpNumberOfBytesTransferred:指向一個長整型變量,,該變量接收有一個讀或?qū)?/span>操作實際傳遞的字節(jié)數(shù)。 ·bWait:指定函數(shù)是否等待掛起的異步操作完成,。如果該參數(shù)設(shè)為1,,則該函數(shù)知道操作完成后才返回。如果該參數(shù)被設(shè)為0,,同時處于被掛起狀態(tài),,則該函數(shù)返回為0,并且GetLastError函數(shù)返回ERROR_IO_INCOMPLETE,。 如果該函數(shù)調(diào)用成功,,則返回值不為零;若函數(shù)調(diào)用失敗,,則返回值為零,。調(diào)用GetLastError()函數(shù)可以獲得進(jìn)一步的出錯信息,。 Windows也使用等待函數(shù)來檢查事件對象的當(dāng)前狀態(tài)或等待Windows狀態(tài)信號,在WaitForSingleObject()函數(shù),, WaitForSingleObjectEx()函數(shù),,以及WaitForMultipleObject() ,WaitForMultipleObjectsEx() 函數(shù)中指定OVERLAPPED結(jié)構(gòu)中的 hEvent,,即可獲取函數(shù)返回事件,。 4. 超時設(shè)置 Windows 9x/NT/2000中讀寫串口引入了超時結(jié)構(gòu)。超時結(jié)構(gòu)直接影響讀和寫的操作行為,。當(dāng)事先設(shè)定的超時間隔消逝時,,ReadFile() 、ReadFileEx(),、 WriteFile()和 WriteFileEx()操作仍未結(jié)束,,那么超時設(shè)置將無條件結(jié)束讀寫操作,而不管是否已讀出或已寫入指定數(shù)量的字符,。 在讀或?qū)懖僮髌陂g發(fā)生的超時將不按錯誤處理,,即讀或寫操作返回指定成功的值。對于同步讀或?qū)?/span>操作,,實際傳輸?shù)淖止?jié)數(shù)由ReadFile()和Write()函數(shù)報告,。對于異步操作,則有OVERLAPPED結(jié)構(gòu)來獲取,。 超時結(jié)構(gòu)定義如下: typedef struct_COMMTIMEOUTS { DWORD ReadIntervalTimeout; DWORD ReadTotalTimeoutMultiplier; DWORD ReadTotalTimeoutConstant; DWORD WriteTotalTimeoutMultiplier; DWORD WriteTotalTimeoutConstant; } COMMTIMEOUTS,*LPCOMMTIMEOUTS; 其中主要參數(shù)如下: ·ReadIntervalTimeout:以ms為單位指定通信線路上兩個字符到達(dá)之間的最大時間間隔,。在ReadFile()操作期間,從接收到第一個字符時開始計時,。如果任意兩個字符到達(dá)之間的時間間隔超過這個最大值,,則ReadFile()操作完成,并返回緩沖數(shù)據(jù),。如果被置為0,,則表示不使用間隔超時。 ·ReadTotalTimeoutMultiplier:以ms為單位指定一個系數(shù),,該系數(shù)用來計算讀操作的總超時時間,。 ·ReadTotalTimeoutConstant:以ms為單位指定一個常數(shù),該常數(shù)也用來計算讀操作的總超時時間,。 ·WriteTotalTimeoutMultiplier:以ms為單位指定一個系數(shù),,該系數(shù)用來計算寫操作的總超時時間。 ·WriteTotalTimeoutConstant:以ms為單位指定一個常數(shù),,該常數(shù)也用來計算寫操作的總超時時間,。 超時有兩種類型。第一種類型叫區(qū)間超時(interval timeout),,它僅適應(yīng)于從端口讀取數(shù)據(jù),。它指定在讀取兩個字符之間要經(jīng)歷多長時間。接收一個字符時,,Windows就啟動一個內(nèi)部計時器,。在下一個字符到達(dá)之前,如果定時器超過了區(qū)間超時設(shè)定時間,,讀函數(shù)就會放棄,。第二種類型的超時叫做總超時( total timeout),它適于讀和寫端口,。當(dāng)讀或?qū)?/span>特定字節(jié)數(shù)需要的總時間超過某一閾值時,,該超時即被觸發(fā)。 Windows使用下面的式子計算總超時時間: ReadTotalTimeout=( ReadTotalTimeoutMultiplier*bytes_to_read )+ ReadTotalTimeoutConstant; WriteTotalTimeout=( WriteTotalTimeoutMultiplier*bytes_to_write )+ WriteTotalTimeoutConstant; 該方程使總超時時間成為靈活的工具,??偝瑫r時間不是固定值,而是根據(jù)讀或?qū)?/span>的字節(jié)數(shù)而“漂浮不定”,。應(yīng)用程序通過設(shè)置系數(shù)為0而只是用常數(shù),,和通過設(shè)置常數(shù)為0而只使用于系數(shù)。如果系數(shù)和常數(shù)都為0,,則沒有總超時時間,。 因此每個讀操作的總超時時間等于ReadTotalTimeoutMultiplier參數(shù)值乘以讀操作要讀取的字節(jié)數(shù)再加上ReadTotalTimeoutConstant參數(shù)值的和。如果將ReadTotalTimeoutMultiplier和ReadTotalTimeoutConstant都設(shè)置為0,,則表示讀操作不使用總超時時間,。每個讀間隔超時參數(shù)ReadIntervalTimeout被設(shè)置為MAXDWORK,而且兩個讀總超時參數(shù)都被設(shè)置為0,,那么標(biāo)識只要一讀完接收緩沖區(qū)而不管得到什么字符就完成讀操作,,即使它是空的。當(dāng)接收中有間隔時,,間隔超時將迫使讀操作返回,。因此使用間隔超時的進(jìn)程可以設(shè)置一個非常短的間隔超時參數(shù),這樣它可以實現(xiàn)對一個或一些字符的小的,、孤立的數(shù)據(jù)作出反應(yīng),。 每個寫操作的WriteTotalTimeoutConstant等于WriteTotalTimeoutMultiplier成員值乘以寫操作要寫的字節(jié)數(shù),再加上WriteTotalTimeoutConstant參數(shù)值的和,。如果WriteTotalTimeoutMultiplier和WriteTotalTimeoutConstant參數(shù)值都設(shè)置為0則表示寫操作不使用WriteTotalTimeoutConstant,。 在傳輸某種流量控制被阻塞時和調(diào)用SetCommBreak()函數(shù)把字符掛起,寫操作的超時可能有用,。如果所有的讀超時參數(shù)都為0,,即沒有使用讀超時,那么讀操作知道讀完要求的字節(jié)數(shù)或發(fā)生錯誤時位置,。同樣,,如果所有的寫超時參數(shù)都為0,,那么寫操作知道要求的字節(jié)數(shù)或發(fā)生錯誤時為止。當(dāng)打開通信資源時,,超時參數(shù)將根據(jù)上次設(shè)備被打開時所設(shè)置的值設(shè)置,。如果資源從未打開或調(diào)用SetComm函數(shù),那么所有的超時參數(shù)都設(shè)置為0,。 如果欲獲得當(dāng)前超時參數(shù),,應(yīng)用程序可以調(diào)用GetCommTimeouts()函數(shù)。該函數(shù)聲明如下: BOOL GetCommTimeouts( HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts ); 其中主要參數(shù)如下: ·hFile:標(biāo)識通信設(shè)備,,CreateFile()函數(shù)返回該句柄,; ·lpCommTimeouts:指向一個CommTIMEOUTS結(jié)構(gòu),返回超時信息,。 如果該函數(shù)調(diào)用成功,,則返回值不為零;若函數(shù)調(diào)用失敗,,則返回值為零,。調(diào)用GetLastError()函數(shù)可以獲得進(jìn)一步的出錯信息。 如果要設(shè)置或改變原來的超時參數(shù),,應(yīng)用程序可以調(diào)用SetCommTimeouts()函數(shù),。該函數(shù)聲明如下: BOOL SetCommTimeouts( HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts ); 其中主要參數(shù)如下: ·hFile:標(biāo)識通信設(shè)備,CreateFile()函數(shù)返回該句柄,; ·lpCommTimeouts:指向一個CommTIMEOUTS結(jié)構(gòu),,返回超時信息。 如果該函數(shù)調(diào)用成功,,則返回值不為零,;若函數(shù)調(diào)用失敗,則返回值為零,。調(diào)用GetLastError()函數(shù)可以獲得進(jìn)一步的出錯信息,。 5. 通信狀態(tài)和通信錯誤 如果在串口通信中發(fā)生錯誤,如發(fā)生中斷,,奇偶錯誤等,,I/O操作將會終止。如果程序要進(jìn)一步執(zhí)行I/O操作,,必須調(diào)用ClearCommError()函數(shù),。ClearCommError()函數(shù)有兩個作用:第一個作用是清除錯誤條件;第二個作用是確定串口通信狀態(tài),。ClearCommError()函數(shù)的聲明如下: BOOL ClearCommError( HANDLE hFile, LPDWORD lpErrors, LPCOMSTAT lpStat ); 其中主要參數(shù)介紹如下: ·hFile :標(biāo)識通信設(shè)備,,CreateFile()函數(shù)返回該句柄。 ·lpErrors:指向用一個指明錯誤類型的掩碼填充的32位變量。該參數(shù)可以是表6中各值的組合,。 ·lpStat:指向一個COMSTAT結(jié)構(gòu),,該結(jié)構(gòu)接收設(shè)備的狀態(tài)信息。如果lpStat參數(shù)不設(shè)置,,則沒有設(shè)備狀態(tài)信息被返回,。 表6 通信錯誤列表
如果該函數(shù)調(diào)用成功,,則返回值不為零,;若函數(shù)調(diào)用失敗,則返回值為零,。調(diào)用GetLastError()函數(shù)可以獲得進(jìn)一步的出錯信息,。在同步操作時,可以調(diào)用ClearCommError()函數(shù)來確定串口的接收緩沖區(qū)處于等待狀態(tài)的字節(jié)數(shù),,而后可以使用ReadFile()或者WriteFile()函數(shù)一次讀寫完,。 COMSTAT結(jié)構(gòu)存放有關(guān)通信設(shè)備的當(dāng)前信息。該結(jié)構(gòu)內(nèi)容由ClearCommError()函數(shù)填寫,。COMSTAT結(jié)構(gòu)聲明如下: typedef struct_COMSTAT( DWORD fCtsHold: 1; DWORD fDsrHold: 1; DWORD fRlsdHold: 1; DWORD fXoffSent: 1; DWORD fEof: 1; DWORD fTxim: 1; DWORD fReserved: 25; DWORD cbInQue; DWORD cbOutQue; } COMSTAT,*LPCOMSTAT; 其中主要參數(shù)介紹如下: ·fCtsHold:指明是否等待CRS信號,,如果為1,則發(fā)送等待,。 ·fDsrHold:指明是否等到DRS信號,,如果為1,則發(fā)送等待,。 ·fRlsdHold:指明是否等待RLSD信號,,如果為1,則發(fā)送等待,。 ·fXoffSent:指明收到XOFF字符后發(fā)送是否等待,。如果為1,則發(fā)送等待,。如果把XOFF字符發(fā)送給一系統(tǒng)時,,該系統(tǒng)就把下一個字符當(dāng)成XON,而不管實際字符是什么,,此時發(fā)送將停止,。 ·fEof:EOF字符送出。 ·fTxim:指明字符是否正等待被發(fā)送,,如果為1,,則字符正等待被發(fā)送。 ·fReserved:系統(tǒng)保留。 ·cbInQue:指明串行設(shè)備接收到的字節(jié)數(shù),。并不是指ReadFile操作要求讀的字節(jié)數(shù),。 ·cbOutQue:指明發(fā)送緩沖區(qū)尚未發(fā)送的字節(jié)數(shù)。如果進(jìn)行不重疊寫操作時值為0,。
2.4 通信事件 Windows進(jìn)程中監(jiān)視發(fā)生在通信資源中的一組事件,,這樣應(yīng)用程序可以不檢查端口狀態(tài)就可以知道某些條件何時發(fā)生,這將是非常有用的,。通過使用事件,,應(yīng)用程序不需要為接收字節(jié)而連續(xù)不斷地檢測端口,從而節(jié)省CPU時間,。 1. 通信事件 Windows可以利用GetCommMask()函數(shù)和 SetCommMask函數(shù)來控制表7所示的通信事件,。 表7 Windows通信事件列表
2. 操作通信事件 應(yīng)用程序可以利用SetCommMask()函數(shù)簡歷事件掩模來監(jiān)視指定通信資源上的事件,。SetCommMask函數(shù)的聲明如下: BOOL SetCommMask( HANDLE hFile, DWORD dwEvtMask ); 其中主要參數(shù)介紹如下: ·hFile :標(biāo)識通信設(shè)備,,CreateFile()函數(shù)返回該句柄。 ·dwEvtMask:事件掩模,,標(biāo)識將被監(jiān)視的通信事件,。如果該參數(shù)設(shè)置為0,則表示禁止所有事件,。如果不為0,,則可以是表7中各種事件的組合。 如果該函數(shù)調(diào)用成功,,則返回值不為零,;若函數(shù)調(diào)用失敗,則返回值為零,。調(diào)用GetLastError()函數(shù)可以獲得進(jìn)一步的出錯信息,。 如果想獲取特定通信資源的當(dāng)前事件掩模,可以使用GetCommMask()函數(shù),。GetCommMask()函數(shù)聲明如下: BOOL GetCommMask( HANDLE hFile, LPDWORD lpEvtMask ); 其中主要參數(shù)介紹如下: ·hFile :標(biāo)識通信設(shè)備,,CreateFile()函數(shù)返回該句柄。 ·dwEvtMask:事件掩模,,標(biāo)識將被監(jiān)視的通信事件,,一個32位變量,可以是表7中各種事件的組合,。 如果該函數(shù)調(diào)用成功,,則返回值不為零;若函數(shù)調(diào)用失敗,則返回值為零,。調(diào)用GetLastError()函數(shù)可以獲得進(jìn)一步的出錯信息,。 3. 監(jiān)視通信事件 在用SetCommMask()指定了有用的事件后,應(yīng)用程序就調(diào)用WaitCommEvent()函數(shù)來等待其中一個事件發(fā)生,。WaitCommEvent()函數(shù)既可以同步使用,,也可以異步使用。WaitCommEvent()函數(shù)聲明如下: BOOL WaitCommEvent( HANDLE hFile, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped, ); 其中主要參數(shù)介紹如下: ·hFile :標(biāo)識通信設(shè)備,,CreateFile()函數(shù)返回該句柄,。 ·dwEvtMask:指向一個32位變量,接收事件掩模,,標(biāo)識所發(fā)生的通信事件屬于何種類型,??梢允潜?/span>7中各種事件的組合,。 ·lpOverlapped:指向一個OVERLAPPED結(jié)構(gòu),如果打開hFile表示的通信設(shè)備時,,指定FILE_FLAG_OVERLAPPED標(biāo)志,,則該參數(shù)被忽略。如果不需要異步操作,,則這個參數(shù)不用設(shè)置,。 如果該函數(shù)調(diào)用成功,則返回值不為零,;若函數(shù)調(diào)用失敗,,則返回值為零。調(diào)用GetLastError()函數(shù)可以獲得進(jìn)一步的出錯信息,。 如果lpOverlapped參數(shù)不設(shè)置或打開hFile標(biāo)識的通信設(shè)備是未指定FILE_FLAG_OVERLAPPED標(biāo)志,,則知道發(fā)生了指定時間或出錯時,WaitCommEvent()函數(shù)才返回,。如果lpOverlapped參數(shù)指向一個OVERLAPPED結(jié)構(gòu),,并且打開hFile標(biāo)識的通信設(shè)備時指定了FILE_FLAG_OVERLAPPED標(biāo)志,則WaitCommEvent()函數(shù)以異步操作實現(xiàn),。這種情況下,,OVERLAPPED結(jié)構(gòu)中必須含有一個人工復(fù)位事件的句柄。和所有異步函數(shù)一樣,,如果異步操作不能立即實現(xiàn),,則該函數(shù)返回0,并且GetLastError()函數(shù)返回ERROR_IO_PENDING,,以指示該操作正在后臺進(jìn)行,。此時WaitCommEvent()函數(shù)返回之前,系統(tǒng)將OVERLAPPED結(jié)構(gòu)中的hEvent參數(shù)設(shè)置為無信號狀態(tài);當(dāng)發(fā)生了指定時間或出錯時,系統(tǒng)將其設(shè)置為有信號狀態(tài),。調(diào)用程序可使用等待函數(shù)確定事件對象的狀態(tài),,然后使用GetOverlappedResult()函數(shù)確定WaitCommEvent()函數(shù)的操作結(jié)束。GetOverlappedResult()函數(shù)報告該操作成功或者失敗,,并且lpEvtMask()函數(shù)所指向的變量被設(shè)置以指示所發(fā)生的事件,。 如果一個進(jìn)程在WaitCommEvent()函數(shù)操作進(jìn)行期間使用SetCommMask()函數(shù)將立即返回,并且由EvtMask參數(shù)指向的變量被設(shè)置,。 注意:WaitCommEvent()只檢測發(fā)生在等待開始后的事件,。例如,如果指定EV_RXCHAR事件,,則只有當(dāng)收到函數(shù)字符并將字符放進(jìn)接收緩沖區(qū)后才能滿足等待條件,。WaitCommEvent()調(diào)用時已在接收緩沖區(qū)中的字符不符合等待條件。監(jiān)視CTS,、DSR等信號狀態(tài)改變的事件時,,WaitCommEvent()函數(shù)只報告信號的變動,但不報告當(dāng)前的信號狀態(tài),,如果要查詢這些信號狀態(tài),,進(jìn)程可以調(diào)用GetCommModemstatus()函數(shù)。 |
|