QB64 Phoenix Edition
Issue with code? - Printable Version

+- QB64 Phoenix Edition (https://staging.qb64phoenix.com)
+-- Forum: Official Links (https://staging.qb64phoenix.com/forumdisplay.php?fid=16)
+--- Forum: QB64 Phoenix Edition Wiki and Repo (https://staging.qb64phoenix.com/forumdisplay.php?fid=41)
+---- Forum: Repo Discussion (https://staging.qb64phoenix.com/forumdisplay.php?fid=42)
+---- Thread: Issue with code? (/showthread.php?tid=699)

Pages: 1 2


Issue with code? - bobkreid - 07-29-2022

I am writing a small sub to gather the available drives on a system (windows) and I am getting spurious items printed on to the console window.  There are no print statements so the screen should be blank
[Image: 1screen.jpg]



Code: (Select All)
Dim Shared Drive$
Dim Shared DrvErr
Dim Shared DriveName$(27)
Dim Shared DriveNum%

DECLARE SUB FindDrives ()       '*** Find which drives are on the PC ***

FindDrives
'For x% = 1 To DriveNum%
'    Print DriveName$(x%)
'Next x%
'End

DriveErr:
If Err = 68 Then ProgErr = 1
DrvErr = 1
Resume Next

End



Sub FindDrives
    DriveNum% = 0
    '*** Find what drives are present in the PC ***

    Erase DriveName$
    On Error GoTo DriveErr
    For Count = 65 To 90
        DrvErr = 0
        Drive$ = Chr$(Count) + ":\"
        Files Drive$
        If DrvErr = 0 Then
            DriveNum% = DriveNum% + 1
            DriveName$(DriveNum%) = Chr$(Count)
        End If
    Next Count

End Sub


When using $Debug to watch execution, I get program crashes and windows messages that a problem has caused the program to stop working correctly. 

Not sure what is happening here, but it looks like a memory issue.


RE: Issue with code? - RhoSigma - 07-29-2022

If you are not depend, that your programs are Linux/Mac compatible, but working on Windows only, then you may use a WinAPI call and do some bit puzzeling.

Code: (Select All)
DECLARE LIBRARY
    FUNCTION GetLogicalDrives& ()
END DECLARE

'Find all currently available drives in one compact string.
PRINT CurrDrives$

'Test for a particular drive.
IF INSTR(CurrDrives$, "E") > 0 THEN
    PRINT "Drive E: is available."
ELSE
    PRINT "Drive E: is not available."
END IF
END

FUNCTION CurrDrives$
cdm& = GetLogicalDrives&
drives$ = "": i& = (2 ^ 25): d% = ASC("Z")
DO
    IF (cdm& AND i&) THEN drives$ = CHR$(d%) + drives$
    i& = i& \ 2: d% = d% - 1
LOOP UNTIL i& = 0
CurrDrives$ = drives$
END FUNCTION

On my system it prints:
Quote:CDEF
Drive E: is available.



RE: Issue with code? - bobkreid - 07-29-2022

Thank you for that code, I may use it as a work around.  I am only using QB64 operands and I do not think I am doing anything that is not allowed by QB64, I do not believe it should fail as it appears to be.  If you or anyone else would try the code and see if they have similar issues or if some one could point out where my code is incorrect that would be great. 

I really think this is a bug but I am not sure if it is with the on Error or with File$. If it is not a bug and it is my code, there are no errors in the IDE or during compile to indicate I may be causing an issue. If I am abusing either the on error or the File$, I do not see it, so I think I am doing something that is syntactically correct.


RE: Issue with code? - JRace - 07-29-2022

Count the lines in your output display.  It looks like FILES is printing something for each drive that you check for.

In your screenshot, "C:\USERS\BOB\QB64\SOURCE\FILE" is the last directory successfully listed.

It looks like the extra text lines are being printed by the FILES statement, with one line printed for each non-existent drive that the program checks for.

I added a line to your program, "Print "{{{ "; Drive$; " }}}", directly above the FILES line.  Screenshot of test run:
[Image: QB-BUGHUNT.png]

The PRINT statement tells us which drive is being checked for.
Note how FILES prints the name of the current working directory for each non-existent drive that it is run for.



Instead of FILES, you might try the _DIREXISTS function (https://qb64phoenix.com/qb64wiki/index.php/DIREXISTS), looking for "/" (the root directory) on each drive:
"A:/"
"B:/"
"C:/"
and so on. I'm using the forward slash (instead of the Windows-specific backslash) for multi-OS compatibility.

Here's a quick test, which works on my Win7 machine (although it does not show my DVD drive, E:, since that drive is empty):
Code: (Select All)
DefInt A-Z
found$ = ""
For test = Asc("A") To Asc("Z")
    lookfor$ = Chr$(test) + ":/"
    If _DirExists(lookfor$) Then found$ = found$ + Chr$(test)
Next
Print found$



RE: Issue with code? - Pete - 07-29-2022

The creator of QB64, Rob, wasn't very enthusiastic about implementing the FILES statement into QB64. He did so for compatibility sake only. FILES is probably one of the least reliable QBasic statements ever made. Now you mentioned you shouldn't see anything printed to the screen, because you didn't use a print statement, but the thing is FILES prints to the screen all by itself! The few times I messed with it, I made a hidden screen to hide the output, and then used the screen command to read the hidden output and place it in string variable. That would work, without intrusion to your working screen, oh, provided the output will fit on the hidden screen without scrolling it! If you have too much output, the screen scrolls, and then reading that screen becomes virtually impossible. Long story short, use something better than FILES.

Substitute routines include error trapping to see if a drive exists (old school for QBasic). Some old school PEEK/POKE routines which I no longer have as I believe they may no longer be supported, not sure, and the _DRIVEEXISTS QB64 command.

Here is a demo with the two examples I mentioned above.

Code: (Select All)
WIDTH 80, 41
FOR i = 1 TO 26
    drive$ = CHR$(i + 64) + ":\"
    PRINT drive$,
    IF _DIREXISTS(drive$) THEN PRINT "Drive exists: " + drive$ ELSE PRINT
NEXT
PRINT: PRINT "Press a key to run the error trap method."
SLEEP
CLS
ON ERROR GOTO trap
FOR i = 1 TO 26
    drive$ = CHR$(i + 64) + ":\"
    OPEN drive$ + "null" FOR INPUT AS #1
NEXT

trap:
IF ERR = 53 THEN PRINT "Drive " + drive$ + " exists and is active."
IF ERR = 68 THEN PRINT "Drive " + drive$ + " exists and is inactive."
RESUME NEXT

Note that _DIREXISTS only finds the active drives, while the trap method also finds inactive ones, like an optical drive without media present.

If you would like any explanation of how either or both work, let me know. Also, all of us here love the past, so please, please, please never hesitate to post things from the QJurassic Period. A lot of us old dinosaurs here will be happy to help! Come to think of it we only had one Dumbassosaurus in the herd, but he's been extinct for a long time! I guess you could say he went from crude to crude. Oh well.

Pete


RE: Issue with code? - JRace - 07-29-2022

QB64 has such a huge built-in function set that I figured something appropriate must exist, so after a quick Wiki check I tried _FILEEXISTS, looking for the current directory on each drive: "A:\.", etc.  I've done that before, but not on QB64 where it didn't work.

OK, back to the Wiki and lookee here!  _DIREXISTS!

I learned 2 new QB64 keywords today!

Back in my TRS-80 days I built a crude file selector using Model III Basic's equivalent to FILES (CMD"D:<drive>").  Same story as yours.  If too many files caused the screen to scroll... oh well.  Of course those were the days of single-sided floppy drives, which made scrolling much less likely.


RE: Issue with code? - Pete - 07-29-2022

Yep, _DIREXISTS was a much appreciated QB64 addition.

I use _FILEEXISTS extensively before performing most file open routines. It really saves on building error trapping routine.

It is interesting to note _DIREXISTS was not made to detect inactive drives though. You need my old error trapping routine or Rhos' Windows API routine for that, although the API routine does not seem to indicate activity / inactivity (Device not read) as does the error trapping method.

Fun stuff!

Pete


RE: Issue with code? - SMcNeill - 07-29-2022

If one is talking Windows, there's a ton of simple ways you can get drive info:

Code: (Select All)
Screen _NewImage(1024, 720, 32)

Shell _Hide "cmd /c wmic logicaldisk get name >temp.txt"
Open "temp.txt" For Input As #1
Do Until EOF(1)
    Line Input #1, file$
    Print file$
Loop
Close

Sleep

Shell _Hide "cmd /c wmic logicaldisk get caption >temp.txt"
Open "temp.txt" For Input As #1
Do Until EOF(1)
    Line Input #1, file$
    Print file$
Loop
Close

Sleep



Shell _Hide "cmd /c wmic logicaldisk get deviceid, volumename, description  >temp.txt"
Open "temp.txt" For Input As #1
Do Until EOF(1)
    Line Input #1, file$
    Print file$
Loop
Close

Sleep

Shell _Hide "cmd /c fsutil fsinfo drives >temp.txt"
Open "temp.txt" For Input As #1
Do Until EOF(1)
    Line Input #1, file$
    Print file$
Loop
Close

Sleep


Shell _Hide "powershell get-psdrive -psprovider filesystem >temp.txt "
Open "temp.txt" For Input As #1
Do Until EOF(1)
    Line Input #1, file$
    Print file$
Loop
Close

Sleep


Note that I've set some of the above to give just bare bone information, whereas other examples give more details.  The fsutil command will even give you listings of mapped drives, if you need those, while powershell can tell you everything under the sun, if you just care enough to give it the proper parameters and such.  

Note 2: Some of these return unicode names, and will appear to be with an extra space between each letter.  You can filter that out easily enough, if interested.


RE: Issue with code? - Pete - 07-29-2022

cmd /c won't work on Windows 98. You need command /c for that! Hey, remember when we had a version of QB64 that actually ran on Windows 98?

Anyway, Rob pretty much deprecated the whole need for using cmd /c. START, however, I believe still seems to be needed for some shells to work properly, like START /min. So in the above examples, cmd /c can be included or eliminated from the code.

Good alternative examples though! I use SHELL a lot, and powershell features like text to speech rock.

Pete


RE: Issue with code? - SMcNeill - 07-29-2022

@Pete Lately, I've gotten in the habit of specifying "cmd" or "powershell" for my SHELL calls. Oddly enough, not all commands work the same in each environment. Take "curl -v" for example -- from a command prompt it'll give you version information; whereas from powershell it just gives *nothing*. (Or at least nothing useful that I remember -- it might give an error message or not implemented message or some junk about not being found on the system, but it's nothing useful.)