(11-30-2023, 06:07 AM)eoredson Wrote: Hey. I got an idea for the makers of QB64pe:
Maybe you could add a KillDir(Dir$) function!?
That's what RMDIR does for you. It's just up to you to make certain the directory is empty, or use the function I provided above.
That is some nice code however I have been using the following code to do the same:
Code: (Select All)
Rem The Windows QB64 silent directory delete utility PD 2022.
Rem This code placed into the public domain free BASIC source.
Rem For usage please read Silent.txt which contains disclaimer notes.
' declare library structures.
Type FILETIME
dwLowDateTime As _Unsigned Long
dwHighDateTime As _Unsigned Long
End Type
Type SYSTEMTIME
wYear As Integer
wMonth As Integer
wDayOfWeek As Integer
wDay As Integer
wHour As Integer
wMinute As Integer
wSecond As Integer
wMilliseconds As Integer
End Type
Type WIN32_FIND_DATAA
dwFileAttributes As _Unsigned Long
ftCreationTime As FILETIME
ftLastAccessTime As FILETIME
ftLastWriteTime As FILETIME
nFileSizeHigh As _Unsigned Long
nFileSizeLow As _Unsigned Long
dwReserved0 As _Unsigned Long
dwReserved1 As _Unsigned Long
cFileName As String * Max_path
cAlternateFileName As String * 14
End Type
' declare external libraries.
Declare Dynamic Library "kernel32"
Function DeleteFileA% (F$)
Function FindFirstFileA~%& (ByVal lpFileName~%&, Byval lpFindFileData~%&)
Function FindNextFileA& (ByVal hFindFile~%&, Byval lpFindFileData~%&)
Function FindClose& (ByVal hFindFile~%&)
Function RemoveDirectoryA% (F$)
End Declare
Declare Library
Function GetFileAttributes& (f$)
Function SetFileAttributes& (f$, Byval a&)
End Declare
_Title "DELETE"
Print "Enter directory to delete";: Input G$
If _DirExists(G$) = 0 Then
Print "Directory not fuund."
End
End If
Print "Delete directory and all subfolders/files(y/n)?"
Do
_Limit 100
x$ = LCase$(InKey$)
If x$ = "n" Then End
If x$ = "y" Then Print: Print "OK..": Exit Do
Loop
If Right$(G$, 1) <> "\" Then G$ = G$ + "\"
Call Silentdel_Directories(G$)
If _DirExists(G$) = 0 Then
Print "Directory deleted."
Else
Print "Error deleting directory."
End If
End
' subroutine to access subdirectories
Sub Silentdel_Directories (Directory.Search$)
' declare subroutine variables
Dim Attribute As _Unsigned Long
Dim ASCIIZ As String * 260
Dim finddata As WIN32_FIND_DATAA
Dim Wfile.Handle As _Offset
' check directory
If (Attribute And &H10) = &H10 Then
' store directory name
Directory$ = finddata.cFileName
Directory$ = Left$(Directory$, InStr(Directory$, Chr$(0)) - 1)
' store short filename
If InStr(Directory$, "?") Then
Directory$ = finddata.cAlternateFileName
V = InStr(Directory$, Chr$(0))
If V Then Directory$ = Left$(Directory$, V - 1)
End If
' check directory name
If Directory$ <> "." And Directory$ <> ".." Then
' make next search directory
Next.Directory$ = Directory.Search$ + Directory$ + "\"
' recursively search subdirectories
Call Silentdel_Directories(Next.Directory$)
End If
End If
Loop While FindNextFileA(Wfile.Handle, _Offset(finddata))
x = FindClose(Wfile.Handle)
End If
' delete directory
Call Silentdel_DeleteDirectory(Directory.Search$)
End Sub
' subroutine to delete an empty directory
Sub Silentdel_DeleteDirectory (Directory$)
' declare subroutine variables
Dim ASCIIZ As String * 260
' store directory filename
ASCIIZ = Directory$ + Chr$(0)
' change directory attribute
AttrX& = GetFileAttributes(ASCIIZ)
AttrX& = AttrX& And Not &H1 ' remove read-only bit
x = SetFileAttributes&(ASCIIZ, AttrX&)
' delete directory
x = RemoveDirectoryA(ASCIIZ)
End Sub
' subroutine to delete files in a directory
Sub Silentdel_DeleteFiles (Directory$)
' declare subroutine variables
Dim Attribute As _Unsigned Long
Dim ASCIIZ As String * 260
Dim ASCIIZ2 As String * 260
Dim finddata As WIN32_FIND_DATAA
Dim Wfile.Handle As _Offset
' make filename
ASCIIZ = Directory$ + "*.*" + Chr$(0)
Wfile.Handle = FindFirstFileA(_Offset(ASCIIZ), _Offset(finddata))
If Wfile.Handle <> INVALID_HANDLE_VALUE Then
' filename loop
Do
' store filename
Filename$ = finddata.cFileName
Filename$ = Left$(Filename$, InStr(Filename$, Chr$(0)) - 1)
' check filename
If Filename$ <> "." And Filename$ <> ".." Then
' store filename
ASCIIZ2 = Directory$ + Filename$ + Chr$(0)
' change filename attribute
AttrX& = GetFileAttributes(ASCIIZ2)
AttrX& = AttrX& And Not &H1 ' remove read-only bit
x = SetFileAttributes&(ASCIIZ2, AttrX&)
' delete long filename
x = DeleteFileA(ASCIIZ2)
' check error and delete 8.3 filename
If x = 0 Then
Short.Filename$ = finddata.cAlternateFileName
V = InStr(Short.Filename$, Chr$(0))
If V Then Short.Filename$ = Left$(Short.Filename$, V - 1)
ASCIIZ2 = Directory$ + Short.Filename$ + Chr$(0)
' change filename attribute
AttrX& = GetFileAttributes(ASCIIZ2)
AttrX& = AttrX& And Not &H1
x = SetFileAttributes&(ASCIIZ2, AttrX&)
' delete short filename
x = DeleteFileA(ASCIIZ2)
End If
End If
Loop While FindNextFileA(Wfile.Handle, _Offset(finddata))
x = FindClose(Wfile.Handle)
End If
End Sub
I'm with you Terry -- I'm lost. If he's running QB64, what I shared works fine. If he's using QB45 then no new command we write will work. If he's using DosBox-X, as explained, the DELTREE works.
I have no idea what's being asked for here anymore. Honestly, I think I'm none even trying with this topic. Sometimes a guy just has to figure out a way for themselves.
(11-30-2023, 05:03 AM)eoredson Wrote: But it has to be backwards compatible with QB1, QB4, and QB7..
What is "QB1" and "QB7"?
I'm telling the general about someone else that has to be kept away from Linux. Purposely set a really long ridiculous password for him to make sure he could never be "root" user.
But... why is there such a need for a "nuke" directory command built into QB64?
What is one going to do after data loss and he/she realized the wrong directory was nuked?
BTW "deltree" was yet another way M$ purposely spoiled people and started counteracting with making Windows act more like Unix, in response to ongoing complaints that Windows didn't behave "multiuser" enough. Anyway, in Windows Vista and later the operating system would give someone a hard time with trying to eradicate directories, read-only files and what the system thinks are "my" files, unless it's being handled directly by an account with enough elevation.
Oh but this is only for programs to run inside DOSBOX. (facepalm)
But why does it have to work in QB64 as well? Better stick to floppy disks, Iomega ZIP disks and any platter smaller than 1GB. Anyway QB64 wouldn't work properly inside DOSBOX. Phoenix requires Windows Vista, doesn't it? And DOSBOX was designed to work primarily with 16-bit applications. So those are like two different worlds...
I think backward compatibility with QBasic, as far as supporting archaic commands in MS-DOS, is a red herring. "JOIN" and "SUBST" obviously don't work on Linux with Wine. The other day I had a program crashing on me for using a drive alias: instead of writing it as "Z:\home\user\Documents\somewhere\something.txt" I wanted to write it down as "Y:\something.txt", with the fake drive letter properly being assigned in the global Wine "prefix".
Apparently "RMDIR /S/Q" cannot be done in DOSBOX because the authors of DOSBOX feared the angry, fist-waving users very willing to lose their data LOL. "Let's just leave it out for safety. We have enough people crabbing about security having to do with that arr-eff-option thing."
Yeah, I just read every post on this thread and I have to agree with Steve and Terry... I am lost and think Eric is confusing QB64 with QuickBasic. To sum up what I've read:
1) QuickBasic <> QB64
2) DOSBOX is unable to run QB64
3) You should write your own function that checks everything first rather than just deleting the directory with zero regard
4) (Not something I've read but something I want to point out) Your WinAPI code is not going to work in DOSBOX
5) I am confused as all Hell as to what you are trying to achieve
This is a DB-INFO.BAT script someone wrote. You can see many ways to detect if running in dosbox here - you wouldn't implement the entire .BAT file of course, just pick one of the options, or a few and concatenate to test the result...
rem +--------------------------------------------------
rem ! DB-INFO 1.0.2 - Show essential DOSBox configuration
rem ! info.
rem !
rem ! By MiniMax
rem +--------------------------------------------------
:Usage
echo Usage DB-INFO [ /n ]
echo.
echo where /n indicates which page to view.
echo.
echo. Page 1 = DOSBox version and mount information.
echo. Page 2 - DOSBox emulated hardware.
echo. Page 3 - Directory listing of C:\ and D:\
echo.
echo If no page number is given all 3 pages will be shown.
goto End
:Main
rem Validate that DB-INFO is running inside DOSBox.
if not "%COMSPEC%" == "Z:\COMMAND.COM" goto NotDB
if not exist %COMSPEC% goto NotDB
if not exist Z:\LOADFIX.COM goto NotDB
if not exist Z:\MOUNT.COM goto NotDB
rem Figure out which version of DOSBox this is.
if not exist Z:\KEYB.COM goto else1
rem Version 0.66 introduced the KEYB.COM program, so we
rem are running 0.66 or later.
set CONFIG=66+
goto endif1
:else1
rem Version 0.65 introduced the CONFIG -GET option.
rem If the get-operation succeeds, the CONFIG-variable
rem will be set to something, and we are running 0.65.
rem If not, we are running 0.63 or earlier.
set CONFIG=
config -get sdl output > NUL:
if not "%CONFIG%" == "" set CONFIG=65
if "%CONFIG%" == "" set CONFIG=63-
:endif1
rem Check if only a specific page is requested.
if "%1" == "/1" goto Page1
if "%1" == "/2" goto Page2
if "%1" == "/3" goto Page3
:Page1
echo +--------------------------------------------------
echo ! Page 1 - DOSBox version and mounts.
echo +--------------------------------------------------
echo.
if "%CONFIG%" == "63-" echo DOSBox version 0.63 or earlier. Reported DOS version 5.0.
if "%CONFIG%" == "65" echo DOSBox version 0.65. Reported DOS version 5.0
if "%CONFIG%" == "66+" ver
echo.
rem If we are running version 0.63 or earlier, we can only
rem report on the BLASTER and GUS variables.
if "%CONFIG%" == "63-" goto Page2a
goto Page2b
:Page2a
rem +--------------------------------------------------
rem ! Page 2a - For DOSBox v.0.63 or earlier.
rem +--------------------------------------------------
rem The last attribute (T) of the BLASTER variable can tell us
rem which type of card we have. We will make a best-effort to
rem determine the card type.
rem
rem Type of card: 1=SB 1.5, 2=SB Pro I, 3=SB 2.0, 4=SB Pro II,
rem 6=SB 16, 7=SB AWE32.
set CONFIG=unknown
rem First check the standard IRQ 7 settings:
if "%BLASTER%" == "A220 I7 D1 T1" set CONFIG=sb1
if "%BLASTER%" == "A220 I7 D1 T2" set CONFIG=sbpro1
if "%BLASTER%" == "A220 I7 D1 T3" set CONFIG=sb2
if "%BLASTER%" == "A220 I7 D1 T4" set CONFIG=sbpro2
if "%BLASTER%" == "A220 I7 D1 T6" set CONFIG=sb16
if "%BLASTER%" == "A220 I7 D1 T7" set CONFIG=sbawe32
rem Version 0.62 and later added the HDMA setting.
if "%BLASTER%" == "A220 I7 D1 H5 T1" set CONFIG=sb1
if "%BLASTER%" == "A220 I7 D1 H5 T2" set CONFIG=sbpro1
if "%BLASTER%" == "A220 I7 D1 H5 T3" set CONFIG=sb2
if "%BLASTER%" == "A220 I7 D1 H5 T4" set CONFIG=sbpro2
if "%BLASTER%" == "A220 I7 D1 H5 T6" set CONFIG=sb16
if "%BLASTER%" == "A220 I7 D1 H5 T7" set CONFIG=sbawe32
rem Many games wants the SoundBlaster to use IRQ5 so we will
rem try that too:
if "%BLASTER%" == "A220 I5 D1 T1" set CONFIG=sb1
if "%BLASTER%" == "A220 I5 D1 T2" set CONFIG=sbpro1
if "%BLASTER%" == "A220 I5 D1 T3" set CONFIG=sb2
if "%BLASTER%" == "A220 I5 D1 T4" set CONFIG=sbpro2
if "%BLASTER%" == "A220 I5 D1 T6" set CONFIG=sb16
if "%BLASTER%" == "A220 I5 D1 T7" set CONFIG=sbawe32
rem Version 0.62 and later added the HDMA setting.
if "%BLASTER%" == "A220 I5 D1 H5 T1" set CONFIG=sb1
if "%BLASTER%" == "A220 I5 D1 H5 T2" set CONFIG=sbpro1
if "%BLASTER%" == "A220 I5 D1 H5 T3" set CONFIG=sb2
if "%BLASTER%" == "A220 I5 D1 H5 T4" set CONFIG=sbpro2
if "%BLASTER%" == "A220 I5 D1 H5 T6" set CONFIG=sb16
if "%BLASTER%" == "A220 I5 D1 H5 T7" set CONFIG=sbawe32
if not "%BLASTER%" == "" echo SBlaster sbtype = %CONFIG%
if not "%BLASTER%" == "" echo SBlaster BLASTER = %BLASTER%
if not "%ULTRASND%" == "" echo GUS gus = true
if not "%ULTRASND%" == "" echo GUS ULTRASND = %ULTRASND%
if not "%ULTRADIR%" == "" echo GUS ULTRADIR = %ULTRADIR%
goto EndP2
:Page2b
rem +--------------------------------------------------
rem ! Page 2b - For DOSBox v.0.65 or later.
rem +--------------------------------------------------
config -get dos xms > NUL:
echo DOS xms = %CONFIG%
config -get dos ems > NUL:
echo DOS ems = %CONFIG%
config -get dos umb > NUL:
echo DOS umb = %CONFIG%
:EndP2
if %1 == /2 goto End
echo.
pause
:Page3
echo +--------------------------------------------------
echo ! Page 3 - Directory listing of C:\ and D:\
echo +--------------------------------------------------
echo.
if not exist C:\. echo Drive C: is not mounted.
if exist C:\. dir C:\ /w
if exist C:\. echo.
if not exist D:\. echo Drive D: is not mounted.
if exist D:\. dir D:\ /w
if %1 == /3 goto End
echo.
pause
goto End
:NotDB
echo.
echo .--------------------------------------------------.
echo ! Error: DB-INFO must be run from *inside* DOSBox! !
echo '--------------------------------------------------'
echo.
pause
goto End
Dir$ = UCASE$(Dir$) 'old skool file names could only be ALL CAPS IFRIGHT$(Dir$, 1) <> "\"THEN Dir$ = Dir$ + "\"'coding this dor windows only. Make changes as necessary for Linux/Mac slashes and such 'Note that the UCASE$ line probably won't work with Linux/MAc as well, as they hold uppercase/lowercase to be case specific
CHDIR Dir$ 'change to the specified directory SHELL"cd > TEMP.TXT" OPEN"TEMP.TXT"FORINPUTAS #1 INPUT #1, Verify_Dir$ 'get the changed directory name CLOSE #1
Verify_Dir$ = UCASE$(Verify_Dir$) IFRIGHT$(Verify_Dir$, 1) <> "\"THEN Verify_Dir$ = Verify_Dir$ + "\"'make certain it matchs old skool formatting before verifying
IFUCASE$(Verify_Dir$) <> Dir$ THEN'verify that we're in the proper directory now PRINT"ERROR: INVALID DIRECTORY!"'if not, then error and die BEEP END END IF
OPEN"TEMP.TXT"FORINPUTAS #1 'can't use BINARY as we're going old skool! IFLOF(1) THEN'If there's any data in that file and it's not just blank REDIM DirList(10000) ASSTRING'If you have more than 10,000 directories on an old skool folder, you fail! DO
i = i + 1 LINE INPUT #1, DirList(i) LOOP UNTILEOF(1) REDIM_PRESERVE DirList(i) ASSTRING'free up unused memory in that array of dir lists END IF CLOSE #1 FOR j = 1TO i IF DirList(j) <> "."AND DirList(j) <> ".."THEN
Sub_Dir$ = Dir$ + DirList(j) + "\" RD_OldSkool Sub_Dir$ END IF NEXT
I believe every command in this little RD routine works in QB45 and lower. It also works in QB64 -- well, the Windows version of QB64. QB45 never ran on Linux or Mac, so it never followed their rules for slashes and filenames and such, so I certainly didn't bother to write this with those particulars in mind.
As before, I left a TEST variable for anyone who just wants to test this out. (Make it any non-zero value.) And, as before, I take **ZERO** responsibility if you point it to some folder/drive and erase it off the face of the earth. Use this at your own risk! Recursive File/Folder deletion isn't something suitable for most folks to run like this, and this DOES NOT move anything to the Recycle Bin. This ZAPS things to oblivion, making them lost forever more. (Unless you want to spend time and effort running some snazzy file recovery software to look for lost data on a drive and restore it. NOTE -- I WILL NOT HELP WITH ANY RESTORATION NEEDS FOR LOST DATA!! You have been warned here first, and repeatedly!)
11-30-2023, 02:35 PM (This post was last modified: 11-30-2023, 02:41 PM by mnrvovrfc.)
Quote:- Windows: shell command: 'rd /s`
I dislike insisting like this but also must add "/Q" switch so it just goes ahead and does its thing quietly, and doesn't ask any confirmation. To make it more equal to what has to be done on Linux with "root" permissions.
(11-30-2023, 06:58 AM)mnrvovrfc Wrote: what the system thinks are "my" files,
To clarify for some people, I meant files marked with "system" flag of the file attributes, apart from "archive", "hidden", "read-only"... and "directory". "system" flag assumes "hidden" as well such as "IO.SYS" and "MSDOS.SYS" in root directory which were sometimes a PITA to show in a file manager. But of course regular files do not get "directory" flag. This is for MS-DOS but I don't know if Windows still works in this way.
11-30-2023, 09:05 PM (This post was last modified: 11-30-2023, 09:08 PM by Kernelpanic.)
Microsoft introduced "Deltree" with MS-DOS 6.0 because quite a few people wanted a command that, like Unix/Linux, could delete entire directories, whether they were empty or not. It is dangerous for MS users because they are usually just pure users. But the command was useful, and still is for “power users” - but Explorer can also do it very quickly.
Attached is a Deltree for Windows 64 and one for 16 bit MS-DOS. Should also work under the DOS box. Deltree64 is clean and works. If one put it in a directory where the path points, you can call it from the command line.