0. 前言
做序列槽方面的程式,使用CreateFile打開序列槽通信端口。在對序列槽操作之前,需要首先打開序列槽。使用C++進行序列槽程式設計,如果采用VS開發,則可以直接借助于序列槽通信控件來操作,其次,直接調用Windows的底層API函數來控制序列槽通信。
在Window 32bit 的作業系統上, 将序列槽(通信裝置)作為檔案來處理,是以序列槽的打開、關閉、讀寫所使用的API函數與檔案操作一樣。是以打開序列槽使用CreateFile函數,讀寫序列槽使用ReadFile、WriteFile,函數。關閉序列槽使用CloseHandle函數。
1. 檢視通信序列槽裝置,可以在裝置管理器中檢視;
2.
-------------------------------
1. CreateFile
這個函數的功能是建立或者打開一個檔案或者I/O裝置,通常使用的I/O形式有檔案、檔案流、目錄、實體磁盤、卷、終端流等。如執行成功,則傳回檔案句柄。 INVALID_HANDLE_VALUE 表示出錯,會設定 GetLastError 。
函數的聲明定義:
HANDLE WINAPI CreateFile(
_In_ LPCTSTR lpFileName,
_In_ DWORD dwDesiredAccess,
_In_ DWORD dwShareMode,
_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
_In_ DWORD dwCreationDisposition,
_In_ DWORD dwFlagsAndAttributes,
_In_opt_ HANDLE hTemplateFile
);
參數清單:

