Discussion:
POSSIBLE BUG : WriteFile/ReadFile block threads in MFC applications
(too old to reply)
Selin Metin
2003-10-13 09:19:48 UTC
Permalink
Hi everyone,

In Windows CE .NET 4.1 I found out that whatever way I choose I can't manage
to get WriteFile or ReadFile to work properly to communicate from serial
ports. The problem is whether I begin with a MFC AppWizard(exe) or write an
MFC class directly and choose "use MFC as a shared dll", the thread in which
I call WriteFile or ReadFile is blocked. I tested this by writing more than
10 test applications, creating seperate threads, using them in the same
thread, etc. I suspected that using SetCommMask and WaitCommEvent is
blocking these threads (and I found only one posting that is pointing to
this), but not using them did not help either. I can easily open the port
with CreateFile, the handle is always valid (I never lose it). CloseHandle
works fine, too. Also these 4 API functions (CreateFile, WriteFile,
ReadFile, CloseHandle) function flawlessly when I open and modify any text
file (.txt extension). Only when I try to access the serial ports using
WriteFile/ReadFile, my threads are blocked. I can work with the user
interface (menus, etc) if they are in a seperate thread. My eVC code works
properly when I port it to Win32, so I'm not using erroneous codes.

I could not find a solution to this problem. I reinstalled PB, recreated my
platform and nothing is changed.

In the past weeks I have posted a couple of messages about this problem to
these newsgroups. Unfortunately I have not received a satisfying answer yet.
So I'm thinking of reporting this as a bug in Windows CE .NET 4.1.

If anyone of you could succeed in creating a serial communication
application using MFC with CE 4.1, I beg from him/her to give me any hints.
I guess that there are people who use this, for if it is a bug in MFCCE, it
is such a basic and important problem that I should not be the first one to
notice this.

Best regards,
Selin Metin
Offir Bakshitz
2003-10-13 13:01:01 UTC
Permalink
I use CE 4.0 / 4.1 / 4.2 to read/write from Serial ports using
Write/ReadFile() in a threaded application without a problem.
Perhaps I did not understand you correctly, but you must realize that
ReadFile or WriteFile would block if the device is not ready for writing or
when there is no character ready to be read from the serial port.
You can change this behaviour by using SetCommTimeouts to get timeout events
instead of blocking the thread. You can also use GetCommState to determine
if a call to ReadFile would block (meaning to check if there is a character
waiting to be read).
Maybe you COM port registry keys (in Platform.reg) are not configured
correctly (to the correct address / IRQ) and for this reason you are unable
to read/write from the COM ports?

Offir.
Selin Metin
2003-10-13 13:38:49 UTC
Permalink
I have already tested all the meaningful timeout values with the
SetCommTimeouts. Also I know that there's data waiting on the serial port. I
use SetCommState and GetCommState to configure the device. I check for every
possible error that might occur before WriteFile/ReadFile is called.
Interesting point is, I can use the same serial communication code (dcb
settings, timeout values, port open, write, read etc.) in wce api
applications without any problem. Actually this code was originally copied
from such an application. Basically I do this:
////////////////////////////////////////////////////
UINT CMyDialog::OnThreadWrite(LPVOID pvParam)
{
CMyDialog *pMyDialog = reinterpret_cast<CMyDialog *> (pvParam);

DCB PortDCB;
COMMTIMEOUTS CommTimeouts;
HANDLE hPort;

if (INVALID_HANDLE_VALUE == (hPort = CreateFile(TEXT("COM2:"),
GENERIC_READ|GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0)))
return 0;

// Set the port.
PortDCB.DCBlength = sizeof(DCB);
GetCommState(hPort, &PortDCB);
PortDCB.BaudRate = CBR_1200;
PortDCB.fBinary = TRUE;
PortDCB.fParity = TRUE;
PortDCB.fOutxCtsFlow = FALSE; // ignore possible hangups
PortDCB.fOutxDsrFlow = FALSE; // don't wait on the DSR line
PortDCB.fDtrControl = DTR_CONTROL_DISABLE;
PortDCB.fDsrSensitivity = FALSE;
PortDCB.fTXContinueOnXoff = TRUE;
PortDCB.fOutX = FALSE; // no XON/XOFF control
PortDCB.fInX = FALSE;
PortDCB.fErrorChar = FALSE;
PortDCB.fNull = FALSE;
PortDCB.fRtsControl = RTS_CONTROL_DISABLE;
PortDCB.fAbortOnError = FALSE;
PortDCB.ByteSize = 8;
PortDCB.Parity = NOPARITY;
PortDCB.StopBits = ONESTOPBIT;
if (!SetCommState(hPort, &PortDCB))
printf("SetCommState fails!..\n");

// Set comm timeouts (nonblocking read, and write waiting for completion).
GetCommTimeouts(hPort, &CommTimeouts);
CommTimeouts.ReadIntervalTimeout = 0;
CommTimeouts.ReadTotalTimeoutMultiplier = 0;
CommTimeouts.ReadTotalTimeoutConstant = 0;
CommTimeouts.WriteTotalTimeoutMultiplier = 0;
CommTimeouts.WriteTotalTimeoutConstant = 0;
SetCommTimeouts(hPort, &CommTimeouts);

for (int i = 0; i < 20; ++i) {
char ch = 'A' + i;
DWORD len;

if (!WriteFile(hPort, &ch, 1, &len, NULL)) {
AfxMessageBox(L"Cannot write port!..");
return 0;
}

if (len != 1) {
AfxMessageBox(L"Cannot write port!..");
return 0;
}

::Sleep(100);
}
::CloseHandle(hPort);

return 0;
}
////////////////////////////////////////////////////
This code works with no problem in Win32. The same code (without the
CMyDialog part) works flawlessly in wce api. But with mfcce I never get this
to work!

