David has the correct answer to avoid a range check error. But if you do not want to do this, you can still disable / enable {$RANGECHECKS} manually, just use {$IFOPT} to do this conditionally, so that the surrounding code will not be affected, for example:
function DirExists(Name: string): Boolean; var Code: Integer; begin {$IFOPT R+} {$DEFINE _RPlusWasEnabled} {$R-} {$ENDIF} Code := GetFileAttributesW(PChar(Name)); Result := (Code <> -1) and (FILE_ATTRIBUTE_DIRECTORY and Code <> 0); {$IFDEF _RPlusWasEnabled} {$UNDEF _RPlusWasEnabled} {$R+} {$ENDIF} end;
It is not enough to check the result of GetFileAttributes() only for INVALID_FILE_ATTRIBUTES . A directory may exist, but is simply not accessible. This is why the RTL DirectoryExists() function checks GetLastError() for several error codes ( ERROR_PATH_NOT_FOUND , ERROR_BAD_NETPATH , ERROR_NOT_READY , etc.), looking for this possible condition. Another thing DirectoryExists() can do is to check if the path specified is really a shortcut to the directory, and if so, check if the target directory exists or not.
Update: Here's the implementation of SysUtils.DirectoryExists() in XE3:
function DirectoryExists(const Directory: string; FollowLink: Boolean = True): Boolean; {$IFDEF MSWINDOWS} var Code: Cardinal; Handle: THandle; LastError: Cardinal; begin Result := False; Code := GetFileAttributes(PChar(Directory)); if Code <> INVALID_FILE_ATTRIBUTES then begin if faSymLink and Code = 0 then Result := faDirectory and Code <> 0 else begin if FollowLink then begin Handle := CreateFile(PChar(Directory), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); if Handle <> INVALID_HANDLE_VALUE then begin CloseHandle(Handle); Result := faDirectory and Code <> 0; end; end else if faDirectory and Code <> 0 then Result := True else begin Handle := CreateFile(PChar(Directory), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); if Handle <> INVALID_HANDLE_VALUE then begin CloseHandle(Handle); Result := False; end else Result := True; end; end; end else begin LastError := GetLastError; Result := (LastError <> ERROR_FILE_NOT_FOUND) and (LastError <> ERROR_PATH_NOT_FOUND) and (LastError <> ERROR_INVALID_NAME) and (LastError <> ERROR_BAD_NETPATH) and (LastError <> ERROR_NOT_READY); end; end; {$ENDIF MSWINDOWS} {$IFDEF POSIX} var StatBuf, LStatBuf: _stat; Success: Boolean; M: TMarshaller; begin Success := stat(M.AsAnsi(Directory, CP_UTF8).ToPointer, StatBuf) = 0; Result := Success and S_ISDIR(StatBuf.st_mode); if not Result and (lstat(M.AsAnsi(Directory, CP_UTF8).ToPointer, LStatBuf) = 0) and S_ISLNK(LStatBuf.st_mode) then begin if Success then Result := S_ISDIR(StatBuf.st_mode) else if not FollowLink then Result := True; end; end; {$ENDIF POSIX}
The implementation in XE4 is the same with only one difference - in the Windows version there is also a check for LastError <> ERROR_BAD_NET_NAME when calling GetLastError() .