CSerialPort class problem and Error 87
Hello.
First, I'd like you to take a look at this post from 2 years ago on this forum: http://www.dev-archive.com/forum/showthread.php?threadid=193904 (it explains the problem with CSerialPort -- this should also be brought to the attention of the authors of the class)
Anyway, I came across the exact same problem, except I was not using the class. I simply had WaitCommEvent and GetLastError() give me the same error 87 using this piece of code:
if (WaitCommEvent(hCom, &event, &obj))
{
cout << "Character Detected! ";
fsuccess = ReadFile (hCom, &data, 1, &transferred, &obj);
if (fsuccess)
cout << "Character Read! Here it is: " << data;
getch();
}
else
{
if (GetLastError() == ERROR_IO_PENDING)
cout << "Still waiting";
else
{
cout << "Fatal error: " << GetLastError();
getch();
exit(1);
}
}
As I said, the output for this program is Fatal error: 87. I should explain, this is after the COM1 port has been opened successfully for reading. Does anyone have any suggestions as to how to solve this? I will be very thankful if someone could help.
Thanks..
# 1 Re: CSerialPort class problem and Error 87
Well, 87 is ERROR_INVALID_PARAMETER...
What are your hCom, event and obj?
# 2 Re: CSerialPort class problem and Error 87
Thanks for the reply. Well, see, the link above explains the problem: "Error 87 is bad parameter, and in this case is returned from GetLastError() when a call to WaitCommEvent() using overlapped IO is made using an OVERLAPPED structure made in a previous call to WaitCommEvent() which hasn't finished yet. Read MSDN on WaitCommEvent()."
Not very descriptive, but gives the general idea.
My hCom is just a CreateFile handle for the serial port, while event is a DWORD that is assigned EV_RXCHAR (DWORD event = EV_RXCHAR; is a line in my code), which is the event I want to check for, and data is the buffer, which is just a BYTE. I attached my whole program, if you want to try to see if there's anything else that sticks out to you. The only thing I'm uncomfortable with is that my "data" variable is a BYTE, and so the ReadFile buffer is technically only one byte long, so that might be causing a problem with overloading and such -- but I doubt that's it, since I use the data variable right away and then ReadFile can redefine it on the next go-around in the loop.
Hope that clarifies things - again, your help is greatly appreciated.
# 3 Re: CSerialPort class problem and Error 87
Well...the second parameter of 'WaitCommEvent()' is an 'out'-parameter...in other words it will be set from inside the function. Pass an pointer to a empty DWORD instead...
DWORD event = 0;
WaitCommEvent(hCom, &event, &obj);
# 4 Re: CSerialPort class problem and Error 87
Originally posted by Andreas Masur
Well...the second parameter of 'WaitCommEvent()' is an 'out'-parameter...in other words it will be set from inside the function. Pass an pointer to a empty DWORD instead...
DWORD event = 0;
WaitCommEvent(hCom, &event, &obj);
I don't understand -- isn't WaitCommEvent supposed to wait FOR the event? How could it know what to wait for if I don't preset that?
Or is that what SetCommMask does?
# 5 Re: CSerialPort class problem and Error 87
Originally posted by Programmer02012
I don't understand -- isn't WaitCommEvent supposed to wait FOR the event? How could it know what to wait for if I don't preset that?
Or is that what SetCommMask does?
From MSDN:
The WaitCommEvent function monitors a set of events for a specified communications resource. To set and query the current event mask of a communications resource, use the SetCommMask and GetCommMask functions.
# 6 Re: CSerialPort class problem and Error 87
Yes, okay.
So SetCommMask sets the event and that same event is sent to WaitCommEvent, correct? How could setting the event empty and sending it to WaitCommEvent AFTER calling SetCommMask have any use then? Isn't that just counteracting what SetCommMask just did?
Any help with the error 87 issue is also appreciated, by the way - the seemingly overlapped object overuse.
# 7 Re: CSerialPort class problem and Error 87
Originally posted by Programmer02012
How could setting the event empty and sending it to WaitCommEvent AFTER calling SetCommMask have any use then? Isn't that just counteracting what SetCommMask just did?
Well...if you want to wait for three different events, you would be happy if you know which event of the three actual occurred if 'WaitComState()' returns, right? :cool:
Originally posted by Programmer02012
Any help with the error 87 issue is also appreciated, by the way - the seemingly overlapped object overuse.
I expected the mentioned to be gone after the change... :confused:
# 8 Re: CSerialPort class problem and Error 87
Okay, gotcha. So you want me to modify my code such that I have a DWORD event declared, then call SetCommMask, and then set the event to 0, and then finally call WaitCommEvent, right?
In other words, instead of:
DWORD event = EV_RXCHAR;
[...]
SetCommMask(hCom, event)
[...]
WaitCommEvent(hCom, &event, &obj)
I should do:
DWORD event = 0;
[...]
SetCommMask(hCom, EV_RXCHAR)
[...]
WaitCommEvent(hCom, &event, &obj)
Right?
Thanks a lot for your help, by the way. I was just concerned because your fix did not seem to mention the obj variable, which I thought was what was causing the problem.
# 9 Re: CSerialPort class problem and Error 87
No such luck... I tried the fix you suggested as implemented per my last post, and the result was the same... error 87.
Could anything else be causing this? What do I have to do to get my program to read a darned character from the serial port? :(
# 10 Re: CSerialPort class problem and Error 87
Okay, I tried something new here. I read over the post from that thread above, where the guy suggests that you should wait for the first event to finish before checking it again to avoid that pesky error 87.
So I inserted a bit of code with a boolean flag and WaitForSingleObject so now my main line of code looks like this:
BOOL obj_flag = true;
while (true)
{
if (obj_flag)
{
if (WaitCommEvent(hCom, &event, &obj))
{
cout << "Character Detected! ";
fsuccess = ReadFile (hCom, &data, 1, &transferred, &obj);
if (fsuccess)
cout << "Character Read! Here it is: " << data;
getch();
}
else
{
if (GetLastError() == ERROR_IO_PENDING)
{
cout << "Still waiting";
obj_flag = false;
}
else
{
cout << "Fatal error: " << GetLastError();
getch();
exit(1);
}
}
}
switch (WaitForSingleObject(hCom, INFINITE))
{
case WAIT_OBJECT_0:
obj_flag = true;
break;
case WAIT_ABANDONED_0:
cout << "What happened?";
break;
case WAIT_FAILED:
cout << "WFSO Failed due to error: " << GetLastError();
break;
default:
cout << "This code should never be reached.";
}
cout << endl << "End of infinite loop..." << endl;
getch();
}
Basically, if the ERROR_IO_PENDING error comes up, I set the flag to false, so WaitCommEvent isn't called again, and call WaitForSingleObject with the port handle. However, upon executing, it seems that WaitForSingleObject never terminates (I set the time limit to INFINITE), and the program never ends. I tried changing this to calling WaitForSingleObject with obj.hEvent, which was the event created for the overlapped object. However, this yielded the same result.
Any ideas on how to fix this? Thanks for your help. (I also attached the modified version of my program with this post)