Is there a different registry setting for api and mfc applications in
platform reg (sounds stupid)?
Marcus N
2003-10-13 15:55:02 UTC
Permalink
Well, I do have an MFC application running which uses the COM-port to write
data. I saw your code was missing one call that I've made: SetupComm() is
called after CreateFile, and way before I do a WriteFile(). SetupComm
initialises the buffers, read about it in the docs. Maybe it has something
to do with your problem, I do not know.

Otherwise, I do like this in a dialog-based MFC-app:
CreateFile()

SetupComm()

GetCommState()

manipulate DCB structure from GetCommState()

SetCommState()

and then I can call WriteFile() with success!

/Marcus
Post by Selin Metin
I have already tested all the meaningful timeout values with the
SetCommTimeouts. Also I know that there's data waiting on the serial port. I
use SetCommState and GetCommState to configure the device. I check for every
possible error that might occur before WriteFile/ReadFile is called.
Interesting point is, I can use the same serial communication code (dcb
settings, timeout values, port open, write, read etc.) in wce api
applications without any problem. Actually this code was originally copied
////////////////////////////////////////////////////
UINT CMyDialog::OnThreadWrite(LPVOID pvParam)
{
CMyDialog *pMyDialog = reinterpret_cast<CMyDialog *> (pvParam);
DCB PortDCB;
COMMTIMEOUTS CommTimeouts;
HANDLE hPort;
if (INVALID_HANDLE_VALUE == (hPort = CreateFile(TEXT("COM2:"),
GENERIC_READ|GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0)))
return 0;
// Set the port.
PortDCB.DCBlength = sizeof(DCB);
GetCommState(hPort, &PortDCB);
PortDCB.BaudRate = CBR_1200;
PortDCB.fBinary = TRUE;
PortDCB.fParity = TRUE;
PortDCB.fOutxCtsFlow = FALSE; // ignore possible hangups
PortDCB.fOutxDsrFlow = FALSE; // don't wait on the DSR line
PortDCB.fDtrControl = DTR_CONTROL_DISABLE;
PortDCB.fDsrSensitivity = FALSE;
PortDCB.fTXContinueOnXoff = TRUE;
PortDCB.fOutX = FALSE; // no XON/XOFF control
PortDCB.fInX = FALSE;
PortDCB.fErrorChar = FALSE;
PortDCB.fNull = FALSE;
PortDCB.fRtsControl = RTS_CONTROL_DISABLE;
PortDCB.fAbortOnError = FALSE;
PortDCB.ByteSize = 8;
PortDCB.Parity = NOPARITY;
PortDCB.StopBits = ONESTOPBIT;
if (!SetCommState(hPort, &PortDCB))
printf("SetCommState fails!..\n");
// Set comm timeouts (nonblocking read, and write waiting for
completion).
Post by Selin Metin
GetCommTimeouts(hPort, &CommTimeouts);
CommTimeouts.ReadIntervalTimeout = 0;
CommTimeouts.ReadTotalTimeoutMultiplier = 0;
CommTimeouts.ReadTotalTimeoutConstant = 0;
CommTimeouts.WriteTotalTimeoutMultiplier = 0;
CommTimeouts.WriteTotalTimeoutConstant = 0;
SetCommTimeouts(hPort, &CommTimeouts);
for (int i = 0; i < 20; ++i) {
char ch = 'A' + i;
DWORD len;
if (!WriteFile(hPort, &ch, 1, &len, NULL)) {
AfxMessageBox(L"Cannot write port!..");
return 0;
}
if (len != 1) {
AfxMessageBox(L"Cannot write port!..");
return 0;
}
::Sleep(100);
}
::CloseHandle(hPort);
return 0;
}
////////////////////////////////////////////////////
This code works with no problem in Win32. The same code (without the
CMyDialog part) works flawlessly in wce api. But with mfcce I never get this
to work!
Is there a different registry setting for api and mfc applications in
platform reg (sounds stupid)?
Selin Metin
2003-10-16 11:50:09 UTC
Permalink
The problem is this:

