winapi - CreateFile() devuelve INVALID_HANDLE_VALUE pero GetLastError() es ERROR_SUCCESS
serial-port iocp (1)
Estoy abriendo un puerto serie usando CreateFile () . Tengo un caso de prueba (demasiado complicado para redistribuir) que causa constantemente 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.
No sé si esto hace la diferencia, pero más adelante en el código asocio el puerto con un CompletionPort utilizando 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 que este tipo de cosas no deberían suceder. ¿Estoy haciendo algo mal? ¿Cómo obtengo la API para devolver un resultado correcto?
MÁS DETALLES : Este código está tomado de una biblioteca de puertos serie que he desarrollado: JPeripheral
Aquí está el código fuente real (no optimizado):
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á el resultado real que obtengo:
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.
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 (). Fijar:
HANDLE port = CreateFile(...);
int err = GetLastError();
// etc, use err instead...