What's the best way (if there is one) to determine if a user can create a read/write file in a particular folder?
i.e. a folder protected by Vista
Larry
			
			
			
				The OPENFILE function will return a value of 0 if it was successful, and 1 if it fails.  You could use it to determine if a file can be opened for writing:
DEF myfile as BFILE
IF OPENFILE(myfile, "C:\\temp.txt", "W") = 0
    MESSAGEBOX 0, "File successfully opened for writing.","Woot!"
    CLOSEFILE myfile
ELSE
    MESSAGEBOX 0, "Could not open file for writing.","Error!"
ENDIF
			
			
			
				I just didn't know if it was going to be that simple and straight-forward on Vista.
Larry
			
			
			
				You can also use the GetFileAttributes to get info on files and folders:
DECLARE "kernel32.dll", GetFileAttributesA(lpFileName:STRING),INT
CONST FILE_ATTRIBUTE_ARCHIVE = 0x20 				:'32 
CONST FILE_ATTRIBUTE_COMPRESSED = 0x800 			:'2048
CONST FILE_ATTRIBUTE_DEVICE = 0x40 					:'64
CONST FILE_ATTRIBUTE_DIRECTORY = 0x10 				:'16
CONST FILE_ATTRIBUTE_ENCRYPTED = 0x4000 			:'16384
CONST FILE_ATTRIBUTE_HIDDEN = 0x2 					:'2
CONST FILE_ATTRIBUTE_NORMAL = 0x80 					:'128
CONST FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000 	:'8192
CONST FILE_ATTRIBUTE_OFFLINE = 0x1000 				:'4096
CONST FILE_ATTRIBUTE_READONLY = 0x1 				:'1
CONST FILE_ATTRIBUTE_REPARSE_POINT = 0x400 			:'1024
CONST FILE_ATTRIBUTE_SPARSE_FILE = 0x200 			:'512
CONST FILE_ATTRIBUTE_SYSTEM = 0x4 					:'4
CONST FILE_ATTRIBUTE_TEMPORARY = 0x100 				:'256
FileAttributes=GetFileAttributesA("C:\\Program Files")
MESSAGEBOX 0,STR$(fileattributes),""
END
I dont use Vista, so I cant exactly do any testing for it.  Just throwing out ideas here. 
			
			
			
				thanks
Larry
			
			
			
				GetFileAttributes can't be used to determine whether a folder is read-only.  At least according to the Microsoft docs.
			
			
			
				Msdn GetFileAttributes function page:
http://msdn.microsoft.com/en-us/library/aa364944(VS.85).aspx (http://msdn.microsoft.com/en-us/library/aa364944(VS.85).aspx)
leads to the File attributes page listing the different types and values:
http://msdn.microsoft.com/en-us/library/ee332330(VS.85).aspx (http://msdn.microsoft.com/en-us/library/ee332330(VS.85).aspx)
and under the FILE_ATTRIBUTE_READONLY section it lists:
QuoteA file that is read-only. Applications can read the file, but cannot write to it or delete it. This attribute is not honored on directories. For more information, see "You cannot view or change the Read-only or the System attributes of folders in Windows Server 2003, in Windows XP, or in Windows Vista".
and when you click the "for more information, see" link, it brings you to this page:
http://support.microsoft.com/kb/326549 (http://support.microsoft.com/kb/326549)
Which has absolutely nothing to do with the function at all...it was about using the Attrib command in dos (or whatever the current equivilent is) to change the read only flags of the folders...  lol. Leave it to microsoft to give thier website attention defeciet dis-hey wanna go ride bikes?  
I didnt really find anything that said that te function would not return the appropriate values for readonly folders... its kind of late, so maybe Im missing something here... 
			
				"You cannot view or change the Read-only or the System attributes of folders in Windows Server 2003, in Windows XP, or in Windows Vista"
Which is saying the FILE_ATTRIBUTE_READONLY bit isn't returned (viewable) when the function is used on a folder (directory).
Never tried it though.
			
			
			
				Okay, so I'm getting confused by Microsoft's logic here.  lol.
It says:
For more information, see "You cannot view or change the Read-only or the System attributes of folders in Windows Server 2003, in Windows XP, or in Windows Vista".
This is where it gets confusing.  The "You cannot view .... " line isnt actually a statement, but in fact is the title of the page that it is linked to.  Its a knowledge base article about people having problems viewing or changing the attributes of folders, not with the GetFileAttributes or SetFileAttributes, but in general. 
When you click the link, it brings you to a page that has nothing to do with the GetFileAttributes function.  This is what confused me.  It should have been linked to a page that describes why you cannot get the read only flag from winxp and higher, instead of a page that tells you how to change the attributes of files and folders using the ATTRIB.EXE program. 
Now, I've just been trying to get the read only attributes of a folder in WinXP using GetFileAttributes.   It works, and it doesnt work at the same time... lol.   If you change the ReadOnly flag within the folder properties page, then it will not return the read only flag, it returns 16 (FILE_ATTRIBUTE_DIRECTORY).   However, if you change the read only flag using ATTRIB.EXE +R then GetFileAttributes will return 17 for the directory (FILE_ATTRIBUTE_DIRECTORY and FILE_ATTRIBUTE_READONLY).
So, it DOES work, but only if the read only flag is set by the ATTRIB.EXE  program.  Apparently setting the read-only flag in the folder properties window does nothing, since it always reverts back to a grayed out checkbox that is checked. 
   ??? 