If I use the COMMTIMEOUTS structure with the following values:

CommTimeouts.ReadIntervalTimeout = MAXDWORD;
CommTimeouts.ReadTotalTimeoutMultiplier = 0;
CommTimeouts.ReadTotalTimeoutConstant = 0;
CommTimeouts.WriteTotalTimeoutMultiplier = 0;
CommTimeouts.WriteTotalTimeoutConstant = 0;

ReadFile or WriteFile waits forever for an event to occur at the com port.
If I change the timeout values as the following:

CommTimeouts.ReadIntervalTimeout = 0;
CommTimeouts.ReadTotalTimeoutMultiplier = 1;
CommTimeouts.ReadTotalTimeoutConstant = 1;
CommTimeouts.WriteTotalTimeoutMultiplier = 10;
CommTimeouts.WriteTotalTimeoutConstant = 10;

ReadFile and WriteFile timeout for they receive or send no data.

I checked my ports with other programs, with leds, with CE API applications.
Only if I try to use com ports from a MFC application, this problem occurs.
Otherwise everything is just fine.

Although most of you declare that nothing is wrong with MFC, this problem is
related with the MFC library. The functions just don't do anything with the
hardware ports. The handle to the port is not invalid, but the application
cannot address the port and communicate with it.

Can anyone clearly define the steps to create an MFC application which
communicates with the serial ports using PB? I'm sure what I do is not
wrong, but I'd rather check it.

Thanks again.
Selin
Chris Tacke, eMVP
2003-10-16 17:04:15 UTC
Permalink
At this point I think I'd scrap the MFC classes, wrap the APIs myself and go
from there. Why fight a bug in MFC when writing it right to the APIs is
simple enough?
--
Chris Tacke, eMVP
Advisory Board Member
www.OpenNETCF.org
---
Windows CE Product Manager
Applied Data Systems
www.applieddata.net
Post by Selin Metin
CommTimeouts.ReadIntervalTimeout = MAXDWORD;
CommTimeouts.ReadTotalTimeoutMultiplier = 0;
CommTimeouts.ReadTotalTimeoutConstant = 0;
CommTimeouts.WriteTotalTimeoutMultiplier = 0;
CommTimeouts.WriteTotalTimeoutConstant = 0;
ReadFile or WriteFile waits forever for an event to occur at the com port.
CommTimeouts.ReadIntervalTimeout = 0;
CommTimeouts.ReadTotalTimeoutMultiplier = 1;
CommTimeouts.ReadTotalTimeoutConstant = 1;
CommTimeouts.WriteTotalTimeoutMultiplier = 10;
CommTimeouts.WriteTotalTimeoutConstant = 10;
ReadFile and WriteFile timeout for they receive or send no data.
I checked my ports with other programs, with leds, with CE API
applications.
Post by Selin Metin
Only if I try to use com ports from a MFC application, this problem occurs.
Otherwise everything is just fine.
Although most of you declare that nothing is wrong with MFC, this problem is
related with the MFC library. The functions just don't do anything with the
hardware ports. The handle to the port is not invalid, but the application
cannot address the port and communicate with it.
Can anyone clearly define the steps to create an MFC application which
communicates with the serial ports using PB? I'm sure what I do is not
wrong, but I'd rather check it.
Thanks again.
Selin
Doug Forster
2003-10-17 03:52:41 UTC
Permalink
Hi Selin,

Do you actually use the pMyDialog pointer in your real code? You do know
that passing MFC objects across thread boundaries is strictly a nono ?
Different environment, but I've had no problems doing serial programming in
an MFC app on PPC2002, 2003 via eVC3, eVC4

Cheers

