2011-10-05 15 views
7

Estoy abriendo un puerto serie usando CreateFile(). Tengo un caso de prueba (demasiado complicado para redistribuir) que ocasiona que CreateFile() devuelva INVALID_HANDLE_VALUE y GetLastError() para devolver ERROR_SUCCESS. Por lo que parece, este error solo ocurre si un hilo abre el puerto al mismo tiempo que otro puerto lo cierra. El hilo que abre el puerto corre a través de este problema.CreateFile() devuelve INVALID_HANDLE_VALUE pero GetLastError() es ERROR_SUCCESS

No sé si esto hace la diferencia, pero más adelante en el código asocio el puerto con un CompletionPort usando CreateIoCompletionPort.

Aquí está mi código:

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; 
} 

Estoy bastante seguro de este tipo de cosas no debería suceder. ¿Estoy haciendo algo mal? ¿Cómo obtengo la API para devolver un resultado correcto?


más detalles de: Este código se toma de una biblioteca de puerto serie que he desarrollado: JPeripheral

Aquí es el real (unsanitized) el código fuente:

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); 
} 

Aquí está la salida real que recibo:

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

¿Son estas líneas las exactas que está utilizando en su prueba? Cualquier simplificación (incluso aparentemente inofensiva) podría ocultar el origen del problema. –

+0

¿Cuál es el hardware al que está accediendo? – Gabe

+0

@Gabe: estoy accediendo a un dispositivo integrado que hemos desarrollado internamente. Tiene una conexión estándar de puerto serie DB9 que he conectado a mi PC (no hay adaptadores USB-RS232 aquí). – Gili

Respuesta

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

La salida a cerr invoca llamadas winapi bajo el capó. Lo cual restablecerá el valor de error de subproceso devuelto por GetLastError(). Solución:

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

No estoy convencido. El código original que tenía este problema no contenía ninguna instrucción 'cerr'. Solo agregué eso recientemente. ¿Ves algo mal con el código anterior (menos 'cerr')? – Gili

+1

El rastreo de salida que mostró solo puede ser generado por el código que * no * daña el valor GetLastError. No dudo que pueda fallar, hay muchas razones para abrir un puerto COM para que falle. –

+0

Tenías razón. El código original invocado 'throw IOException (jace :: java_new (L" CreateFile() falló con el error: "+ getErrorMessage (GetLastError()))'. Observe la cantidad de código existente entre el punto de falla y la lectura de 'GetLastError() '. Leyendo el valor antes solucionado el problema. Gracias! – Gili

Cuestiones relacionadas