Pelles C forum

C language => Windows questions => Topic started by: czerny on February 08, 2012, 05:25:29 PM

Title: Com port
Post by: czerny on February 08, 2012, 05:25:29 PM
Hallo,

I have to establish a serial connection between a win me and an old dos box.  Because of a programming error of mine the opend com port (COM2:) keeps obviously open after program execution. If i try to run my program a second time I get an error (access denied). I have to restart the computer (I develop on win2k or xp resp.) to go on.
So, the simple solution is to catch my error. This is just done. But I wonder, if there isn't a solution to close the port somehow afterwards. I am also a bit puzzled that the port is not closed automatically after program termination.

czerny


Title: Re: Com port
Post by: CommonTater on February 08, 2012, 07:40:31 PM
This depends entirely how you are opening the COM port... Under windows since 2000 this is done by opening it as a file and closing the file should release the port.  Under DOS doing this with interrupts can leave the port open in DOS with nothing listening to it.

Best practice is always to clean up your "mess"... if you open something, close it when done, if you allocate memory, free it when done... same with handles, mutex, critical sections and so on... If you use it, you need to release it when done. 

Windows will clean up after itself on *normal termination*... but not always so under abnormal situations.  DOS did very little post processing when running a program.


Title: Re: Com port
Post by: czerny on February 09, 2012, 06:41:21 PM
It is obviously clear that the port should closed afterwards. I have written so.
The question was: how can this be done if this has been forgotten by an programming error.
The port is opend by CreateFile().

czerny
Title: Re: Com port
Post by: CommonTater on February 09, 2012, 11:16:58 PM
Quote from: czerny on February 09, 2012, 06:41:21 PM
It is obviously clear that the port should closed afterwards. I have written so.
The question was: how can this be done if this has been forgotten by an programming error.
The port is opend by CreateFile().

czerny

In pseudocode...


if (OpenComport)
  {
    try
       { transfer data }
    finally
       { close comport}
  }


Under Windows SEH ... The finally section is executed whether there is an error or not, providing guaranteed cleanup.

I've written a library "Error-X", available from the user contributions forum that makes SEH very easy to work with.

Files opened with CreateFile() are closed with CloseHandle()... Which should realease the lock on the ComPort.

     
Title: Re: Com port
Post by: TimoVJL on February 10, 2012, 11:27:57 AM
For WindowsXP and newer:
Use SysInternals Process Explorer http://technet.microsoft.com/en-us/sysinternals/bb896653
to find if there is process that still uses serialport.
Search keyword Serial from Find -> Find Handle or DLL...
Title: Re: Com port
Post by: DMac on February 10, 2012, 06:27:39 PM
Although it may not help with the DOS box.  This Code and article might be helpful for the windows side of things.  http://forum.pellesc.de/index.php?topic=2994.0 (http://forum.pellesc.de/index.php?topic=2994.0)
Title: Re: Com port
Post by: CommonTater on February 10, 2012, 07:03:34 PM
Quote from: DMac on February 10, 2012, 06:27:39 PM
Although it may not help with the DOS box.  This Code and article might be helpful for the windows side of things.  http://forum.pellesc.de/index.php?topic=2994.0 (http://forum.pellesc.de/index.php?topic=2994.0)

Excellent article.... but not many AT modems in use these days... :D
Title: Re: Com port
Post by: TimoVJL on February 10, 2012, 08:21:41 PM
QuoteBut I wonder, if there isn't a solution to close the port somehow afterwards.
Have anyone example for that situation ?
Must we have Win95 - WinME for that ?
Windows NT and newer clean handles even after crash ?

Title: Re: Com port
Post by: czerny on February 10, 2012, 10:45:52 PM
It happend to me a few months ago with win2k and this week with xp. I do not develop on win me.

czerny
Title: Re: Com port
Post by: czerny on February 13, 2012, 06:30:48 PM
But I can not produce this phenomenon  intentionally.

