這個函數可以創建或打開一個對象的句柄,憑借此句柄就可以控制這些對象:
控制台對象、通信資源對象、目錄對象(只能打開)、磁盤設備對象、文件對象、郵槽對象、管道對象。
函數原型:
1 HANDLE CreateFile( 2 LPCTSTR lpFileName, // 文件名 3 DWORD dwDesiredAccess, // 訪問模式 4 DWORD dwShareMode, // 共享模式 5 LPSECURITY_ATTRIBUTES lpSecurityAttributes, // 安全屬性(也即銷毀方式) 6 DWORD dwCreationDisposition, // how to create 7 DWORD dwFlagsAndAttributes, // 文件屬性
8 HANDLE hTemplateFile // 模板文件句柄
9 );
【參數】
1、lpFileName
一個指向無終結符的字符串的指針,來指明要創建或打開的對象的名字。
在Windows NT/2000/XP平台上:如果用ANSI版本的函數,字符串長度應限制在MAX_PATH;如果用Unicode版本的函數,這個限制可以擴充到32000個Unicode字符。
在Windows95/98/Me平台上:只能用ANSI版本的函數,字符串長度限制在MAX_PATH。
2、dwDesiredAccess
指明對象的控制模式。一個應用程序可以包含讀控制、寫控制、讀/寫控制、設備查詢控制。
這個參數的取值可以是下面這些的組合:
0 指定設備查詢控制:程序可以不訪問設備就查詢到設備屬性。
GENERIC_READ 指定讀控制,可以從對象中讀取數據(指針將可以移動)。
GENERIC_WRITE 指定寫控制,可以向對象中寫數據(指針將可以移動)。
----------------------------------------------------------------------
另外,還可以指定下面的控制標志:
標准控制權限(16-23位掩碼):
DELETE 刪除對象的權限。
READ_CONTROL 從對象的安全描述符中讀取信息的權限,但不包括SACL(系統訪問控制列表)中的信息。
WRITE_DAC 修改對象安全描述符中的DACL(隨機訪問控制列表)的權限
WRITE_OWNER 修改對象安全描述符中的屬主的權限
SYNCHRONIZE 同步化使用對象的權限,即可以創建一個線程等待信號量釋放(但有些對象不支持這個權限)。
STANDARD_RIGHTS_REQUIRED 等價於前面四種權限的總合(通常這四種是必須具有的權限)。
STANDARD_RIGHTS_READ 一般等價於READ_CONTROL
STANDARD_RIGHTS_WRITE 一般等價於READ_CONTROL
STANDARD_RIGHTS_EXECUTE 一般等價於READ_CONTROL
STANDARD_RIGHTS_ALL 等價於前面五種權限的總合。
特殊控制權限(0-15位掩碼):
SPECIFIC_RIGHTS_ALL
ACCESS_SYSTEM_SECURITY
MAXIMUM_ALLOWED
GENERIC_READ
GENERIC_WRITE
GENERIC_EXECUTE
GENERIC_ALL
注:實質上是通過ACCESS_MASK結構體的一個雙字值來設置標准權限、特殊權限和一般權限的。
3、dwShareMode
指定對象的共享模式。如果dwShareMode==0,表示是互斥使用的。如果CreateFile打開成功,則別的程序只能等到當前程序關閉對象句柄CloseHandle后才能在打開或使用。
使用下面這些值的組合來表示對象的共享模式:
FILE_SHARE_DELETE Windows NT/2000/XP:打開操作只有在刪除請求發生時才能返回成功。
FILE_SHARE_READ 打開操作只有在讀控制請求發生時才能返回成功。
FILE_SHARE_WRITE 打開操作只有在寫控制請求發生時才能返回成功。
4、lpSecurityAttributes
一個指向SECURITY_ATTRIBUTES結構對象的指針,決定返回的句柄是否被子進程所繼承。如果lpSecurityAttributes參數為NULL,句柄就不能被子進程繼承。
在Windows NT/2000/XP平台下:lpSecurityDescriptor這個成員指明了這個對象的安全描述符。如果lpSecurityAttributes參數為NULL,對象將獲得一個默認的安全描述符。目標文件系統必須為這個參數的在文件上的有效操作保證安全性。
1 typedef struct _SECURITY_ATTRIBUTES { 2 DWORD nLength; //結構體的大小(字節為單位),即siziof(SECURITY_ATTRIBUTES) 3 LPVOID lpSecurityDescriptor; //指向對象的安全描述符的指針,控制對象的共享屬性。在Windows 95/98/Me平台 //上這個成員被忽略。 4 BOOL bInheritHandle; //指明當一個新的子進程創建時,是否繼承當前返回的句柄 5 } SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES;
5、dwCreationDisposition
指明當打開的對象存在或不存在的時候各需怎樣處理。這個參數必須是一下值的其中之一:
CREATE_NEW 創建新文件/對象(當對象已經存在是將返回失敗)。
CREATE_ALWAYS 總是創建(如果對象存在就覆蓋它,清除當前屬性,把文件屬性和dwFlagsAndAttributes指定的標志相結合)。
OPEN_EXISTING 打開文件(如果不存在就返回失敗)。
OPEN_ALWAYS 存在就打開;若不存在,假如dwCreationDisposition==CREATE_NEW就創建一個新文件。
TRUNCATE_EXISTING 存在就打開,且清空文件內容(至少要有GENERIC_WRITE權限);若文件不存在就返回失敗。
6、dwFlagsAndAttributes
指定文件屬性和標志。可以是以下值的任意組合(只有FILE_ATTRIBUTE_NORMAL必須單獨使用,唯一例外):
Attribute:
FILE_ATTRIBUTE_ARCHIVE 文件存檔(備份或移動時會對文件做標記)。
FILE_ATTRIBUTE_ENCRYPTED 加密(對文件來說是內容加密,對目錄來說是對將來新建的文件默認為加密屬性),與此同時,如果還設置了FILE_ATTRIBUTE_SYSTEM屬性,當前這個屬性將無效。
FILE_ATTRIBUTE_HIDDEN 隱藏屬性。
FILE_ATTRIBUTE_NORMAL 文件沒有其他屬性設置,此屬性只能單獨使用才合法。
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 不建立內容索引。
FILE_ATTRIBUTE_OFFLINE 脫機屬性。文件內容暫時不可用。此屬性被Remote Storage軟件所用,不能任意更改。
FILE_ATTRIBUTE_READONLY 只讀文件屬性。應用程序不能寫或刪除。
FILE_ATTRIBUTE_SYSTEM 文件是系統文件或被操作系統互斥地使用。
FILE_ATTRIBUTE_TEMPORARY 臨時文件,使用過程中盡量留在內存以保證存取速度。
Flag:
FILE_FLAG_WRITE_THROUGH 指示系統立即寫磁盤。這個寫操作允許被cache緩存,但不能被擱置。
FILE_FLAG_OVERLAPPED 指示系統初始化對象,如果操作需要大量時間執行就先返回一 個 ERROR_IO_PENDING,當操作 完成后再通過事件使能信號量。指定這個標志就必須在read和write函數里初始化OVERLAPPED 結構體,應用程序必須執行重復的讀寫操作。此時,操作系統不維護文件指針,當前的位置 需要通過OVERLAPPED的指針傳遞給讀寫函數。這個標志還允許多個操作的並行(並行讀寫)。
FILE_FLAG_NO_BUFFERING 指示系統不要緩沖,它如果和FILE_FLAG_OVERLAPPED聯合使用,將呈現最好的異步性能,因為I/O操作並不依賴於內存管理器的同步性。但是有時I/O操作會慢些,因為沒用cache。有時程序需要做調整,比如文件大小必須是扇區大小的整數倍,Buffer地址的按扇區地址對齊等。按扇區地址對齊內存邊界可以使用VirtualAlloc來分配內存,GerDiskFreeSpace函數可以得到磁盤一個扇區的大小。
FILE_FLAG_RANDOM_ACCESS 指示文件進行隨即存取,系統可據此對cache的分配進行優化。
FILE_FLAG_SEQUENTIAL_SCAN 指示順序存取,系統也可據此對cache的分配進行優化。即使有隨即存取的操作,也不會出錯,不過cache的優化就取消了。在連續讀取大文件時性能非常好。
FILE_FLAG_DELETE_ON_CLOSE 指示系統在句柄關閉時將響應的文件立即刪除,對當前句柄以外的其他句柄也有效。而且隨后的打開請求也會失敗,直到你使用了FILE_SHARE_DELETE屬性。
FILE_FLAG_BACKUP_SEMANTICS 在Windows NT/2000/XP平台上:指示文件作為備份或恢復文件打開,這是如果調用進程擁有特殊權限(SE_BACKUP_NAME 或 SE_RESTORE_NAME),就可以不進行安全檢查。也可以在獲得一個目錄的句柄時設置這個flag,目錄句柄可以代替文件句柄傳遞給一些函數。
FILE_FLAG_POSIX_SEMANTICS 指明按照操作系統接口規范進行文件存取,這包括允許多文件名的使用。請謹慎使用,因為MS_DOS或16位Windows系統可能不支持。
FILE_FLAG_OPEN_REPARSE_POINT 這個標志指明禁止文件系統的重解析點的動作。文件打開時就返回文件的句柄,而不在乎控制重解析點的過濾器是否可運行。不能和CREATE_ALWAYS同時使用。
FILE_FLAG_OPEN_NO_RECALL 表明文件數據被請求,但仍然駐留在遠程存儲體中,而不會被傳回本地存儲體。這個標志 由遠程存儲系統或分層存儲管理系統使用。
如果CreateFile函數打開一個命名管道的客戶端,dwFlagsAndAttributes 參數也會包含服務信息的安全性。當調用程序指定了
SECURITY_PRESENT標志時,dwFlagsAndAttributes 參數可以取以下一個或多個值:
SECURITY_ANONYMOUS 指定將客戶端模擬在匿名級別(the Anonymous impersonation level)
SECURITY_IDENTIFICATION 指定將客戶端模擬在身份認證級別(the Identification impersonation level)
SECURITY_IMPERSONATION 指定將客戶端模擬在偽裝級別(the Impersonation impersonation level)
SECURITY_DELEGATION 指定將客戶端模擬在授權級別(the Delegation impersonation level)
SECURITY_CONTEXT_TRACKING 指定安全跟蹤模式是動態的,否則(不指定此標志)是靜態的
SECURITY_EFFECTIVE_ONLY 指定客戶端的安全內容中的有效內容才可以被服務端使用,否則所有內容都可被使用。 這個標志允許客戶端限制服務端在模擬客戶端時所具有的權限。
7、hTemplateFile
把具有GENERIC_READ權限的句柄指定為一個模板文件。這個模板文件提供了文件屬性和擴展屬性,用於創建文件。在Windows95/98/Me平台上:這個參數必須為空,否則如果你提供一個句柄,函數調用將會失敗,用GerLastError函數獲得的出錯信息為ERROR_NOT_SUPPORTED。
【Return Values】
調用如果成功,返回值時一個打開文件的句柄。
如果調用之前文件已存在,且dwCreationDisposetion 為CREATE_ALWAYS或OPEN_ALWAYS,用GetLastError返回ERROR_ALREADY_EXISTS。
(即使調用成功也會返回這個值)。如果調用之前不存在,GetLastError返回0。
調用如果失敗,返回值是INVALID_HANDLE_VALUE。要進一步了解出錯原因,調用GetLastError。
【備注】
在Windows 2000/XP平台上:
如果你企圖打開一個遠程機器上的文件或目錄,dwDesiredAccess設置為DELETE或者任一其他的控制標志,
而這時遠程文件或目錄還沒有以FILE_SHARE_DELETE的方式打開的話,你的函數調用就會發生共享錯誤了。
為了避免共享錯誤,一種辦法是單獨用DELETE方式打開遠程文件或目錄,另一種方法是在打開文件或目錄之前先調用DeleteFile函數。
如果dwCreationDisposition 參數指定為CREATE_ALWAYS 並且dwFlagsAndAttributes 參數指定為FILE_ATTRIBUTE_NORMAL 的話,CreateFile調用將失敗,GetLastError報告的錯誤是ACCESS_DENIED。這時,把dwFlagsAndAttributes 參數設置為FILE_ATTRIBUTE_HIDDEN和FILE_ATTRIBUTE_NORMAL的聯合值,將避免這個問題。
二、*****CloseHandle*****
用於關掉一個打開的對象句柄。
函數原型:
1 BOOL CloseHandle( 2 HANDLE hObject // 句柄 3 );
【返回值】
函數調用成功返回非零,失敗返回0。獲得更多錯誤信息,需要調用GetLastError函數。
在Windows NT/2000/XP平台上:當應用程序在調試器下運行時,關閉一個不合法的句柄將產生一個異常(Exception)。包括兩次關閉同一個句柄,或者試圖關閉一個由FindFirstFile函數返回的句柄,都會產生異常。
【備注】
CloseHandle使指定的句柄無效,減少對象的句柄計數,進行對象保持檢驗。當對象的最后一個句柄關閉時,對象將從系統中刪除。關閉一個線程句柄並不會終止一個線程,要釋放一個線程對象,必須terminate線程,然后關閉所有的線程句柄。用CloseHandle只能關閉由CreateFile函數返回的句柄。用FindClose來關閉由FindFirstFile返回的句柄。
三、*****ReadFile*****
ReadFile函數從文件指針指定的位置讀取數據。讀操作完成后,文件指針將根據實際讀出的數據自動進行調整,除非文件句柄是以OVERLAPPED屬性值打開的。如果是以OVERLAPPED打開的I/O,應用程序就需要自己手動調整文件指針。
這個函數被設計成兼有同步和異步操作。ReadFileEx函數則設計成只支持異步操作,異步操作允許應用程序在讀文件期間可以同時進行其他的操作。
函數原型:
1 BOOL ReadFile( 2 HANDLE hFile, // handle to file 3 LPVOID lpBuffer, // data buffer 4 DWORD nNumberOfBytesToRead, // number of bytes to read 5 LPDWORD lpNumberOfBytesRead, // number of bytes read 6 LPOVERLAPPED lpOverlapped // overlapped buffer 7 );
【參數】
1、hFile
文件句柄(必須具有GENERIC_READ訪問權限)。
在Windows NT/2000/XP平台上:對於異步讀操作,hFile可以是由CreateFile函數以FILE_FLAG_OVERLAPPED方式打開的任何句柄,或者一個由socket或accept函數返回的socket句柄。
在Windows 95/98/Me平台上:對於郵槽、命名管道和磁盤文件不能使用異步讀操作。
2、lpBuffer
用來接收從文件中讀出的數據的緩沖區指針。
3、nNumberOfBytesToRead
指明要讀的字節總數。
4、lpNumberOfBytesRead
一個變量指針,用來存儲實際傳輸的字節總數。ReadFile在做所有事情(包括錯誤檢查)之前,先將這個值賦為0。當ReadFile從一個命名管道上返回TRUE時這個參數為0,說明消息管道另一端調用WriteFile時設置的nNumberOfBytesToWrite 參數為0。
在Windows NT/2000/XP平台上:如果lpOverlapped 為NULL,則lpNumberOfBytesRead不能為NULL。如果lpOverlapped 不是NULL,lpNumberOfBytesRead可以設為NULL。如果是一個overlapped形式的讀操作,我們可以動用GetOverlappedResult函數來獲得傳輸的實際字節數。如果hFile關聯的是一個完成端口(I/O completion port),那么可以調用GetQueuedCompletionStatus函數來獲得傳輸的實際字節數。
如果完成端口(I/O completion port)被占用,而你用的是一個用於釋放內存的回調例程,對於lpOverlapped參數指向的OVERLAPPED結構體來說,為這個參數指定NULL可以避免重新分配內存時發生內存泄漏。內存泄漏會導致返回這個參數值時是一個非法值。
Windows 95/98/Me平台上:這個參數不允許為NULL。
5、lpOverlapped
一個指向OVERLAPPED結構體的指針。如果hFile是以FILE_FLAG_OVERLAPPED方式獲得的句柄,這個結構是必須的,不能為NULL。(否則函數會在錯誤的時刻報告讀操作已經完成了)。這時,讀操作在由OVERLAPPED中Offset成員指定的偏移地址開始讀,並且在實際完成讀操作之前就返回了。在這種情況下,ReadFile返回FALSE,GerLastError報告從錯誤類型是ERROR_IO_PENDING。這允許調用進程繼續其他工作直到讀操作完成。OVERLAPPED結構中的事件將會在讀操作完成時被使能。
如果hFile不是以FILE_FLAG_OVERLAPPED方式獲得的句柄,並且lpOverlapped為NULL,讀操作就從當前文件的開始位置讀起,直到讀操作完成ReadFile函數才能返回。
在Windows NT/2000/XP平台上:如果hFile不是以FILE_FLAG_OVERLAPPED方式獲得的句柄,並且lpOverlapped不為NULL,則讀操作在由OVERLAPPED中Offset成員指定的偏移地址開始讀,直到讀操作完成ReadFile函數才能返回。
在Windows 95/98/Me平台上:對於文件、磁盤、管道和郵槽的操作,這個參數必須為NULL。一個不為空的OVERLAPPED結構體指針將導致調用失敗。Windows 95/98/Me平台只支持串行口和並行口的overlapped 讀寫。
【返回值】
有如下任一種情況發生都會導致函數返回:(1)在管道另一端的寫操作完成后(2)請求的字節數傳輸完畢(3)發生錯誤。
如果函數正確,返回非零。
如果返回值是非零,但接收的字節數是0,那么可能是文件指針在讀操作期間超出了文件的end位置。然而,如果文件以FILE_FLAG_OVERLAPPED方式打開,lpOverlapped 參數不為NULL,文件指針在讀操作期間超出了文件的end位置,那么返回值肯定是FALSE,GetLastError返回的錯誤是ERROR_HANDLE_EOF。
【備注】
如果文件的一部分被另一個進程鎖定,而當前進程試圖重復鎖定,那將會失敗。
一個應用程序在讀以FILE_FLAG_NO_BUFFERING方式打開的文件時要符合一定的條件。
(1)文件讀的開始地址必須是扇區大小的整數倍。GetDiskFreeSpace函數可以取得扇區的大小。
(2)請求讀的字節數也必須是扇區大小的整數倍。
(3)用於讀寫操作的Buffer地址必須按照扇區大小進行邊界對齊。可以通過用VirtualAlloc 函數申請內存來做到。
在讀操作期間試圖訪問相應的輸入緩沖區,會導致讀入到緩沖區的數據損壞。讀操作完成之前,應用程序不能對這段輸入緩沖區做任何操作(包括讀、寫、重新分配內存,釋放內存等)。
ReadFile可以通過指向控制台輸入對象的句柄將控制台的輸入字符讀出來。控制台的模式決定了ReadFile的具體行為。
如果一個命名管道正在以消息模式被讀取,並且下一條消息比nNumberOfBytesToRead參數指定的長度還大,那么ReadFile將返回FALSE並且GetLastError返回錯誤為ERROR_MORE_DATA。剩下沒讀完的消息可能會被隨后的ReadFile或PeckNamedPipe函數讀出。
讀取一個通信設備時,ReadFile的行為被當前的通信延時所支配,延時屬性的設置和取得使用SetCommTimeouts和GetCommTimeouts函數。如果你設置延時屬性失敗,就會得到不可預知的結果。
如果ReadFile試圖讀取一個buffer太小的郵槽,將會返回FALSE並且GetLastError返回錯誤為ERROR_INSUFFICIENT_BUFFER 。
如果一個匿名的寫管道句柄已經關閉,而ReadFile試圖用響應的匿名權限讀這個管道句柄,將返回FALSE並且
GetLastError返回錯誤為ERROR_BROKEN_PIPE。
每當有太多的異步I/O請求得不到響應,ReadFile就會失敗,並返回ERROR_INVALID_USER_BUFFER或ERROR_NOT_ENOUGH_MEMORY的錯誤。
在同步和異步兩種情況下,ReadFile中檢測EOF(文件結尾邊界)的代碼是不同的。當一個同步讀操作到達文件結尾時,ReadFile返回TRUE,並設置*lpNumberOfBytesRead 為0 。異步讀操作會在開始調用的讀操作中或者隨后的其他異步操作中突然遇到文件結尾。(1)如果EOF在ReadFile期間被檢測到,將會返回FALSE,且 GetLastError返回錯誤描述 ERROR_HANDLE_EOF。(2)如果EOF在隨后的其他異步操作中被檢測到,則類似GetOverlappedResult 等試圖獲取操作結果的函數返回FALSE,且 GetLastError返回錯誤描述ERROR_HANDLE_EOF。
為了取消未響應的異步I/O操作,用CancelIo函數。這個函數只能取消由調用進程對特定句柄進行的操作。被取消的I/O操作將被描述為ERROR_OPERATION_ABORTED。
如果你正試圖從並不存在的軟驅中讀數據,系統會彈出消息框提示你重新操作。為了阻止系統的消息框,調用函數SetErrorMode,參數設置為SEM_NOOPENFILEERRORBOX。