Click to See Complete Forum and Search --> : OVERLAPPED mode


zariostr
August 16th, 2004, 01:39 PM
hi
can somebody tell me some theory about overlapped mode and events
how read/write data in it and use events ?

thanks

pinzo
August 17th, 2004, 06:33 AM
Well, I'll try my best ;-)

Let's see... when you open a file with CreateFile or similar you must set the FILE_FLAG_OVERLAPPED flag (note that this is not available in win9X for regular files, but it is for sockets or COMs).
Now, every call to ReadFile or WriteFile MUST specify a valid OVERLAPPED structure. Then the following things can happen:
1. ReadFile/WriteFile returns TRUE: the operation completed succesfully.
2. ReadFile/WriteFile returns FALSE. You must call GetLastError()
2a. GetLastError() returns ERROR_IO_PENDING: the operation is pending (see below)
2b. GetLastError() return another error code: an error happened.

If 2a happened you have an overlapped operation in course. Eventually it will finish and the event into the overlapped structure will be signaled. Then you must call GetOverlappedResult() to get the result of the operation.

Let's see some sample code:

----------------8<---------------

HANDLE hFile = CreateFile(... FILE_FLAG_OVERLAPPED ...);
OVERLAPPED ovl;
memset(&ovl, o, sizeof(ovl));
ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); //Manual event
ovl.Offset = ...; // meanigless for sockets, COMs, pipes. Useful for regular files
DWORD read = 0;
BOOL bRes = ReadFile(hFile, buffer, bytes, &read, &ovl);
if (bRes)
ProcessBytes(buffer, read);
else
{
DWORD gle = GetLastError();
if (gle!=ERROR_IO_PENDING)
Error(gle);
else
{ // Overlapped operation!
// you can execute other code while the read is in progress
....
bRes = GetOverlappedResult(hFile, &ovl, &read, TRUE);
if (bRes)
ProcessBytes(buffer, read);
else
Error(GetLastError());
}
}

----------------8<---------------

And some points to remember:
1. Don't forget to CloseHandle the event when you finish with the ovelapped structure.
2. You can issue several overlapped operations at the same time (that is, overlapping), but you must allocate one different OVERLAPPED struct and event for each one.
3. When an overlapped operation ends the system signals the event, so you can wait for it with WaitForSingleObject or WaitForMultipleObjects, but you must nevertheless call GetOverlappedResult to get the result of the operation.

Well, I think this is enoug for now... if in trouble, just ask.

HTH.

zariostr
August 21st, 2004, 08:58 AM
hi
thanks for reply
another question about overlap
does i need create 2 overlapped structure for read and write
or i can use one ?

pinzo
September 3rd, 2004, 07:05 AM
YRW
sorry for the delay...
you need an OVERLAPPED struct (and its associated event) for each simultaneous operation you'll issue. So if you never make a read and a write at the same time you can use the same OVERLAPPED.

Regards.

zariostr
September 13th, 2004, 12:05 AM
hi again
when need use overlap and when don't ???

pinzo
September 14th, 2004, 05:59 PM
hi again
when need use overlap and when don't ???

Well, you don't actually need to use it, this is a decision only you can make ;-)
Say, for example, that your project must use SIMULTANEOUSLY and all the time N serial ports (or sockects, or pipes... for that matter). Then you have several options:
1. Blocking I/O. You'll probably need one thread per port.
2. Overlapped I/O. You can still use one thread per port, or you can have one thread that handles several ports simultaneously.
3. Specific handling. Serial ports can have timed-out I/O, sockets can use non-blocking semantics...

Even if you have one thread per handle, you may want to use overlapped, so you can handel inputs and output at the same time, and it's easier to control the logic of the thread. I mean, I you want to send a signal to the thread just use WaitForMultipleObjects on all the pending overlappeds plus 1 event to handle external events.

On the other side, OVERLAPPED can be a bit tricky to make it work the first times. So for simple projects it may just not worth it.

