NO

Author Topic: Com port  (Read 12204 times)

czerny

  • Guest
Com port
« 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



CommonTater

  • Guest
Re: Com port
« Reply #1 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.



czerny

  • Guest
Re: Com port
« Reply #2 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

CommonTater

  • Guest
Re: Com port
« Reply #3 on: February 09, 2012, 11:16:58 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...
Code: [Select]

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.

     
« Last Edit: February 09, 2012, 11:24:43 PM by CommonTater »

Offline TimoVJL

  • Global Moderator
  • Member
  • *****
  • Posts: 2091
Re: Com port
« Reply #4 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...
« Last Edit: February 10, 2012, 11:42:02 AM by timovjl »
May the source be with you

Offline DMac

  • Member
  • *
  • Posts: 272
Re: Com port
« Reply #5 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
No one cares how much you know,
until they know how much you care.

CommonTater

  • Guest
Re: Com port
« Reply #6 on: February 10, 2012, 07:03:34 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

Excellent article.... but not many AT modems in use these days... :D

Offline TimoVJL

  • Global Moderator
  • Member
  • *****
  • Posts: 2091
Re: Com port
« Reply #7 on: February 10, 2012, 08:21:41 PM »
Quote
But 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 ?

May the source be with you

czerny

  • Guest
Re: Com port
« Reply #8 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

czerny

  • Guest
Re: Com port
« Reply #9 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

CommonTater

  • Guest
Re: Com port
« Reply #10 on: February 13, 2012, 07:08:07 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.
 
Code: [Select]
/ 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  ... but there's no harm in taking the entire thing, I've used most of them from time to time.
« Last Edit: February 13, 2012, 07:25:26 PM by CommonTater »

czerny

  • Guest
Re: Com port
« Reply #11 on: February 14, 2012, 10:09:36 AM »
Hallo Tater,

Quote
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.

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

CommonTater

  • Guest
Re: Com port
« Reply #12 on: February 14, 2012, 04:44:26 PM »
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...
 
Code: [Select]
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...
Code: [Select]

 
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
 
 

Offline Stefan Pendl

  • Global Moderator
  • Member
  • *****
  • Posts: 582
    • Homepage
Re: Com port
« Reply #13 on: February 14, 2012, 07:17:52 PM »
Code: [Select]
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.
---
Stefan

Proud member of the UltraDefrag Development Team

CommonTater

  • Guest
Re: Com port
« Reply #14 on: February 14, 2012, 07:33:59 PM »
Code: [Select]
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.