2009-06-05 56 views
2

失敗我們有一行代碼與OPEN_ALWAYS的CreateFile Win32 API調用以一種奇怪的方式

if(!CreateFile(m_hFile, szFile, GENERIC_READ|GENERIC_WRITE, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL)) 
    { 
     DWORD dwErr = GetLastError(); 

     CString czInfo; 
     czInfo.Format ("CMemoryMapFile::OpenAppend SetFilePointer call failed - GetLastError returned %d", dwErr); 
     LOG(czInfo); 

     return false; 
    } 

此代碼工作多年很大。幾個星期前,我們遇到了一個有問題的客戶。原來,問題可以追溯到這行代碼,其中函數將返回一個INVALID_HANDLE_VALUE句柄,而GetLastError()返回ERROR_FILE_NOT_FOUND(2)。

現在,這對我們來說非常混亂。如果文件不存在,OPEN_ALWAYS應該指示文件被創建。那麼,爲什麼我們會收到一個ERROR_FILE_NOT_FOUND?

更多的困惑:對於這個客戶,這隻發生在一個網絡共享點(我們正在使用UNC路徑)。此客戶的其他UNC路徑可以工作。本地路徑工作。我們所有其他客戶(10000+安裝)完全沒有問題。

客戶使用XP作爲客戶端操作系統,服務器運行的似乎是標準的Windows Server 2003(我認爲小型企業服務器版本)。我們無法使用相同的操作系統在我們的測試實驗室中複製它們的錯誤。他們可以用幾個XP客戶端重複這個問題,但問題只出現在一臺服務器上(其他Server 2003服務器沒有出現問題)。

我們通過嵌套兩個CreateFile調用來解決這個問題,第一個調用OPEN_EXISTING,第二個調用CREATE_ALWAYS如果OPEN_EXISTING失敗。所以,我們沒有立即需要修復。

我的問題:有誰知道爲什麼這個API調用會以這種特殊方式失敗嗎?我們感到困惑。

附錄:

在上面的CreateFile函數是在Windows API函數的包裝。代碼如下:

bool CMemoryMapFile::CreateFile(HANDLE & hFile, LPCSTR szFile, DWORD dwDesiredAccess, DWORD dwShareMode, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes) 
{ 
    hFile = ::CreateFile (szFile, dwDesiredAccess, dwShareMode, NULL, 
         dwCreationDisposition, dwFlagsAndAttributes, NULL); 
    return (hFile != INVALID_HANDLE_VALUE) 
} 
+0

幾位用戶非常有幫助地指出,我們假設CreateFile在失敗時返回NULL句柄。我忘了(mea culpa)提到上面的例子中的CreateFile實際上是一個包裝函數。我將在上面的問題中添加包裝函數。包裝返回一個布爾值。 – 2009-06-05 18:28:06

回答

2

也許你想創建文件的目錄不存在?

您確定您使用2個CreateFile調用修復了它嗎?還是你沒有重現它?

+0

是的,它通過添加兩個CreateFile調用來解決。我們給了他們一個新的構建,並解決了他們的問題。 – 2009-06-05 18:19:46

+0

並且該目錄確實存在。我們與用戶一起完成了WebEx,並直接觀察了情況。 – 2009-06-05 18:20:31

+0

關於重新讀取代碼,我們可能會遇到一個timimg問題。該目錄是在CreateFile之前立即創建的,因此嘗試在其中創建文件可能存在某種延遲問題。我們沒有客戶可以試用。由於這似乎是一個可能的解釋,我將這個答案標記爲已接受。 – 2009-06-08 16:39:13

1

如果CreateFile失敗,它將返回非零的INVALID_HANDLE_VALUE(我認爲它是負數1)。所以CreateFile可能會成功並返回零作爲句柄。

在函數失敗後檢查GetLastError()只是安全的,但看起來您可能會在CreateFile成功(返回零)時檢查最後一個錯誤。

根據this article,一些功能設置 「一個錯誤」,如果他們取得成功:

3

首先,你應該經常檢查像這樣的CreateFile()API的成功:

if (CreateFile(...) == INVALID_HANDLE_VALUE) 
{ 
    // handle the error 
} 

因爲的CreateFile ()在成功的情況下不會返回!= 0,但不是INVALID_HANDLE_VALUE(即-1)。

然後,如果該目錄不存在要創建/打開該文件的位置,則CreateFile()可能會失敗,或者如果該用戶有權打開和寫入,該文件可能會失敗文件在該目錄中,但無權創建新文件。

0

我的猜測可能與服務器相關,如服務器沒有正確地爲該文件系統操作實現支持。也許一個Linux服務器相比,一個Windows服務器?

您創建文件的參數不正確,所以我認爲這是某種CreateFile helper函數。

到的CreateFile調用看起來應該像:

m_hFile = CreateFile(szFile, GENERIC_READ|GENERIC_WRITE, 0, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); 
if(m_hFile == INVALID_HANDLE_VALUE) 
2

當一個文件被UNC共享訪問,我們也看到了這個問題。在我們的例子中沒有應用的想法和建議 - 目錄總是存在,CreateFile的參數是正確的,我們正在檢查返回。

我們認爲這是一個股票問題。我們通過一個簡單的重試循環解決了這個問題:

如果一個CreateFileOPEN_ALWAYS失敗ERROR_FILE_NOT_FOUND,我們只是睡幾個小時,然後再試一次。它總是第二次運作(如果它第一次失敗)。