问题描述
我正在使用 CreateFile( ).我有一个测试用例(太复杂,无法重新分配),该用例始终导致CreateFile()
返回INVALID_HANDLE_VALUE
和GetLastError()
返回ERROR_SUCCESS
.从外观上看,仅当一个线程在另一个端口关闭端口的同时打开该端口时,才会发生此错误.打开端口的线程遇到了这个问题.
I am opening a serial port using CreateFile(). I've got a testcase (too complicated to redistribute) that consistently causes CreateFile()
to return INVALID_HANDLE_VALUE
and GetLastError()
to return ERROR_SUCCESS
. By the looks of it, this bug only occurs if one thread opens the port at the exact same time that another port closes it. The thread opening the port runs across this problem.
我不知道这是否有所不同,但是稍后在代码中,我使用CreateIoCompletionPort .
I don't know if this makes a difference, but later on in the code I associate the port with a CompletionPort using CreateIoCompletionPort.
这是我的代码:
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以返回正确的结果?
I'm pretty sure this sort of thing should not happen. Am I doing anything wrong? How do I get the API to return a correct result?
更多详细信息:此代码摘自我开发的串行端口库: JPeripheral
MORE DETAILS: This code is taken from a serial-port library I've developed: JPeripheral
这是实际的(未消毒的)源代码:
Here is the actual (unsanitized) source-code:
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);
}
这是我得到的实际输出:
Here is the actual output I get:
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();
cerr的输出在后台调用winapi调用.这将重置由GetLastError()返回的线程错误值.修复:
The output to cerr invokes winapi calls under the hood. Which will reset the thread error value returned by GetLastError(). Fix:
HANDLE port = CreateFile(...);
int err = GetLastError();
// etc, use err instead...
这篇关于CreateFile()返回INVALID_HANDLE_VALUE,但GetLastError()为ERROR_SUCCESS的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!