Doug Forster
Post by Selin Metin
CommTimeouts.ReadIntervalTimeout = MAXDWORD;
CommTimeouts.ReadTotalTimeoutMultiplier = 0;
CommTimeouts.ReadTotalTimeoutConstant = 0;
CommTimeouts.WriteTotalTimeoutMultiplier = 0;
CommTimeouts.WriteTotalTimeoutConstant = 0;
ReadFile or WriteFile waits forever for an event to occur at the com port.
CommTimeouts.ReadIntervalTimeout = 0;
CommTimeouts.ReadTotalTimeoutMultiplier = 1;
CommTimeouts.ReadTotalTimeoutConstant = 1;
CommTimeouts.WriteTotalTimeoutMultiplier = 10;
CommTimeouts.WriteTotalTimeoutConstant = 10;
ReadFile and WriteFile timeout for they receive or send no data.
I checked my ports with other programs, with leds, with CE API
applications.
Post by Selin Metin
Only if I try to use com ports from a MFC application, this problem occurs.
Otherwise everything is just fine.
Although most of you declare that nothing is wrong with MFC, this problem is
related with the MFC library. The functions just don't do anything with the
hardware ports. The handle to the port is not invalid, but the application
cannot address the port and communicate with it.
Can anyone clearly define the steps to create an MFC application which
communicates with the serial ports using PB? I'm sure what I do is not
wrong, but I'd rather check it.
Thanks again.
Selin
Selin Metin
2003-10-17 10:29:35 UTC
Permalink
No, pMyDialog is used only in that function and only to send WM_USER message
to another function of the same thread. It is not being passed to anywhere
else. And you must remember that the code I sent in this ng thread is only
one of the many trial codes I created, it is not my actual application.

And I agree with Chris's comment about forgetting MFC and doing it in API.
But I've already done many things in MFC and this serial communication is
just one aspect of my application. I'm reluctant to go back to API because
of this and also I find MFC more practical while organizing the user
interface of my application. Going back to API will cause some time loss
too, and I'm in a dilemma whether to choose to write in API or to wait
hopefully for a cure to occur. Anyway, that is still my last chance.
Besides, calling serial communication API functions from any MFC class /
function results in timeouts or thread blocks. As far as I can understand,
the mfcce400(d).dll is loaded when I start my application and something in
this library module prevents the serial communication. This library is not
active when I run any API functions on the same platform image and so I can
communicate with the ports.

I welcome any ideas about the handling of this problem or about using MFC
and API together.
Post by Doug Forster
Hi Selin,
Do you actually use the pMyDialog pointer in your real code? You do know
that passing MFC objects across thread boundaries is strictly a nono ?
Different environment, but I've had no problems doing serial programming in
an MFC app on PPC2002, 2003 via eVC3, eVC4
Cheers
Doug Forster
Doug Forster
2003-10-19 19:51:13 UTC
Permalink
Hi Selin,

Are you saying that your serial code still fails if it makes no reference at
all to any MFC objects (CDialog, AfxMessageBox etc etc) . It is fairly hard
to see how serial io could possibly interact with MFC. Despite what you say
I would still suspect you might be using MFC objects inadvertantly across a
thread boundary.

Cheers

Doug Forster
Post by Selin Metin
No, pMyDialog is used only in that function and only to send WM_USER message
to another function of the same thread. It is not being passed to anywhere
else. And you must remember that the code I sent in this ng thread is only
one of the many trial codes I created, it is not my actual application.
And I agree with Chris's comment about forgetting MFC and doing it in API.
But I've already done many things in MFC and this serial communication is
just one aspect of my application. I'm reluctant to go back to API because
of this and also I find MFC more practical while organizing the user
interface of my application. Going back to API will cause some time loss
too, and I'm in a dilemma whether to choose to write in API or to wait
hopefully for a cure to occur. Anyway, that is still my last chance.
Besides, calling serial communication API functions from any MFC class /
function results in timeouts or thread blocks. As far as I can understand,
the mfcce400(d).dll is loaded when I start my application and something in
this library module prevents the serial communication. This library is not
active when I run any API functions on the same platform image and so I can
communicate with the ports.
I welcome any ideas about the handling of this problem or about using MFC
and API together.
Post by Doug Forster
Hi Selin,
Do you actually use the pMyDialog pointer in your real code? You do know
that passing MFC objects across thread boundaries is strictly a nono ?
Different environment, but I've had no problems doing serial programming
in
Post by Doug Forster
an MFC app on PPC2002, 2003 via eVC3, eVC4
Cheers
Doug Forster
mocad_tom
2003-10-31 13:16:41 UTC
Permalink
Perhaps you try this site:

