No announcement yet.

Save Console as text file

  • Filter
  • Time
  • Show
Clear All
new posts

  • Save Console as text file

    Alas, another Nubie problem:
    I come from a Mac FB environment, attracted by PBCC's execution speeds and rich command selection. I would like to be able to save the console (page 1) as a text file that could then be read and printed from any of the word processing programs that do .txt files. I have mined these forums but I don't find much help - at least that I can grasp at this point. I can imagine it by doing parallel Print and file commands - or by somehow storing console lines in an array to be read into a file for output, but these seem more devious than PB's developers must have intended. Is there a simple way to do this that I'm overlooking? Thanks for any help - especially pointers to code.

  • #2
    I've been using this style for some time now. Typing this off the cuff so there's probably some mistakes:
    function pbmain()
        local row as long
        local col as long
        local y as long
        open "somefile.txt" for binary as #1
        for row = 1 to {number of lines}
        for col = 1 to {number of columns}
        y = screen(row,col)
        put$ #1,chr$(y)
        next col
        put$ #1,$crlf
        next row
        close #1
        end function
    'course, there may be an API you could use but I'm not aware of it. Hope this helps.

    And, of course, welcome to the board.
    There are no atheists in a fox hole or the morning of a math test.
    If my flag offends you, I'll help you pack.


    • #3
      Don't know if this will help:

      From Win32 Programmer's Reference for API for ReadFile function

      " ... Characters can be read from the console input buffer by using ReadFile with a handle to console input. The console mode determines the exact behavior of the ReadFile function. ..."


      • #4

        Mel's suggestion looks good to me. Doesn't that work? Unless I am misunderstanding what you want, ReadFile() won't do you any good. That Api function reads characters from the console input buffer, something like basic's Inkey$ function.

        Last edited by Fred Harris; 13 Mar 2008, 12:27 PM. Reason: got confused again!


        • #5
          Unless I am misunderstanding what you want, ReadFile() won't do you any good
          If you want to do 'something' in Real Time, ReadFile() could be a terrific way to accomplish it... and quite possibly the ONLY way to do it, depending on the application.

          But if what you want is "give me a text file image of the current screen" then I, too, like Mel's solution: simple is better.
          Michael Mattias
          Tal Systems (retired)
          Port Washington WI USA
          [email protected]


          • #6
            Dear all,
            Thanks very much - I'm happy to have the code and shall use it. I guess I'll need to include an input stataement after Waitkey$ to allow me to call the function -- iff I want to save the console (or portiions thereof) or not. If it were my choice, I'd include a "SaveCons" with line range inputs in a future PBCC command set.
            Again, many thanks. It is a great comfort to a somewhat bewildered Neubie to have your support!


            • #7

              What you wanted to do struck me as unusual and I had never tried anything like that so I gave it a whirl using Mel's suggestion. It worked OK. Here is the program. It prints out exactly what is on the screen to an output.txt file in the program's directory.

              #Compile Exe
              #Dim All
              Function PBMain() As Long
                Local r,c,fp As Long
                Register i As Long
                Register j As Long
                Local byt As Byte
                Console Set Screen 80,80
                Open "Output.txt" For Output As #fp
                Print "extern 'C' __declspec(dllexport) void __stdcall LoadEditCells(HWND hGrid)"
                Print "{"
                Print " DWORD dwGridNum,dwBufferNum;"
                Print " unsigned int i,j,k,iRange,iRows;"
                Print " MyScrollInfo* pMyScrollInfo;"
                Print " wchar_t** pData;"
                Print " HANDLES* pHdls;"
                Print " SIZES* pSizes;"
                Print " HWND hCell;"
                Print ""
                Print " pHdls=(HANDLES*)GetWindowLong(hGrid,0);"
                Print " pSizes=(SIZES*)GetWindowLong(hGrid,4);"
                Print " pData=(wchar_t**)GetWindowLong(hGrid,8);"
                Print " pMyScrollInfo=(MyScrollInfo*)GetWindowLong(hGrid,12);"
                Print " iRange=pSizes->nGridCols;"
                Print " iRows=pSizes->nGridRows;"
                Print " k=pMyScrollInfo->yPos;"
                Print " for(i=1;i<=iRows;i++)"
                Print " {"
                Print "     if(k<=pSizes->nBufferRows)"
                Print "     {"
                Print "        for(j=1;j<=iRange;j++)"
                Print "        {"
                Print "            dwGridNum=dwLoc(i,j);"
                Print "            hCell=pHdls->pCells[dwGridNum];"
                Print "            dwBufferNum=dwLoc(k,j);"
                Print "            SetWindowLong(hCell,0,(long)pData[dwBufferNum]);"
                Print "        }"
                Print "        k++;"
                Print "     }"
                Print " }"
                Print "}"
                For i=1 To Screeny
                  For j=1 To ScreenX
                    Print #fp, Chr$(Screen(i,j));
                  Next j
                  Print #fp,
                Next i
                Close #fp
              End Function


              • #8
                If you are interested in speed, and don't mind an API call, and know the size of your console, SaveConsole1 seems to run about 1.2 times faster than SaveConsole2 per call. Although - the API call does not put $CRLF at the end of each line...

                FUNCTION SaveConsole1() AS STRING
                    LOCAL hOut      AS DWORD
                    LOCAL szChar    AS ASCIIZ * 6401
                    LOCAL nLength   AS LONG
                    LOCAL dwCoord   AS DWORD
                    LOCAL lpNumChar AS LONG
                    LOCAL lRet      AS LONG
                    LOCAL tmp       AS STRING
                    dwCoord = 0
                    hOut = GetStdHandle(%STD_OUTPUT_HANDLE)
                    nLength = 6400
                    lRet = ReadConsoleOutputCharacter(hOut, szChar, nLength, dwCoord, lpNumChar)
                    tmp = szChar
                    FUNCTION = tmp
                END FUNCTION
                FUNCTION SaveConsole2() AS STRING
                    LOCAL x, y  AS LONG
                    LOCAL tmp   AS STRING
                    FOR y = 1 TO SCREENY
                        FOR x = 1 TO SCREENX
                            tmp = tmp + CHR$(SCREEN(y, x))
                        tmp = tmp + $CRLF
                    FUNCTION = tmp
                END FUNCTION
                Last edited by Adam J. Drake; 13 Mar 2008, 03:09 PM.
                Adam Drake


                • #9

                  The console location in memory can be obtained.
                  Using this information and a knowledge of how the screen buffers is laid out a direct memory to disk can be worked out.

                  I have no interest in doing same.

                  I do pre-build screens and switch the active screen for speed.
                  Roy Cline


                  • #10
                    Again, thank you all. I tried Mel's code (as written) and it worked perfectly for my purposes.
                    Now, suppose I want to reverse the process? Is that more or less a reverse of this or are there some pit-falls in reading from a file into the console?
                    I'm passing surprised that Fred found this desire "unusual". I write simulations (genetic and neural) and there is output that I want to save and sometimes print out and put in a notebook. (Primitive, I know.) But I should think that many users would want to be able to save their results and later print them out... But I don't want to save every run, often I want to see the results and go back and tweek the code and see the results again - so I put in a INPUT "do you want to save as a .txt file?" dialog. When I get to it - I'll be making some Graphics files for graphs of the output - and then, I'll probably need help in saving and printiing them. I have Console Tools (std) but probably should have gotten the Pro version...
                    Thank you all, I'm a happy PB'er now. Hayden


                    • #11
                      To reverse the process, simply open the file for INPUT AS #1. Then:

                      for x = 1 to rows
                      line input #1,txt$
                      locate x,1
                      next x

                      If you use various (more than one) colors in your screen(s), you will lose the colors restoring your text to the screen. You may be able to use Roy's suggestion by reading the memory location of the console screen. Pretty sure that will retain the various colors. Check out PEEK$ and POKE$.
                      There are no atheists in a fox hole or the morning of a math test.
                      If my flag offends you, I'll help you pack.


                      • #12
                        You can do so with ReadConsoleOutput and WriteConsoleOutput:

                        #COMPILE EXE
                        #DIM ALL
                        #INCLUDE "WIN32API.INC"
                        FUNCTION PBMAIN () AS LONG
                            LOCAL hOut          AS DWORD
                            LOCAL lpBuffer      AS DWORD
                            LOCAL dwBufferSize  AS DWORD
                            LOCAL dwBufferCoord AS DWORD
                            LOCAL lpReadRegion  AS SMALL_RECT
                            LOCAL lpWriteRegion AS SMALL_RECT
                            hOut = GetStdHandle(%STD_OUTPUT_HANDLE)
                            dwBufferSize = MAKDWD(80, 80)
                            dwBufferCoord = 0
                            DIM pCharInfo(1 TO 6400) AS CHAR_INFO
                            lpBuffer = VARPTR(pCharInfo(1))
                            lpReadRegion.xLeft = 0
                            lpReadRegion.xTop = 0
                            lpReadRegion.xRight = 79
                            lpReadRegion.xBottom = 79
                            TYPE SET lpWriteRegion = lpReadRegion
                            CONSOLE SET SCREEN 80,80
                            COLOR 15, 1
                            PRINT "extern 'C' __declspec(dllexport) void __stdcall LoadEditCells(HWND hGrid)"
                            PRINT "{"
                            PRINT " DWORD dwGridNum,dwBufferNum;"
                            PRINT " unsigned int i,j,k,iRange,iRows;"
                            PRINT " MyScrollInfo* pMyScrollInfo;"
                            PRINT " wchar_t** pData;"
                            PRINT " HANDLES* pHdls;"
                            PRINT " SIZES* pSizes;"
                            PRINT " HWND hCell;"
                            PRINT ""
                            PRINT " pHdls=(HANDLES*)GetWindowLong(hGrid,0);"
                            PRINT " pSizes=(SIZES*)GetWindowLong(hGrid,4);"
                            PRINT " pData=(wchar_t**)GetWindowLong(hGrid,8);"
                            PRINT " pMyScrollInfo=(MyScrollInfo*)GetWindowLong(hGrid,12);"
                            PRINT " iRange=pSizes->nGridCols;"
                            PRINT " iRows=pSizes->nGridRows;"
                            PRINT " k=pMyScrollInfo->yPos;"
                            PRINT " for(i=1;i<=iRows;i++)"
                            PRINT " {"
                            PRINT "     if(k<=pSizes->nBufferRows)"
                            PRINT "     {"
                            PRINT "        for(j=1;j<=iRange;j++)"
                            PRINT "        {"
                            PRINT "            dwGridNum=dwLoc(i,j);"
                            PRINT "            hCell=pHdls->pCells[dwGridNum];"
                            PRINT "            dwBufferNum=dwLoc(k,j);"
                            PRINT "            SetWindowLong(hCell,0,(long)pData[dwBufferNum]);"
                            PRINT "        }"
                            PRINT "        k++;"
                            PRINT "     }"
                            PRINT " }"
                            PRINT "}"
                            ReadConsoleOutput hOut, lpBuffer, dwBufferSize, dwBufferCoord, lpReadRegion
                            STDOUT "Console Buffer read, press any key to clear screen..."
                            COLOR 7, 0
                            PRINT "Press a key to restore buffer..."
                            WriteConsoleOutput hOut, lpBuffer, dwBufferSize, dwBufferCoord, lpWriteRegion
                        END FUNCTION
                        Adam Drake


                        • #13
                          Simple is better...


                          If you are going to add graphics and you want to keep it simple, you could use the little freeware PRINTKEY.EXE that
                          capture the console screen by simply hitting the good old Print Screen Key on your keyboard.
                          It will save the whole screen or only part of it as BMP format with any graphics and colors.
                          So, you will be able to take a picture anytime you will need it and give it a significant name.
                          Google it with PRINTKEY.EXE and Alfred Bollinger
                          Last edited by Guy Dombrowski; 13 Mar 2008, 08:12 PM.
                          Old QB45 Programmer


                          • #14
                            Simple is better yes, however, the tools are available at your finger tips through some PB functionality and the Windows API to allow you to screen cap to the clipboard and to a file:

                            #COMPILE EXE
                            #DIM ALL
                            #INCLUDE "WIN32API.INC"
                            GLOBAL hBmpGraphic AS LONG
                            FUNCTION PBMAIN() AS LONG
                                STDOUT "Testing, 1, 2, 3, 4"
                                CALL ScreenCapture(CONSHNDL)
                                IF hBmpGraphic THEN
                                    GRAPHIC SAVE "C:\TEST.BMP"
                                    GRAPHIC ATTACH hBmpGraphic, 0
                                    GRAPHIC BITMAP END
                                END IF
                                ShellExecute %HWND_DESKTOP, "open", "C:\TEST.BMP", "", "", %SW_SHOWNORMAL
                            END FUNCTION
                            SUB ScreenCapture(hWnd AS DWORD)
                                LOCAL hDC       AS DWORD
                                LOCAL nWidth    AS LONG
                                LOCAL nHeight   AS LONG
                                LOCAL hMemDC    AS DWORD
                                LOCAL hBmp      AS DWORD
                                LOCAL hBmpOld   AS DWORD
                                LOCAL rc        AS RECT
                                LOCAL x, y      AS LONG
                                LOCAL lClr      AS LONG
                                GetWindowRect hWnd, rc
                                hBmp=CreateCompatibleBitmap(hDC, nWidth, nHeight)
                                hBmpOld=SelectObject(hMemDC, hBmp)
                                BitBlt hMemDC, 0, 0, nWidth, nHeight, hDC, 0, 0, %SRCCOPY
                                CALL CopyToGraphicBitmap(hDC, nWidth, nHeight, 0, 0)
                                IF OpenClipboard(%HWND_DESKTOP) THEN
                                    SetClipboardData %CF_BITMAP, hBmp
                                    ' Error
                                END IF
                            END SUB
                            SUB CopyToGraphicBitmap(hDC AS DWORD, nWidth AS LONG, nHeight AS LONG, xPos AS LONG, yPos AS LONG)
                                LOCAL hDCGFX    AS DWORD
                                LOCAL x2        AS LONG
                                LOCAL y2        AS LONG
                                IF hBmpGraphic THEN
                                    GRAPHIC ATTACH hBmpGraphic, 0
                                    GRAPHIC BITMAP END
                                    RESET hBmpGraphic
                                END IF
                                GRAPHIC BITMAP NEW nWidth, nHeight TO hBmpGraphic
                                GRAPHIC ATTACH hBmpGraphic, 0
                                GRAPHIC GET DC TO hDCGFX
                                BitBlt hDCGFX, 0, 0, nWidth, nHeight, hDC, xPos, yPos, %SRCCOPY
                            END SUB
                            Adam Drake


                            • #15
                              here is the a tsr to print the screen to a device:lpt1..lpt4 or to a file.
                              i had help here in writing this code and i believe the source is listed here.
                              you can get the the first version which i have been using and the second i worked on but never really tried, but i believe it works ok.
                              this was written for msdos and is a tsr.
                              it might buy you some time till you get the software going like you want.
                              even though i compiled it, i had much help, therefore i can not call this jewel my own.

                              pressing F12 will dump the screen in text mode to whatever you placed on the command line.

                              you could use another(write) a program to monitor the directory for file changes if you wanted to print to a windows printer or do whatever with the text from the console window.
                              the program works well with network printers
                              you can redirect a lpt? port to a networked printer or

                              to a usb printer that has been setup to be a shared device.
                              if you have the file/printer sharing installed in your network connections dialog, you can share a device on you local computer and not
                              have the file/printer sharing turned on(checked) and still use the usb device as a shared device on your local computer and not body else
                              well be able to share your file/printers

                              and something i never tried by should, would be to give the file name as a shared device like \\computer\printersharename, never really thought about that one.


                              Last edited by Paul Purvis; 14 Mar 2008, 02:17 PM.
                              p purvis


                              • #16
                                SaveConsole1 seems to run about 1.2 times faster than SaveConsole2 per call.
                                Any 'slowness' in SaveConsole2 has nothing to do with console I-O. It's caused by our old friend 'needless string concatenation""
                                FOR y = 1 TO SCREENY
                                        FOR x = 1 TO SCREENX
                                            tmp = tmp + CHR$(SCREEN(y, x))
                                        tmp = tmp + $CRLF
                                Just build a buffer to hold all the characters first. Instead of contenating each character individually, use MID$= to replace the characters

                                Let's see if I can do this on-line....
                                nRow = ScreenY
                                nCol   = ScreenX 
                                Buff = SPACE$(NRow*nCol  +  2*nRow)   ' add 2* nrow to make space for a CRLF each row
                                iPos = 0 
                                FOR y = 1 TO SCREENY
                                        FOR x = 1 TO SCREENX
                                            INCR ipos
                                            MID$(BUff, iPos1, 1) =  CHR$(SCREEN(y, x))
                                         INCR ipos
                                         MID$ (BUff, iPos, 2 ) = $CRLF
                                         INCR ipos    ' for the CR
                                         INCR ipos    ' for the LF
                                Heck, that's gotta be close, anyway.

                                Never do lots of string concatenation like this when you don't have too... unless you want to have your software run like a dog.

                                All the WinApi calls in the world are not going to help near as much as will using good technique with the intrinsic BASIC language tools provided.

                                The fault, Dear Brutus, is not in our stars, it is in our selves.

                                Last edited by Michael Mattias; 14 Mar 2008, 09:21 AM.
                                Michael Mattias
                                Tal Systems (retired)
                                Port Washington WI USA
                                [email protected]


                                • #17
                                  (Yes, I know. I could have used BYTE PTRs and avoided all the CHR$() calls. But that would obfuscate my main point).
                                  Michael Mattias
                                  Tal Systems (retired)
                                  Port Washington WI USA
                                  [email protected]


                                  • #18
                                    There is An Easier Way

                                    You can copy and paste all or part of the console screen output by just using your mouse and keyboard. Drag the mouse over the sections that you want to copy with the left button held down. But the copy function is not activated with the expected Ctrl+C combo. Instead, just press the Enter key. That will put the info on the keyboard. Then you can paste it elsewhere using the normal Ctrl+V key combo.

                                    Note: If you plan to do this, do not try to use WAITKEY$ to pause your program, because you might satisfy it when you press the Enter key or a cursor movement key and lose your displayed output. You can substitute a DO:LOOP to make the screen stick around, or test for a specific key, such as $ESC being pressed to terminate the program or clear the screen at that point.