部分參數Tips:
1. lpFileName:指定要打開的序列槽邏輯名,用字元串來表示。如COM1, COM2,分别表示序列槽1,和序列槽2.
如果要确定工控機上有那些序列槽,可以使用裝置管理器檢視。如下圖:
檢視方式如下圖:我的電腦,右鍵, 開發“裝置管理器”即可。
2. dwDesiredAccess:端口屬性的通路類型,
3. dwShareMode:指定端口的共享屬性。
該參數是由那些應用程式共享的檔案提供。對于序列槽來說,是不能共享的,是以,必須設定為0,這是通信裝置與檔案的特殊差别。
如果目前的應用程式調用CreateFile打開一個序列槽,另外一個程式如果已經打開了該序列槽,此時CreateFile會傳回一個錯誤代碼。
然而,同一個應用程式的多個線程是可以共享CreateFile傳回的端口句柄。并且根據安全屬性設定,該句柄可以打開端口的應用程式的子程式來繼承。
4. lpSecurityAttributes:安全屬性,一般該參數為NULL,即該端口被設定為預設的安全屬性。預設安全屬性下,端口的句柄是不能繼承的。
5. dwCreationDisposition:指定此端口正在被其他程式占用采取的動作,因為序列槽總是存在的,是以必須設定為OPEN_EXISTing, 該标志高速Windows不要建立新的端口。而是打開一個已經存在的端口。
, 6. dwFlagsAndSttributes:描述了端口的各種屬性,對于檔案來說有很多屬性,但是對于序列槽來說,唯一的意義是FILE_FLAG _OVERLAPPED 屬性,當設定該屬性時,端口IO可以在背景進行,稱為異步IO重疊結構。
7. hTemplateFile: 指定模闆的檔案句柄,對于序列槽來說,此參數必須設定為0;
關閉序列槽
關閉序列槽,使用CloseHandle,函數聲明為:
函數很簡單,參數是使用CreateFile打開的端口句柄。調用這個函數可以實作序列槽關閉。
示例如下:
2. ReadFile
從檔案指針指向的位置(裝置檔案,通信)開始将資料讀出到一個檔案中, 且支援同步和異步操作,如果檔案打開方式沒有指明FILE_FLAG_OVERLAPPED的話,當程式調用成功時,它将實際讀出檔案的位元組數儲存到lpNumberOfBytesRead指明的位址空間中。FILE_FLAG_OVERLAPPED 允許對檔案進行重疊操作。
函數聲明定義:
BOOL WINAPI ReadFile(
__in HANDLE hFile, // 檔案句柄
__out LPVOID lpBuffer, // 接收資料用的 buffer
__in DWORD nNumberOfBytesToRead, // 要讀取的位元組數
__out LPDWORD lpNumberOfBytesRead, // 實際讀取到的位元組數
__in LPOVERLAPPED lpOverlapped // OVERLAPPED 結構,一般設定為 NULL
);
代碼示例:、
1 BOOL Read(char *filePath)
2 {
3 HANDLE pFile;
4 DWORD fileSize;
5 char *buffer,*tmpBuf;
6 DWORD dwBytesRead,dwBytesToRead,tmpLen;
7
8 pFile = CreateFile(filePath,GENERIC_READ,
9 FILE_SHARE_READ,
10 NULL,
11 OPEN_EXISTING, //打開已存在的檔案
12 FILE_ATTRIBUTE_NORMAL,
13 NULL);
14 // 建立裝置檔案,傳回檔案的位置
15 if ( pFile == INVALID_HANDLE_VALUE)
16 {
17 printf("open file error!\n");
18 CloseHandle(pFile);
19 return FALSE;
20 }
21
22 fileSize = GetFileSize(pFile,NULL); //得到檔案的大小
23
24 buffer = (char *) malloc(fileSize);
25 ZeroMemory(buffer,fileSize);
26 dwBytesToRead = fileSize;
27 dwBytesRead = 0;
28 tmpBuf = buffer;
29
30 do{ //循環讀檔案,確定讀出完整的檔案
31
32 ReadFile(pFile,tmpBuf,dwBytesToRead,&dwBytesRead,NULL);
33
34 if (dwBytesRead == 0)
35 break;
36
37 dwBytesToRead -= dwBytesRead;
38 tmpBuf += dwBytesRead;
39
40 } while (dwBytesToRead > 0);
41
42 // TODO 處理讀到的資料 buffer
43
44 free(buffer);
45 CloseHandle(pFile);
46
47 return TRUE;
48 }
3. WriteFile
将資料寫入一個檔案(裝置檔案,通信)。該函數比fwrite函數要靈活的多。也可将這個函數應用于對通信裝置、管道、套接字以及郵槽的處理。傳回時,TRUE(非零)表示成功,否則傳回零。會設定GetLastError。
函數聲明定義:
BOOL WINAPI WriteFile(
__in HANDLE hFile, // 檔案句柄
__in LPCVOID lpBuffer, // 要寫入的資料
__in DWORD nNumberOfBytesToWrite, // 要寫入的位元組數
__out LPDWORD lpNumberOfBytesWritten, // 實際寫入的位元組數
__in LPOVERLAPPED lpOverlapped // OVERLAPPED 結構,一般設定為 NULL
);
示例代碼:
1 BOOL Write(char *buffer, DWORD contentLen)
2 {
3 HANDLE pFile;
4 char *tmpBuf;
5 DWORD dwBytesWrite,dwBytesToWrite;
6
7 pFile = CreateFile(filePath,GENERIC_WRITE,
8 0,
9 NULL,
10 CREATE_ALWAYS, //總是建立檔案
11 FILE_ATTRIBUTE_NORMAL,
12 NULL);
13
14 if ( pFile == INVALID_HANDLE_VALUE)
15 {
16 printf("create file error!\n");
17 CloseHandle(pFile);
18 return FALSE;
19 }
20
21 dwBytesToWrite = contentLen;
22 dwBytesWrite = 0;
23
24 tmpBuf = buffer;
25
26 do{ //循環寫檔案,確定完整的檔案被寫入
27
28 WriteFile(pFile,tmpBuf,dwBytesToWrite,&dwBytesWrite,NULL);
29
30 dwBytesToWrite -= dwBytesWrite;
31 tmpBuf += dwBytesWrite;
32
33 } while (dwBytesToWrite > 0);
34
35 CloseHandle(pFile);
36
37 return TRUE;
38 }