Leave it to Microsoft to take something simple like file attributes and make it complex and  awkward.....  
			
			
			
				Larry, maybe this little subroutine will show what you need:$include "windowssdk.inc"
$include "aclapi.inc"
if (!CheckDirectoryAccess2("c:\\")) then CheckDirectoryAccess("c:\\")
' method 1: uses security api
sub CheckDirectoryAccess(string path)
	HANDLE hFile = CreateFile(path, MAXIMUM_ALLOWED, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)
	if (hFile = INVALID_HANDLE_VALUE)
		_MessageBox(0, "CreateFile error")
	else
		pointer dacl
		pointer pSecurityDesc
		if (GetSecurityInfo(hFile, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, &dacl, NULL, &pSecurityDesc))
			_MessageBox(0, "GetSecurityInfo error")
		else
			ACCESS_MASK access
			TRUSTEE tr
			tr.pMultipleTrustee = 0
			tr.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE
			tr.TrusteeForm = TRUSTEE_IS_NAME
			tr.TrusteeType = TRUSTEE_IS_USER
			tr.ptstrName   = "CURRENT_USER"
			if (GetEffectiveRightsFromAcl(dacl, &tr, &access))
				_MessageBox(0, "GetEffectiveRightsFromAcl error", "")
			else
				ShowAccess(access)
			endif
			LocalFree(pSecurityDesc)
		endif
		CloseHandle(hFile)
	endif
endsub
sub ShowAccess(ACCESS_MASK access)
	string txt = ""
	' selected set of flags from "File Security and Access Rights"
	if (access & DELETE_CONTROL) then txt += "DELETE\n"
	if (access & FILE_ADD_FILE) then txt += "FILE_ADD_FILE\n"
	if (access & FILE_ADD_SUBDIRECTORY) then txt += "FILE_ADD_SUBDIRECTORY\n"
	if (access & FILE_ALL_ACCESS) then txt += "FILE_ALL_ACCESS\n"
	if (access & FILE_DELETE_CHILD) then txt += "FILE_DELETE_CHILD\n"
	if (access & FILE_LIST_DIRECTORY) then txt += "FILE_LIST_DIRECTORY\n"
	if (access & FILE_READ_ATTRIBUTES) then txt += "FILE_READ_ATTRIBUTES\n"
	if (access & FILE_READ_EA) then txt += "FILE_READ_EA\n"
	if (access & FILE_TRAVERSE) then txt += "FILE_TRAVERSE\n"
	if (access & FILE_WRITE_ATTRIBUTES) then txt += "FILE_WRITE_ATTRIBUTES\n"
	if (access & FILE_WRITE_EA) then txt += "FILE_WRITE_EA\n"
	if (access & STANDARD_RIGHTS_READ) then txt += "STANDARD_RIGHTS_READ\n"
	if (access & STANDARD_RIGHTS_WRITE) then txt += "STANDARD_RIGHTS_WRITE\n"
	_MessageBox(0, txt, "Effective Rights")
endsub
type OBJECT_BASIC_INFORMATION ' un
	ULONG Unknown1
	ACCESS_MASK DesiredAccess
	ULONG HandleCount
	ULONG ReferenceCount
	ULONG PagedPoolQuota
	ULONG NonPagedPoolQuota
	BYTE  Unknown2[32]
endtype
enum OBJECT_INFORMATION_CLASS
	ObjectBasicInformation = 0
endenum
' method 2: uses native api
sub CheckDirectoryAccess2(string path),BOOL
	BOOL success = FALSE
	declare NTQO(HANDLE ObjectHandle, OBJECT_INFORMATION_CLASS ObjectInformationClass, PVOID ObjectInformation, ULONG Length, pointer ResultLength),int
	UINT NtQueryObject = GetProcAddress(GetModuleHandle("ntdll"), "NtQueryObject")
	if (NtQueryObject)
		HANDLE hFile = CreateFile(path, MAXIMUM_ALLOWED, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,_
			0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)
		if (hFile = INVALID_HANDLE_VALUE)
			_MessageBox(0, "CreateFile error")
		else
			OBJECT_BASIC_INFORMATION obi
			ULONG cch
			if (!<NTQO>NtQueryObject(hFile, ObjectBasicInformation, &obi, len(obi), &cch))
				_MessageBox(0, "NtQueryObject error")
			else
				success = TRUE
				ShowAccess(obi.DesiredAccess)
			endif
			CloseHandle(hFile)
		endif
	endif
	return success
endsub
The second option is much (faster?) better, because NtQueryObject is accepting any (real) handle: file, directory, registry, pipe, mutex... without additional flag changes like SE_FILE_OBJECT in GetSecurityInfo.
			
			
			
				thanks Sapero
Larry
			
			
			
				Nice snippet.  I saw a few people using the CreateFile function in a similar manner in other languages when I was trying to figure this out, but didnt have time to dig too deep into it.  I was also looking at the SHGetFileInfo function in the shell32.dll but I didnt have any luck with that.  Thanks  :)