CreateDir 在 QB64 中抛出异常

CreateDir throws exception in QB64

我有以下代码,有时 returns 在尝试创建新目录时出错。有时当该目录不存在时,它会抛出错误并且不会创建该目录。我想知道为什么?

DECLARE DYNAMIC LIBRARY "kernel32"
    FUNCTION CreateDirectoryA% (F$, X$)
    FUNCTION GetLastError& ()
END DECLARE
F$ = "TEMPX" + CHR$(0) ' new directory to create
x = CreateDirectoryA(F$, CHR$(0))
IF x = 0 THEN
    IF GetLastError = &H3E6 THEN
        PRINT "Invalid access to memory location."
    END IF
END IF

这段代码是用QB64写的。

此代码在发生异常 x3E6 时强制创建目录,但确实首先解释了错误发生的原因:

DECLARE DYNAMIC LIBRARY "kernel32"
    FUNCTION CreateDirectoryA% (F$, X$)
    FUNCTION GetLastError& ()
END DECLARE
DO
    F$ = "TEMPX" + CHR$(0) ' new directory to create
    x = CreateDirectoryA(F$, CHR$(0))
    IF x THEN ' successful create
        EXIT DO
    END IF
    IF x = 0 THEN
        REM Test for Invalid access to memory location.
        IF GetLastError = &H3E6 THEN
            _DELAY .2
        ELSE
            EXIT DO
        END IF
    END IF
LOOP

您作为 CreateDirectoryAlpSecurityAttributes 参数传递的是长度为 0 的字符串;字符串仍然有内存地址,这意味着你传递的是一个非空指针。这被 CreateDirectoryA 解释为指向 SECURITY_ATTRIBUTES structure 的指针,其第一个字节设置为 0。结构中的其余字节是您尚未初始化的内存,这意味着结构的第一个字段 nLength一个小端机器可能类似于 0xFFFFFF00,即 4294967040——一个无效的大小。该结构的 lpSecurityDescriptor 字段可能也填充了字节(您的程序可能可以访问,但也许不能访问),因此这也可能导致问题。

您可以轻松解决此问题:

' X%& may also be written X AS _OFFSET.
FUNCTION CreateDirectoryA% (F$, BYVAL X%&)

...

x = CreateDirectoryA(F$, 0)

这导致正确传递 NULL 指针。 BYVAL 关键字是必需的,否则您将传递一个指向 _OFFSET 值的指针(因为 QB64 中的所有内容都是通过指针传递的,除非您使用 BYVAL 关键字;字符串和用户-无法传递定义的类型 BYVAL).

然后我 运行 在路径中创建子目录时遇到问题,所以我这样写:

DECLARE DYNAMIC LIBRARY "kernel32"
    FUNCTION CreateDirectoryA% (F$, BYVAL X&&)
    FUNCTION GetLastError& ()
END DECLARE
DO ' get directory
    PRINT "Dir";: INPUT Directory$
    IF Directory$ = "" THEN END
    GOSUB CreateDir
LOOP
END
CreateDir:
' construct path
Directory$ = RTRIM$(Directory$)
IF RIGHT$(Directory$, 1) <> "\" THEN
    Directory$ = Directory$ + "\"
END IF
' create path
x = 0
Next.Dir = INSTR(Directory$, "\")
DO
    IF Next.Dir = False THEN
        EXIT DO
    END IF
    SubDir$ = LEFT$(Directory$, Next.Dir - 1) ' \tempx\t1\t2\t3\
    Next.Dir = INSTR(Next.Dir + 1, Directory$, "\")
    ' make directory name
    IF LEN(SubDir$) THEN
        ' create directory
        f$ = SubDir$ + CHR$(0)
        x = CreateDirectoryA(f$, 0)
        ' check error
        IF x = 0 THEN
            IF GetLastError& = &HB7 THEN ' ignore already exists
                ' nul
            ELSE
                EXIT DO
            END IF
        END IF
    END IF
LOOP
IF x = 0 THEN
    PRINT "Error x"; HEX$(GetLastError&)
ELSE
    PRINT "Directory created."
END IF
RETURN

这样,如果您指定一个不存在的路径,它将创建整个路径名。例如,如果 \Temp 不存在,\Temp\t1\t2\t3。