Announcement

Collapse
No announcement yet.

ReadFile

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • ReadFile

    I am nearing a point of posting code for what started out as "USB Complete" but a heck of a lot easier if not using HID drivers. Although hard, I almost have it, but one more M$ wall has jumped up in front of me again.

    This time I hope its something simple to solve, but I do not see it.
    What I need to do is the following with a File/Device/Port (does not matter what at the moment)
    1. Open using CreateFile '<=== DONE
    2. Count number of bytes to send '<=== Should be simple since I know what I am sending
    3. WriteFile '<=== Should be simple
    4. Count number of bytes to read '<=== NO CLUE
    5. Read the number of bytes '<=== Should be easy once I have a count


    The getting the number of bytes to read is whats eluding me and re-reading the Win32Api.hlp is just making things worse

    If the handle returned from CreateFile was for a file, I could get the bytes needed from the file itself, if memory serves if it were a ComPort, then I could get the bytes by forcing a timeout time with CommTimeout, that in turn would have the number of bytes ready to be read, but if its some other device (like USB) there must be a way to get the number of bytes to be read?????

    Since ReadFile is a "Blocking" call that does not return until done, or error I need a better way or could be waiting forever if there is no bytes to be read?
    Engineer's Motto: If it aint broke take it apart and fix it

    "If at 1st you don't succeed... call it version 1.0"

    "Half of Programming is coding"....."The other 90% is DEBUGGING"

    "Document my code????" .... "WHYYY??? do you think they call it CODE? "

  • #2
    ReadFile:
    (param 3) NUmber of bytes to read = how many bytes you want to get from file
    (param 4) Number of bytesRead = how many bytes were ACTUALLY read from file

    WriteFile
    (param 3) NUmber of bytes to write = how many bytes you want to write to file
    (param 4) Number of bytesWritten = how many bytes were ACTUALLY written to file

    When Desired<>Actual it means something significant... when reading it probably means "end of file reached before requested number of bytes was found." When writing, I don't think you can get anything other than no bytes written.

    So in your case where you don't know how many bytes are available, loop asking for one at a time until bytesRead = 0, meaning "no more available"

    "If the return value is nonzero and the number of bytes read is zero, the file pointer was beyond the current end of the file at the time of the read operation"
    Michael Mattias
    Tal Systems Inc. (retired)
    Racine WI USA
    [email protected]
    http://www.talsystems.com

    Comment


    • #3
      I get the part of how many read vs how many write, the problem being that read is locking unless I can check how many bytes to look for first (in this case, I do not know at the moment of checking) so I need to ask first

      in the cases of files, or ComPorts, I can either ask, or timeout and check whats there...in the case of USB I have no clue how to not lock things up because I do not know how to ask how many (if any) are there when I want to ask?
      Engineer's Motto: If it aint broke take it apart and fix it

      "If at 1st you don't succeed... call it version 1.0"

      "Half of Programming is coding"....."The other 90% is DEBUGGING"

      "Document my code????" .... "WHYYY??? do you think they call it CODE? "

      Comment


      • #4
        Can't you force a timeout in the same way you would for a comport?
        Rgds, Dave

        Comment


        • #5
          Maybe you need to use ansynchronous I-O?

          Asynchronous (Overlapped) I-O Demo

          (NOTE ADDED): Asynch I-O can be timed out and canceled if necessary.

          When I got an NT-Class machine, I was able to FINALLY try this.. something I had wanted to do for a long time. Somewhere around here is a post where I reported the results, and how disappointed I was by its lack of practical benefits.

          However, I only played with Overlapped DISK I-O. Maybe DEVICE I-O is where Ansync I-O gets its day in the sun.
          Last edited by Michael Mattias; 1 Mar 2008, 10:22 AM.
          Michael Mattias
          Tal Systems Inc. (retired)
          Racine WI USA
          [email protected]
          http://www.talsystems.com

          Comment


          • #6
            Thanx for the post MCM, it got me one step closer as I discovered from bits and pieces online, as long as I am allowed a CreateFile to an interface, I can send and receive as long as I know the number of bytes to send or receive, but the problem is when I do NOT know how many bytes.

            I was trying to decipher what you did for Asynchronous IO but could not get it to run. What do I change the file name to? and do you have a routine for reading? all there was is a writing routine.

            I have so far figured out that I have 2 routes I can take
            1. If I can set a timeout, then ReadFile and timeout if not enough bytes '<---I do NOT like this because I will have to unnecessarily slow down my program for looking for stuff that may never exist?
            2. If I could find the number of bytes waiting to be read '<--- This is what I NEED because then I could just read what is there, and decide what to do with it.


            I am quickly learning why all the forums I have scoured, tend to say the same thing..."Those that Know, write their own", "Those that don't, HID it or use the Manufacturers dll"

            What a pain .... but I am sure I will figure it out somehow
            Engineer's Motto: If it aint broke take it apart and fix it

            "If at 1st you don't succeed... call it version 1.0"

            "Half of Programming is coding"....."The other 90% is DEBUGGING"

            "Document my code????" .... "WHYYY??? do you think they call it CODE? "

            Comment


            • #7
              I like to leave at least something "undone" in my demos.

              It gives me the chance to point out you can always contact my office if you are considering engaging an outside consultant for your project.
              Michael Mattias
              Tal Systems Inc. (retired)
              Racine WI USA
              [email protected]
              http://www.talsystems.com

              Comment


              • #8
                So in your case where you don't know how many bytes are available, loop asking for one at a time until bytesRead = 0, meaning "no more available"

                "If the return value is nonzero and the number of bytes read is zero, the file pointer was beyond the current end of the file at the time of the read operation"
                A good while ago I was attempting to use ReadFile() to mimic the operation of BASIC's Line Input # statement on lines in a text file, and Michael's suggestion is pretty much what I found I had to do for the reason you already are fighting with Cliff. I just read one byte at a time into a preallocated string variable (concatenating all the way in a loop), and if I recall (it was a pretty long time ago), there was some mechanism available through checking the output parameters in the ReadFile() function so that you would know when the line has been read in. Don't know if this helps, but I think MCM already gave you the answer. You are aware, aren't you, that you must check the lpNumberOfBytesRead output parameter after each read byte?
                Last edited by Fred Harris; 1 Mar 2008, 07:12 PM.
                Fred
                "fharris"+Chr$(64)+"evenlink"+Chr$(46)+"com"

                Comment


                • #9
                  Here's some code based on a posting by Peter Lameijn (and others ) which uses Overlapped I/O comms that might help.
                  Code:
                   
                  %USEMACROS = 1
                  #INCLUDE "WIN32API.INC"
                  '------------------
                  GLOBAL gShutDown AS LONG
                   
                  SUB CPrintLine (SOut AS STRING)                                                 ' TT Chuck Hicks
                   STATIC hConsole AS LONG, cWritten AS LONG
                    SOut = SOut + $CRLF
                    IF hConsole = 0 THEN
                      AllocConsole : SetConsoleTitle "Test OutPut"
                      hConsole = GetStdHandle(%STD_OUTPUT_HANDLE)
                    END IF
                    WriteFile hConsole, BYVAL  STRPTR(sOut), LEN(sOut), cWritten, BYVAL 0&
                  END SUB
                   '------------------/CPrintLine
                   
                  FUNCTION ErrorMsg (BYVAL ErrorCode AS DWORD) AS STRING
                   LOCAL szMsg AS ASCIIZ * 255
                    FormatMessage %FORMAT_MESSAGE_FROM_SYSTEM, BYVAL 0, ErrorCode, 0, szMsg, SIZEOF(szMsg), BYVAL 0
                   FUNCTION = STR$(ErrorCode) +" "+ szMsg
                  END FUNCTION
                  '------------------/ErrorMsg
                   
                  FUNCTION GetCommOVL (szComPort AS ASCIIZ) AS LONG                               ' TT Peter Lameijn
                   LOCAL lRet, lError, lCnt, lEvtMsk, hComm, lBytes, WaitStat, E, cErr AS LONG
                   LOCAL lDCB AS DCB
                   LOCAL lCTO AS COMMTIMEOUTS
                   LOCAL lOVL AS OVERLAPPED
                   LOCAL CS AS COMSTAT
                   LOCAL lCommStr, lBuff, lString, sBuffer AS STRING
                   LOCAL Buf AS STRING * 4096
                   LOCAL lByteBuff AS STRING * 1
                    ON ERROR RESUME NEXT                                                                  'Error skip
                   
                    hComm = CreateFile (szComPort, %GENERIC_READ OR %GENERIC_WRITE, 0, _
                                        BYVAL %NULL, %OPEN_EXISTING, %FILE_FLAG_OVERLAPPED, BYVAL %NULL)
                   
                    lRet                              = GetCommState (hComm, lDCB)                        'Get current settings
                    lDCB.BaudRate                     = 4800                                              ' Set Baudrate etc
                    lDCB.ByteSize                     = 8
                    lDCB.Parity                       = %NOPARITY
                    lDCB.StopBits                     = %ONESTOPBIT
                   
                    BIT RESET                         lDCB.fBits,2                                        ' CTS 0
                    BIT RESET                         lDCB.fBits,3                                        ' DSR 0
                    BIT RESET                         lDCB.fBits,4                                        ' DTR 0
                    BIT RESET                         lDCB.fBits,5                                        ' DSRSensitivity
                    BIT RESET                         lDCB.fBits,6                                        ' ContinueOnXOFF
                    BIT RESET                         lDCB.fbits,7                                        ' XON/XOFF output (Set to 0)
                    BIT RESET                         lDCB.fBits,8                                        ' XON/XOFF input  (Set to 0)
                    BIT RESET                         lDCB.fBits,11                                       ' RTS 0
                    lRet                              = SetCommState (hComm, lDCB)                        'And write back
                   
                    lRet                              = GetCommTimeOuts (hComm, lCTO)                     'Get current time-outs
                    lCTO.ReadIntervalTimeOut          = %MAXDWORD                                         ' Set them
                    lCTO.ReadTotalTimeOutMultiplier   = 0                                                 '
                    lCTO.ReadTotalTimeOutConstant     = 0                                                 '
                    lRet                              = SetCommTimeOuts (hComm, lCTO)                     'And write them back
                   
                    lRet                              = SetCommMask (hComm, %EV_RXCHAR OR %EV_ERR)' OR %EV_BREAK) 'What events to watch
                    lOVL.hEvent                       = CreateEvent (BYVAL %NULL, 0, 0, BYVAL %NULL)      'Create event for lOVL
                    IF lOVL.hEvent <> 0 THEN
                      WHILE gShutDown = 0                                                                 'Loop until prog exits
                        CPrintLine "lEvtMsk at start loop: "+STR$(lEvtMsk)
                        SetLastError 0
                        IF WaitCommEvent (hComm, lEvtMsk, lOVL) = %FALSE THEN
                          IF GetLastError = %ERROR_IO_PENDING THEN CPrintLine "Err: "& ErrorMsg (GetLastError) : _
                          CPrintLine "lEvtMsk after WCE: "+STR$(lEvtMsk)
                            'WFSO w/timeout = 5 sec
                            WaitStat = WaitForSingleObjectEx (lOVL.hEvent, 5000, 0)     'hEvent signaled state when EV_ or Error occurs
                              CPrintLine "lEvtMsk after WSO: "+STR$(lEvtMsk)
                              SELECT CASE WaitStat
                                CASE -1&
                                     E = GetLastError
                                     MSGBOX "Wait Failed:" & ErrorMsg (E)
                                CASE %WAIT_OBJECT_0
                                     MSGBOX "Process complete " & ErrorMsg (E)
                                     lRet = GetOverlappedResult(hComm, lOVL, 0, 0)
                                     CPrintLine "After GOR, lEvtMsk: "+STR$(lEvtMsk)
                                     ClearCommError (hComm, cErr, CS)
                                     CPrintLine "Error: "+ STR$(cErr)+ " !"
                                     IF cErr THEN
                                        lDCB.BaudRate = 4800: SetCommState (hComm, lDCB): SLEEP 100
                                        PurgeComm(hComm, %PURGE_RXCLEAR): lEvtMsk = 0: ITERATE LOOP
                                     END IF
                                     CPrintLine "Bytes: "+ STR$(CS.cbInQue)
                   
                                      DO
                                        lBytes = 0
                                        SetLastError 0
                                        IF ( ReadFile( hComm, buf, CS.cbInQue, lBytes, lOVL) ) <> 0 THEN
                                          lError = GetLastError()
                                          IF( lError = %ERROR_IO_PENDING ) THEN
                                            IF ( GetOverlappedResult( hComm, lOVL, lBytes, %TRUE ) ) = 0 THEN
                                              CPrintLine "GetOverlappedResult failed" & STR$(GetLastError())
                                              EXIT DO
                                            END IF
                                          END IF
                                        END IF
                   
                                        IF lBytes > 0 THEN
                                          CPrintLine LEFT$(buf, lBytes)
                                        ELSE
                                          EXIT DO
                                        END IF
                                        SLEEP 1
                                      LOOP
                   
                                     IF lRet THEN
                                       MSGBOX "NonZero" & STR$(lEvtMsk)
                                     END IF
                                CASE %WAIT_TIMEOUT
                                     CPrintLine "lEvtMsk: "+STR$(lEvtMsk)
                                     MSGBOX "Timeout " & ErrorMsg (E)
                                CASE ELSE
                                     MSGBOX "Unexpected Return, code=" & STR$(WaitStat)
                              END SELECT
                           EXIT
                        END IF
                      WEND
                      CloseHandle lOVL.hEvent
                      CloseHandle hComm
                    END IF
                  END FUNCTION
                  '------------------/GetCommOVL
                   
                  FUNCTION PBMAIN()
                   
                    GetCommOVL "Com1"
                    MSGBOX "Fin"
                   gShutDown = 1
                   
                  END FUNCTION
                  '------------------/PbMain
                  Rgds, Dave

                  Comment


                  • #10
                    Haven't run it Dave, but that is very imaginative code. I love imaginative designs like this.

                    While many are stuck in a loop - both figuratively and literally - those using all the WinAPI tools in a creative fashion like this are - rightly - getting all the contracts.

                    Well done.
                    Last edited by Michael Mattias; 2 Mar 2008, 10:11 AM.
                    Michael Mattias
                    Tal Systems Inc. (retired)
                    Racine WI USA
                    [email protected]
                    http://www.talsystems.com

                    Comment


                    • #11
                      If I could find the number of bytes waiting to be read '<--- This is what I NEED ...
                      Is it really? Or is that what you'd "like" or perhaps what you think you "want?"

                      Seems to me what you NEED is "whatever can read what's there, or tell me there is nothing."

                      A timeout might do the job... if you can make the assumption "if there ain't nothin' there in <time interval>, I'm gonna go do something else."

                      Then again, I like to look for explicit tests, just as you do. You might want to put the read in a separate thread of execution.. so your primary thread is not blocked. (Asynch I-O is perfect for this).

                      You might also then when you DO get data, PIPE that to another thread of execution, which does nothing but wait on data from the pipe. (Demo: Anonymous Pipe as Job Queue Demo 10-29-03)

                      Need to cancel the waits? No problem, here's a demo of how to do that, too: Terminate Worker Threads Using Windows Events (and Using Thread Local Storage) Demo Dec 23 2005

                      Use Ye Olde Imagination!

                      MCM
                      Michael Mattias
                      Tal Systems Inc. (retired)
                      Racine WI USA
                      [email protected]
                      http://www.talsystems.com

                      Comment


                      • #12
                        Cut Bait or Fish?

                        Use Ye Olde Imagination!
                        MCM,
                        The closer I get, and the closer to the docs I get "Dimmed Light Bulbs", I am finding more and more concepts, that your snippets all approach. (Even if only partially) its leading me down the right path.

                        I was asked by another programmer I know working on the same sort of concepts (behind me in some areas, ahead in others) if I would post what I got to source code? I gave him what I have to date, but wonder if time to just post to source code forum as part II of USB "In-Complete" since its my next major step to what I often see asked? (and few answers)?

                        I will leave it up to the masses...is it helpful to show up to the point of "Device Available" or not available, and later work on "Send/Receive"???
                        Engineer's Motto: If it aint broke take it apart and fix it

                        "If at 1st you don't succeed... call it version 1.0"

                        "Half of Programming is coding"....."The other 90% is DEBUGGING"

                        "Document my code????" .... "WHYYY??? do you think they call it CODE? "

                        Comment

                        Working...
                        X