Hmmm, I don't know if I am messing it up. My english is far from good.... HTH, anyway.

zariostr
September 14th, 2004, 11:24 PM
thanks
in my task i have

deviceA -> PC ->deviceB
devices are connected throught com port
also device's protocol like "step by step"

for example
deviceA PC
data1 ->
<- ack
<- data2
ack ->
data3 ->

i think overlap not better decision for my purposes

also devices send CRC sum in all data packets and how PC need get it
seems i need write big endian <->low endian function

zariostr
September 24th, 2004, 08:38 AM
hello
i write code but it's not worked - nothing come from device.
anycase thanks at advance

here is part of my code



void Device::InitDevice(LPSTR n,LPSTR c,int s,HWND h,int input,int output)
{
...
InitComPort();
text="";
...
}

void Device::ReadData()
{
buf_size=4096;
ReadFile(com,buf,buf_size,&bc,&ovl);
if (WaitForSingleObject(ovl.hEvent,10000)==WAIT_OBJECT_0)
{
GetOverlappedResult(com,&ovl,&bc,FALSE);
}
else
{
ErrorBox("ReadData error");
}
}

void Device::InitComPort()
{
hCom=CreateFile(com,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,NULL);
if(hCom==INVALID_HANDLE_VALUE)
{
ErrorBox("Unable open");
}
memset(&ovl,0,sizeof(ovl));
ovl.hEvent=CreateEvent(NULL,FALSE,FALSE,NULL);
dcb.DCBlength=sizeof(DCB);
GetCommState(hCom,&dcb);
if (!GetCommState(hCom,&dcb))
{
ErrorBox("Error in GCS");
}
dcb.BaudRate=speed;
dcb.ByteSize=8;
dcb.Parity=NOPARITY;
dcb.StopBits=ONESTOPBIT;
if (!SetCommState(hCom,&dcb))
{
ErrorBox("Error in SCS");
}
PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR);
}

void Tracer::InitTracer()
{
ReadData();
}

class Device
{
protected:
LPSTR name;
LPSTR com;
int speed;

HANDLE hCom;
DCB dcb;
OVERLAPPED ovl;
DWORD bc;
char* buf;
int buf_size;
LPSTR text;
...

public:
void InitDevice(LPSTR,LPSTR,int,HWND,int,int);
void InitComPort();
void ReadData();
BOOL FindRoot(LPSTR,LPSTR);
void ShowData(HWND,LPSTR);
};

