2011-10-05 115 views
7

我打開一個串口使用CreateFile()。我有一個測試用例(太複雜,無法重新分配),導致CreateFile()返回INVALID_HANDLE_VALUEGetLastError()返回ERROR_SUCCESS。從外觀上看,只有當一個線程在另一個端口關閉的同時打開端口時,纔會出現此錯誤。打開端口的線程遍歷這個問題。CreateFile()返回INVALID_HANDLE_VALUE,但GetLastError()是ERROR_SUCCESS

我不知道這是否有所作爲,但後來在代碼中我使用CreateIoCompletionPort將端口與CompletionPort相關聯。

這裏是我的代碼:

HANDLE port = CreateFile(L"\\\\.\\COM1", 
         GENERIC_READ | GENERIC_WRITE, 
         0,     // must be opened with exclusive-access 
         0,     // default security attributes 
         OPEN_EXISTING,  // must use OPEN_EXISTING 
         FILE_FLAG_OVERLAPPED, // overlapped I/O 
         0);     // hTemplate must be NULL for comm devices 
if (port == INVALID_HANDLE_VALUE) 
{ 
    DWORD errorCode = GetLastError(); 
    cerr << L"CreateFile() failed with error: " << errorCode << endl; 
} 

我敢肯定這樣的事情不應該發生的。我做錯了什麼?我如何讓API返回正確的結果?


更多詳情JPeripheral

下面是實際的(unsanitized)源代碼:

JLong SerialChannel::nativeOpen(String name) 
{ 
    cerr << "nativeOpen(" << name << ")" << endl; 
    wstring nameWstring = name; 
    HANDLE port = CreateFile((L"\\\\.\\" + nameWstring).c_str(), 
     GENERIC_READ | GENERIC_WRITE, 
     0,           // must be opened with exclusive-access 
     0,           // default security attributes 
     OPEN_EXISTING,     // must use OPEN_EXISTING 
     FILE_FLAG_OVERLAPPED,  // overlapped I/O 
     0);           // hTemplate must be NULL for comm devices 
    cerr << "nativeOpen.afterCreateFile(" << name << ")" << endl; 
    cerr << "port: " << port << ", errorCode: " << GetLastError() << endl; 
    if (port == INVALID_HANDLE_VALUE) 
    { 
     DWORD errorCode = GetLastError(); 

     switch (errorCode) 
     { 
      case ERROR_FILE_NOT_FOUND: 
       throw PeripheralNotFoundException(jace::java_new<PeripheralNotFoundException>(name, Throwable())); 
      case ERROR_ACCESS_DENIED: 
      case ERROR_SHARING_VIOLATION: 
       throw PeripheralInUseException(jace::java_new<PeripheralInUseException>(name, Throwable())); 
      default: 
      { 
       throw IOException(jace::java_new<IOException>(L"CreateFile() failed with error: " + 
        getErrorMessage(GetLastError()))); 
      } 
     } 
    } 

    // Associate the file handle with the existing completion port 
    HANDLE completionPort = CreateIoCompletionPort(port, ::jperipheral::worker->completionPort, Task::COMPLETION, 0); 
    if (completionPort==0) 
    { 
     throw AssertionError(jace::java_new<AssertionError>(L"CreateIoCompletionPort() failed with error: " + 
      getErrorMessage(GetLastError()))); 
    } 
    cerr << "nativeOpen.afterCompletionPort(" << name << ")" << endl; 

    // Bind the native serial port to Java serial port 
    SerialPortContext* result = new SerialPortContext(port); 
    cerr << "nativeOpen.afterContext(" << name << ")" << endl; 
    return reinterpret_cast<intptr_t>(result); 
} 

此代碼是從一個串行端口庫我已經開發採取這裏是我得到的實際輸出:

nativeOpen(COM1) 
nativeOpen.afterCreateFile(COM1) 
port: 00000374, errorCode: 0 
nativeOpen.afterCompletionPort(COM1) 
nativeOpen.afterContext(COM1) 
[...] 
nativeOpen(COM1) 
nativeOpen.afterCreateFile(COM1) 
port: FFFFFFFF, errorCode: 0 
java.io.IOException: CreateFile() failed with error: The operation completed successfully. 
+0

這些行是您在測試中使用的確切行嗎?任何簡化(甚至顯然無害)都可能隱藏問題的根源。 –

+0

您訪問的硬件是什麼? – Gabe

+0

@Gabe:我正在訪問我們內部開發的嵌入式設備。它有一個標準的DB9串行端口連接,我已連接到我的PC(這裏沒有USB-RS232適配器)。 – Gili

回答

8
HANDLE port = CreateFile(...); 
cerr << "nativeOpen.afterCreateFile(" << name << ")" << endl; 
cerr << "port: " << port << ", errorCode: " << GetLastError() << endl; 
if (port == INVALID_HANDLE_VALUE) 
{ 
    DWORD errorCode = GetLastError(); 

對cerr的輸出調用winapi調用。這將重置由GetLastError()返回的線程錯誤值。修復:

HANDLE port = CreateFile(...); 
int err = GetLastError(); 
// etc, use err instead... 
+0

我不相信。有這個問題的原始代碼不包含任何'cerr'指令。我最近只添加了這個。你看到上面的代碼有錯嗎(減去'cerr')? – Gili

+1

您顯示的輸出跟蹤只能由*確實*弄亂GetLastError值的代碼生成。我不懷疑它可能會失敗,打開COM端口失敗的原因很多。 –

+0

你是對的。原始代碼調用'throw IOException(jace :: java_new (L「CreateFile()failed with error:」+ getErrorMessage(GetLastError()))'。注意在失敗點和讀取GetLastError ()'。更快的讀取數值解決了這個問題。謝謝! – Gili

相關問題