http://vermeij.filternet.nl/programmer/rawir.html

I saw that your code looks a little bit similar, he describes
everything quite good. I must write a IrDA-comm-programm in the next 2
or 3 months as well. Could you write an answer when the site helped
you.

Thanks!
Tom
Post by Selin Metin
No, pMyDialog is used only in that function and only to send WM_USER message
to another function of the same thread. It is not being passed to anywhere
else. And you must remember that the code I sent in this ng thread is only
one of the many trial codes I created, it is not my actual application.
And I agree with Chris's comment about forgetting MFC and doing it in API.
But I've already done many things in MFC and this serial communication is
just one aspect of my application. I'm reluctant to go back to API because
of this and also I find MFC more practical while organizing the user
interface of my application. Going back to API will cause some time loss
too, and I'm in a dilemma whether to choose to write in API or to wait
hopefully for a cure to occur. Anyway, that is still my last chance.
Besides, calling serial communication API functions from any MFC class /
function results in timeouts or thread blocks. As far as I can understand,
the mfcce400(d).dll is loaded when I start my application and something in
this library module prevents the serial communication. This library is not
active when I run any API functions on the same platform image and so I can
communicate with the ports.
I welcome any ideas about the handling of this problem or about using MFC
and API together.
Hari
2003-10-13 18:40:32 UTC
Permalink
Selin,
It is possible that you are trying to use interleaved
serial I/O. Windows CE does not support this. All serial
I/O is non interleaved i.e: all read/writes are blocked
operations. I worked around this by having a dedicated
reader and writer thread. The reader thread blocks on read
with a time out, sleaps for some time and loops back into
a read.
Let me know if this helps.
- Hari
-----Original Message-----
Hi everyone,
In Windows CE .NET 4.1 I found out that whatever way I
choose I can't manage
to get WriteFile or ReadFile to work properly to
communicate from serial
ports. The problem is whether I begin with a MFC AppWizard
(exe) or write an
MFC class directly and choose "use MFC as a shared dll",
the thread in which
I call WriteFile or ReadFile is blocked. I tested this by
writing more than
10 test applications, creating seperate threads, using
them in the same
thread, etc. I suspected that using SetCommMask and
WaitCommEvent is
blocking these threads (and I found only one posting that
is pointing to
this), but not using them did not help either. I can
easily open the port
with CreateFile, the handle is always valid (I never lose
it). CloseHandle
works fine, too. Also these 4 API functions (CreateFile,
WriteFile,
ReadFile, CloseHandle) function flawlessly when I open
and modify any text
file (.txt extension). Only when I try to access the
serial ports using
WriteFile/ReadFile, my threads are blocked. I can work
with the user
interface (menus, etc) if they are in a seperate thread.
My eVC code works
properly when I port it to Win32, so I'm not using
erroneous codes.
I could not find a solution to this problem. I
reinstalled PB, recreated my
platform and nothing is changed.
In the past weeks I have posted a couple of messages
about this problem to
these newsgroups. Unfortunately I have not received a
satisfying answer yet.
So I'm thinking of reporting this as a bug in Windows
CE .NET 4.1.
If anyone of you could succeed in creating a serial
communication
application using MFC with CE 4.1, I beg from him/her to
give me any hints.
I guess that there are people who use this, for if it is
a bug in MFCCE, it
is such a basic and important problem that I should not
be the first one to
notice this.
Best regards,
Selin Metin
.
Selin Metin
2003-10-14 09:09:44 UTC
Permalink
I have a main thread which controls the user interface operations (dialogs
etc), one thread for reading and one thread for writing. The read and write
threads are blocked but the main thread is working. I tried the readtimeout
value from 0 to 1000, that didn't change the result.

I also tried to use the setupcomm function, which didn't help either. In the
API version of my application I don't use it and it works fine.

I have already tried reinstalling platform builder. Now I'm thinking of
formatting my development pc and reinstalling everything (which will be
"very" painful). If I hadn't communicated with the API application, this
would have been my first choice.

Since some of you have managed to use serial ports with MFC, it should not
be a WinCE bug. But I know that I'm not doing anything wrong. Any more
ideas?
Post by Hari
Selin,
It is possible that you are trying to use interleaved
serial I/O. Windows CE does not support this. All serial
I/O is non interleaved i.e: all read/writes are blocked
operations. I worked around this by having a dedicated
reader and writer thread. The reader thread blocks on read
with a time out, sleaps for some time and loops back into
a read.
Let me know if this helps.
- Hari
Loading...