Meanwhile I have found a tool with name 'handle' from sysinternals. If I am faced with a similar problem in the futur, I will try this. PortMon seems to be usefull to me too.

timovjl: And you are right. Process Explorer would also be helpfull in this situation.

czerny
Title: Re: Com port
Post by: CommonTater on February 13, 2012, 07:08:07 PM
Quote from: czerny on February 13, 2012, 06:30:48 PM
But I can not produce this phenomenon  intentionally.

Try rebuilding your project with all optimizations and inlining turned off... see if it still happens.
See if it still happens when the code includes debugging symbols.

If you can't isolate it and reproduce it, it might be that something is not exiting normally... which can cause Windows to skip the cleanup steps...  which is where Structured Exception Handling comes in very handy...

Here's an example of code using SEH to guarantee a cleanup if things go wrong... It works with the Error-X library I suggested earlier, take a close look at the try{}finally{} construct.  This forces a cleanup if there's an error.  The Exception() function is from Error-X and forces an exception to occur.


/ open and translate file
BOOL M3ULaunch(PWCHAR FileName)
  { PBYTE  rf;      // raw file data
    DWORD  br;      // bytes read
    // load the raw file
    { HANDLE pl;    // playlist file handle
      DWORD  fs;    // file size
      // get path to file
      wcsncpy(FilePath,FileName,MAX_PATH);
      PathRemoveFileSpec(FilePath);
      wcscat(FilePath,L"\\");
      // open the file
      pl = CreateFile(FileName,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
      if (pl == INVALID_HANDLE_VALUE)
        Exception(GetLastError());
      fs = GetFileSize(pl,NULL);       
      rf = calloc(fs + 2, sizeof(BYTE));
      if (! ReadFile(pl, rf, fs, &br, NULL))
        Exception(GetLastError());
      CloseHandle(pl); 
      if (br != fs)
        Exception(0xE00640007); }

    try                                   
     { DWORD bom = *(DWORD*)rf;
       if ((bom == 0x0000FEFF) || (bom == 0xFFFE0000))  // utf32le bom 
         Exception(0xE0640002);                         // utf32be bom 
       else if ((bom & 0xFFFF) == 0xFFFE)               // utf16be bom
         { FlipEndian(rf,br);
           CopyWChar((PWCHAR) rf + 1); }
       else if ((bom & 0xFFFF) == 0xFEFF)               // utf16le bom
         CopyWChar((PWCHAR) rf + 1); 
       else if ((bom & 0xFFFFFF) == 0xBFBBEF)           // utf8 bom
         CopyMByte(rf + 3, br - 3);
       else                                             // no known bom, probe the file
         { if (! memchr(rf, 0x00, br))                  // 8 bit text has no nulls
             CopyMByte(rf,br);                          // ansi / utf8 no bom
           else
            { PBYTE lf = memchr(rf,0x0A,br);            // lf is always present as 1 byte.
              if (!lf)
                Exception(0xE0640003);
              if ((!(*(DWORD*)(lf - 3) & 0x00FFFFFF)) ||    //utf32be no bom
                   (!(*(DWORD*)lf & 0xFFFFFF00)))           //utf32le no bom
                 Exception(0xE0640002);   
              if ((lf - rf) & 1)                        // big endian? (lf at odd offset)
                FlipEndian(rf,br);                      // utf16be no bom 
              CopyWChar((PWCHAR) rf);  } } }            // utf16le no bom
     finally 
      { free(rf); }


    return 1; }

Although it's much simpler for comports, the principle is the same... If an error occurs while sending/receving data, force an exception which forces the finally{} block to execute, guarnteeing your  cleanup is performed.  If there is no error the finally{} block is executed as it is encountered, once again ensuring your cleanup happens as planned.

(note: Error-X is not required to use SEH... it just makes it a lot easier.)

Quote
Meanwhile I have found a tool with name 'handle' from sysinternals. If I am faced with a similar problem in the futur, I will try this. PortMon seems to be usefull to me too.

timovjl: And you are right. Process Explorer would also be helpfull in this situation.

czerny

Since you are now have XP you also have some expanded capability in Task Manager...

Right click the taskbar... select "start task manager" --->  look in the menus.  You will find that you can add columns in the process tab for memory usage, handle count, thread count with View -> Add Columns.  The window is also resizeable so you can see all of it at once.

These will be very handy in tracking most leaks.  That is, your program's handle count should not be constantly increasing as it runs... it should reach a certain count and stay there, even when idling in the message dispatcher.  The memory usage count is rather granular but it will help you find big leaks or accumulating leaks over multiple function calls.  For example:  If you are working on a program, you should see the handle count and memory usage increase as it opens files and launches threads but when the task completes it should go right back down to the original idle-state counts.

From Sysinternals, ProcMon is probably what you will use the most...  http://technet.microsoft.com/en-us/sysinternals/bb896653 (http://technet.microsoft.com/en-us/sysinternals/bb896653)  ... but there's no harm in taking the entire thing, I've used most of them from time to time.
Title: Re: Com port
Post by: czerny on February 14, 2012, 10:09:36 AM
Hallo Tater,

QuoteSince you are now have XP you also have some expanded capability in Task Manager...

Right click the taskbar... select "start task manager" --->  look in the menus.  You will find that you can add columns in the process tab for memory usage, handle count, thread count with View -> Add Columns.  The window is also resizeable so you can see all of it at once.

I have not got become disloyal to my old win2k box. I use XP on work and win2k at home. What you are explaining is available in Win2000 too. But I haven't seen this bevor. Thank you!

I do not like the try-finally thing very much. Don't know why. My application is a gui and the places where I open and close the port are far from each other. So try-finally would not match either

czerny
Title: Re: Com port
Post by: CommonTater on February 14, 2012, 04:44:26 PM
Quote from: czerny on February 14, 2012, 10:09:36 AM
I have not got become disloyal to my old win2k box. I use XP on work and win2k at home. What you are explaining is available in Win2000 too. But I haven't seen this bevor. Thank you!

You're welcome... I haven't used win2000 for about 6 years and I guess memory failed me a bit.  Glad to hear you can make use of it.

Quote
I do not like the try-finally thing very much. Don't know why. My application is a gui and the places where I open and close the port are far from each other. So try-finally would not match either

There are situations where you don't get to use it that's for sure.  One of the main impediments to SEH is that people don't understand it...  For example you can do this...


BOOL SendString(FILE *f, char *str)
  {
     try
      {
         if (fputs(str,f) < 0)
           Exception(GetLastError());
         return 1;  // success
       }
     finally
       {
          fclose(f);
          return 0;
       }
  }

In this case you return from the function from inside the try block, so the finally is only executed if there is an error.

In practice this is something of a race-car version of the old goto thing...


BOOL SendString(FILE *f, char *str)
  {
       if (fputs(str,f) < 0)
          goto error;
       return 1;  // success

      error:
        fclose(f);
        return 0;
  }

The difference being that the OS directly supports SEH where the goto error thing is strictly a C contrivancy. 

You can read more about SEH ...  here  (http://www.microsoft.com/msj/0197/exception/exception.aspx)

Title: Re: Com port
Post by: Stefan Pendl on February 14, 2012, 07:17:52 PM
Quote from: CommonTater on February 14, 2012, 04:44:26 PM

BOOL SendString(FILE *f, char *str)
  {
     try
      {
         if (fputs(str,f) < 0)
           Exception(GetLastError());
         return 1;  // success
       }
     finally
       {
          fclose(f);
          return 0;
       }
  }

In this case you return from the function from inside the try block, so the finally is only executed if there is an error.

From my understanding finally is executed in any case, but catch is only executed in the case of an error.

So, if you have a try {} catch {} finally{} construct, a regular execution will execute the code for try and finally, but if there is an exception encountered inside the try section, then the catch section will be executed before the finally section.
Title: Re: Com port
Post by: CommonTater on February 14, 2012, 07:33:59 PM
Quote from: Stefan Pendl on February 14, 2012, 07:17:52 PM
Quote from: CommonTater on February 14, 2012, 04:44:26 PM

BOOL SendString(FILE *f, char *str)
  {
     try
      {
         if (fputs(str,f) < 0)
           Exception(GetLastError());
         return 1;  // success
       }
     finally
       {
          fclose(f);
          return 0;
       }
  }

In this case you return from the function from inside the try block, so the finally is only executed if there is an error.

From my understanding finally is executed in any case, but catch is only executed in the case of an error.

So, if you have a try {} catch {} finally{} construct, a regular execution will execute the code for try and finally, but if there is an exception encountered inside the try section, then the catch section will be executed before the finally section.

That's correct... but by returning from within the try block, you destroy the stack frame and the finally part is not executed.  I presented it only as an example... try{} except{} would probably be the preferred method in most cases.

Title: Re: Com port
Post by: Stefan Pendl on February 14, 2012, 07:40:54 PM
try..catch is a nice feature for manged code, but for pure C I still prefer to know the problems I may encounter ;)
Title: Re: Com port
Post by: CommonTater on February 14, 2012, 07:58:04 PM
Quote from: Stefan Pendl on February 14, 2012, 07:40:54 PM
try..catch is a nice feature for manged code, but for pure C I still prefer to know the problems I may encounter ;)