class Tracer:public Device
{

public:
void InitTracer();

pinzo
September 28th, 2004, 07:12 AM
Hello.
There are a few problems with your code. First you should use manual-reset events for OVERLAPPED structures
ovl.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
And do not forget the close event in the destructor.

Then, you don't set Timeouts. Use SetCommTimeouts. If you use OVERLAPPED you'll probably want timeouts disabled, so:
COMMTIMEOUTS to;
memset(&to, 0, sizeof(to));
SetCommTimeouts(hCom, &to);

I recommend that you use BuildCommDCB instead of setting DCB fields manually, because it can be rather tricky:
BuildCommDCB(&dcb, "baud=9600 parity=n data=8 stop=1");

And, at last, the most important thing to remember when using OVERLAPPED: ReadFile can return data immediatly or can start an overlapped operation. You'll call GetOverlappedResult ONLY if ReadFile/WriteFile returns FALSE and GetLastError return ERROR_IO_PENDING. Something like this:


DWORD bytes;
BOOL res = ReadFile(hCom, ptr, size, &bytes, &ovl);
if (!res)
{
if (GetLastError()==ERROR_IO_PENDING)
{
DWORD resW =WaitForSingleObject(ovl.hEvent, 10000);
if (resW!=WAIT_OBJECT_0)
Timeout();

res = GetOverlappedResult(hCom, &ovl, &bytes, FALSE);
}
}
if (!res)
Error(GetLastError());

// Here you've just read 'bytes' bytes


I think it should work this way.
HTH

zariostr
October 11th, 2004, 12:40 AM
hi
can i test my program using modem ???
for example if i use "ATZ\r"
i need write "ATZ\r" in my program or from OS ?

kawasaki056
October 16th, 2004, 10:28 AM
it' s accidental but I have just accomplished my fax software and I think what you wrote is allright. just writing "ATZ/" can go well. using CreateFile , with parameters "COM1" or "COM2" or ... to filename ....

zariostr
October 16th, 2004, 12:06 PM
it' s accidental but I have just accomplished my fax software and I think what you wrote is allright. just writing "ATZ/" can go well. using CreateFile , with parameters "COM1" or "COM2" or ... to filename ....

hi
so i want use "ATZ" on modem (like emulator another device)
but how send this command to modem ?
under my program ???
then how open com port if it's have modem on it ???

kawasaki056
October 16th, 2004, 12:39 PM
hi
so i want use "ATZ" on modem (like emulator another device) yes.
but how send this command to modem ?
you WriteFile ;

under my program ??? of course . what do you mean by "from OS" ? I am not sure

then how open com port if it's have modem on it ???
didn't you CreateFile ? opened already .

just sample but ,

hModem = CreateFile( "COM1" , GENERIC_WRITE , FILE_SHARE_READ | FILE_SHARE_WRITE , NULL , OPEN_EXISTING , FILE_FLAG_OVERLAPPED , NULL ) ;

( sorry but it's better to specify "GENERIC_READ" too, because read operation is also done through this handle )

WriteAsync( hFile , "ATZ\r" ..) ; // you write your own writing func.it's your work I think. if you want to test , nothing special is necessary , just


OVERLAPPED ovlap ; ZeroMemory( &ovlap , sizeof( OVERLAPPED )) ;
ovlap.hEvent = CreateEvent( NULL , TRUE , FALSE , NULL ) ;
DWORD dwAccBytes ;
WriteFile( hModem , "ATZ\r" , strlen("ATZ\r") , &dwAccBytes , &ovlp ) ;

just ok with these.( for test only , though you must write read thread to ensure the modem's response \r\nOK\r\n )

do you want to know which com port is attached to the mdoem ?
first you try "COMx" , x modifying yourself...want to get com port automatically ?
well.. if you want achieve it , learn about "tapi" or as another way, check registry.
I cant tell whole story at all. so with more concrete question , I can be helpful.

//////////////////
In addition ....
//////////////////

there is good idea to ensure you could write right in the modem .
"ATDT#xxx" may be good, though you should take care about the phone number.

and about tapi, tapi's official explanation may recommend the use of "tapi functions" through the whole sessions, but I think it's easier to operate directly the com port for the case here.
for example , in my fax application, tapi is used only to get the pairs of "modem name" and "port name" by funciton "lineGetID()" , start with this function first to learn tapi is perhaps ok.

but even just for that purpose , tapi was no perfect , because it behaves differently on Win98 and NT( XP). so, at last , finishing all coding, I found tapi is no use at all...( sorry Microsoft )though it is of some use when learning. com port name can't be got on Win98 machines even using tapi . it may be natural because tapi's reference refers nothing to fax programing. maybe it says to use mapi.

as a result
Use registry to get com port
and ,
Use standard api WriteFile or ReadFile to the handle (hModem ) opened by CreateFile .

about registry , it being very hard for me to reach the conclusion of using registry,
thought I was saved finding the way exits I can manage my work. if you want to learn it,use these keywords :

"RegOpenKeyEx"
"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E96D-E325-11CE-BFC1-08002BE10318}" this is for NT machine
(this {4D36E96D-E325-11CE-BFC1-08002BE10318} is important ! )
and "SYSTEM\\CurrentControlSet\\Services\\Class\\Modem" this is for 95/98 machine
and more, "AttachedTo" , which is the key name in registry about modem information. the registry's structure itself also differs from each case, so , be ready for your hard time , with regedit.exe.

these key word helps you.