WIN API ReadFile() returns GetLastError() ERROR_INVALID_PARAMETER
WIN API ReadFile() returns GetLastError() ERROR_INVALID_PARAMETER
我在下面写了这段代码,它在 code::blocks 下使用 mingw gcc 4.7 编译它运行良好。从那以后,我决定开始使用 Visual Studio 2013 express。现在调用 ReadFile() 时出现错误。这似乎是一个无效参数。我看不到错误希望这里有人能发现它。
这一切都包含在一个 class 系列中。从我在 IDE 中看到的情况来看,与句柄的引用 CreateFile() returns 相比,m_hSerial 的内存引用是正确的。
m_hSerial = CreateFile(m_pchPort,
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
0);
我这样调用 WorkThread
m_hThread = (HANDLE)_beginthreadex(0, 0, &WorkThread, (void*) this, 0, 0);
这是 WorkThread 代码
unsigned int __stdcall Serial::WorkThread(void* pvParam)
{
// This is a pointer to the 'this' serial class.
// Needed to be able to set members of the class in a static class function
Serial * cThis = (Serial*) pvParam;
// Set up the overlapped event
OVERLAPPED ov;
memset(&ov, 0, sizeof(ov));
ov.hEvent = CreateEvent(0, true, 0, 0);
DWORD dwEventMask = 0;
DWORD dwWait;
HANDLE aHandles[2];
aHandles[0] = cThis->m_hThreadTerminator;
aHandles[1] = ov.hEvent;
SetEvent(cThis->m_hThreadRunning);
while (true)
{
if (!WaitCommEvent(cThis->m_hSerial, &dwEventMask, &ov))
{
assert(GetLastError() == ERROR_IO_PENDING);
}
dwWait = WaitForMultipleObjects(2, aHandles, FALSE, INFINITE);
switch(dwWait)
{
case WAIT_OBJECT_0:
{
_endthreadex(1);
}
case WAIT_OBJECT_0 + 1:
{
if (dwEventMask & EV_TXEMPTY)
{
ResetEvent(ov.hEvent);
}
else if (dwEventMask & EV_RXCHAR)
{
// read data here
DWORD dwBytesRead = 0;
DWORD dwErrors;
COMSTAT cStat;
OVERLAPPED ovRead;
ovRead.hEvent = CreateEvent(0, true, 0, 0);
// Get the Bytes in queue
ClearCommError(cThis->m_hSerial, &dwErrors, &cStat);
DWORD nSize = cStat.cbInQue;
// EM_REPLACESEL needs a LPARAM null terminated string, make room and set the CString NULL
char *szBuf = new char[nSize+1];
memset(szBuf, 0x00, sizeof(szBuf));
if (!ReadFile(cThis->m_hSerial, &szBuf, nSize, &dwBytesRead, &ovRead))
DWORD err = GetLastError();
if (dwBytesRead == nSize)
SendMessage(cThis->m_hHwnd, WM_SERIAL, 0, LPARAM(&szBuf));
CloseHandle(ovRead.hEvent); // clean up!!!
delete[] szBuf;
}
// Reset the overlapped event
ResetEvent(ov.hEvent);
}
break;
}//switch
}
return 0;
}
ReadFile(cThis->m_hSerial, &szBuf, nSize, &dwBytesRead, &ovRead)
你要求一个异步操作,而且要求函数告诉你已经读取了多少字节。您传递了 &dwBytesRead
作为倒数第二个参数。当您执行重叠读取时,为该参数传递NULL
。 documentation 表示:
Use NULL for this parameter if this is an asynchronous operation to avoid potentially erroneous results.
上面代码中传&szBuf
也是错误的。你的意思是通过 szBuf
.
您也无法初始化 OVERLAPPED
结构。这样做:
OVERLAPPED ovRead = {};
一个更大的问题是您要求异步访问,但随后编写了同步代码。一旦 ReadFile
returns 您尝试从 dwBytesRead
中获取有意义的信息,您就关闭了放置在重叠结构中的事件。
如果您真的要异步编写此代码,则需要重新编写异步代码。从表面上看,您似乎还没有完全理解重叠 I/O 的含义,您或许应该切换到非重叠的同步 I/O.
我在下面写了这段代码,它在 code::blocks 下使用 mingw gcc 4.7 编译它运行良好。从那以后,我决定开始使用 Visual Studio 2013 express。现在调用 ReadFile() 时出现错误。这似乎是一个无效参数。我看不到错误希望这里有人能发现它。
这一切都包含在一个 class 系列中。从我在 IDE 中看到的情况来看,与句柄的引用 CreateFile() returns 相比,m_hSerial 的内存引用是正确的。
m_hSerial = CreateFile(m_pchPort,
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
0);
我这样调用 WorkThread
m_hThread = (HANDLE)_beginthreadex(0, 0, &WorkThread, (void*) this, 0, 0);
这是 WorkThread 代码
unsigned int __stdcall Serial::WorkThread(void* pvParam)
{
// This is a pointer to the 'this' serial class.
// Needed to be able to set members of the class in a static class function
Serial * cThis = (Serial*) pvParam;
// Set up the overlapped event
OVERLAPPED ov;
memset(&ov, 0, sizeof(ov));
ov.hEvent = CreateEvent(0, true, 0, 0);
DWORD dwEventMask = 0;
DWORD dwWait;
HANDLE aHandles[2];
aHandles[0] = cThis->m_hThreadTerminator;
aHandles[1] = ov.hEvent;
SetEvent(cThis->m_hThreadRunning);
while (true)
{
if (!WaitCommEvent(cThis->m_hSerial, &dwEventMask, &ov))
{
assert(GetLastError() == ERROR_IO_PENDING);
}
dwWait = WaitForMultipleObjects(2, aHandles, FALSE, INFINITE);
switch(dwWait)
{
case WAIT_OBJECT_0:
{
_endthreadex(1);
}
case WAIT_OBJECT_0 + 1:
{
if (dwEventMask & EV_TXEMPTY)
{
ResetEvent(ov.hEvent);
}
else if (dwEventMask & EV_RXCHAR)
{
// read data here
DWORD dwBytesRead = 0;
DWORD dwErrors;
COMSTAT cStat;
OVERLAPPED ovRead;
ovRead.hEvent = CreateEvent(0, true, 0, 0);
// Get the Bytes in queue
ClearCommError(cThis->m_hSerial, &dwErrors, &cStat);
DWORD nSize = cStat.cbInQue;
// EM_REPLACESEL needs a LPARAM null terminated string, make room and set the CString NULL
char *szBuf = new char[nSize+1];
memset(szBuf, 0x00, sizeof(szBuf));
if (!ReadFile(cThis->m_hSerial, &szBuf, nSize, &dwBytesRead, &ovRead))
DWORD err = GetLastError();
if (dwBytesRead == nSize)
SendMessage(cThis->m_hHwnd, WM_SERIAL, 0, LPARAM(&szBuf));
CloseHandle(ovRead.hEvent); // clean up!!!
delete[] szBuf;
}
// Reset the overlapped event
ResetEvent(ov.hEvent);
}
break;
}//switch
}
return 0;
}
ReadFile(cThis->m_hSerial, &szBuf, nSize, &dwBytesRead, &ovRead)
你要求一个异步操作,而且要求函数告诉你已经读取了多少字节。您传递了 &dwBytesRead
作为倒数第二个参数。当您执行重叠读取时,为该参数传递NULL
。 documentation 表示:
Use NULL for this parameter if this is an asynchronous operation to avoid potentially erroneous results.
上面代码中传&szBuf
也是错误的。你的意思是通过 szBuf
.
您也无法初始化 OVERLAPPED
结构。这样做:
OVERLAPPED ovRead = {};
一个更大的问题是您要求异步访问,但随后编写了同步代码。一旦 ReadFile
returns 您尝试从 dwBytesRead
中获取有意义的信息,您就关闭了放置在重叠结构中的事件。
如果您真的要异步编写此代码,则需要重新编写异步代码。从表面上看,您似乎还没有完全理解重叠 I/O 的含义,您或许应该切换到非重叠的同步 I/O.