Well there is that... Which is why I included the ReportError() function in my Error-X library...

The poject workspace is attached... take a look at the source code for the test program... Nothing stops you from reporting the errors when except{} occurs.  The ReportError() function searches Message Tables... first in your App or DLL resources, then in Windows DLLs and finally defaults to it's own set of messages...  You also have the option to terminate the program or not.

Anyway... having hijacked czerny's thread here... we should get back to the problem he's having with comports...

Title: Re: Com port
Post by: aardvajk on February 14, 2012, 09:44:40 PM
Quote from: CommonTater on February 14, 2012, 07:33:59 PM
That's correct... but by returning from within the try block, you destroy the stack frame and the finally part is not executed.

How can you say he's correct and then assert that what actually happens is entirely the opposite of what he said? BTW he is correct, it's well defined and works perfectly.
Title: Re: Com port
Post by: czerny on February 15, 2012, 11:59:29 AM
One try{} catch{} finally{} construct is tolerably clear. But what about more nested trys?

I often try to code so, that I leave the function in case of an error as soon as possible. A dozen nested if-else statements is not clear at all and a dozen try blocks is even worse.


int myfunc(void)
{
  if (errorvalue == func1()) {
    finalize();
    return 0;
  }
  if (errorvalue == func2()) {
    finalize();
    return 0;
  }
  if (errorvalue == func3()) {
    finalize();
    return 0;
  }
  // do what I actually want to do
  return 1;
}


It is sure, that one can not stand this in all cases, but I can often reduce the nesting complexity considerably.

czerny
Title: Re: Com port
Post by: CommonTater on February 15, 2012, 04:57:20 PM
If you wrote your functions to throw an exception...  (shown the Error-X way)

int func1( int a)
  { if (a == 0)
       exception(DIV_0);
     return 10 / a; }


... you could do this...


try
  { x = func1( y );
     func2( x );
     func3( x );  }
except
   { ReportError(ExcCode,false);
      doCleanup(); }


... and if any of the functions threw an exception the sequence is aborted an error is reported, doCleanup() gets called and execution resumes at the end of the except{} block.

There are even cases where you can fix an error...

try
  { x = func1(y); }
except
  { y = REPAIR_VALUE;
     x = func1(y); }
func2(x);
func3(x);

... and the user is none the wiser.