FATTR - Sample file manipulation DLL for Microsoft Access
=========================================================

5/9/95 -- KNG
	Added SetFileDateTime() function
3/20/94 -- KNG
	Added Get/SetFileAttr() functions.


This is a DLL callable from Microsoft Access that contains the following
functions:

GetFileSize() - gets the size of a specified file
GetFileDateTime() - gets the timestamp of a specified file
GetDiskFree() - returns the amount of free disk space on a specifie drive
DosFindFirst() - returns the first file matching a specification
DosFindNext() - returns the next file from the original DosFindFirst()
ConvertDosTime() - converts the date/time information from DOS time to
		   Access time format
GetFileAttr() - Retrieve a specific file's DOS attribute (one or more of the 
		ATTR_*, constants listed below, added together
SetFileAttr() - Set a specific file's DOS attribute, using the sum of one
		or more of the ATTR_* constants.
SetFileDateTime() - Set the file date/time for any DOS file.

This is commonly requested information from Microsoft Access, however they
are not currently supplied by Access or the Windows API.

To use
------

Copy FATTR.DLL to your Access directory or Windows directory.

The file FATTR.MDB contains the following declarations:

Global Const ATTR_NORMAL = 0
Global Const ATTR_READONLY = 1
Global Const ATTR_HIDDEN = 2
Global Const ATTR_SYSTEM = 4
Global Const ATTR_LABEL = 8
Global Const ATTR_SUBDIR = 16
Global Const ATTR_ARCHIVE = 32

Type FINDFILE
  reserved As String * 21
  attrib As String * 1
  wr_time As Integer
  wr_date As Integer
  size As Long
  name As String * 13
End Type

' Both these functions return the file's attribute after the function call.
' On error, they return -2 if the file wasn't found, or -5 if permission was denied.
Declare Function GetFileAttr Lib "FATTR.DLL" Alias "GetFAttr" (ByVal strFileName As String) As Integer
Declare Function SetFileAttr Lib "FATTR.DLL" Alias "SetFAttr" (ByVal strFileName As String, ByVal intAttr As Integer) As Integer

Declare Function GetDiskFree Lib "FATTR.DLL" (ByVal disk As Integer) As Long
Declare Function ConvertDosTime Lib "FATTR.DLL" (ff As FINDFILE) As Double
Declare Function DosFindFirst Lib "FATTR.DLL" (ByVal FileName$, ByVal attrib%, ff As FINDFILE) As Integer
Declare Function DosFindNext Lib "FATTR.DLL" (ff As FINDFILE) As Integer
Declare Function GetFileDateTime Lib "FATTR.DLL" (ByVal FileName$) As Double
Declare Function GetFileSize Lib "FATTR.DLL" (ByVal FileName$) As Long
Declare Function SetFileDateTime Lib "FATTR.DLL" (ByVal FileName$, ByVal intYear%, ByVal intMonth%, ByVal intDay%, ByVal intHour%, Byval intMinute%, ByVal intSecond%) As Integer

Reference to Functions
======================

GetFileAttr()
-------------

Syntax    GetFileAttr(strFileName)

	  strFileName is the name of a file to examine.

Returns   an integer representing the file's attribute.
	  -2 if the file wasn't found.
	  -5 if permission was denied.

Notes

	  Use the ATTR_* attribute constants when checking 
	  and setting file attributes.
	  To see if a file is hidden:

	  intAttr = GetFileAttr("someFileName")
	  isHidden = intAttr AND ATTR_HIDDEN

SetFileAttr()
-------------

Syntax    SetFileAttr(strFileName, intAttrib)

	  strFileName is the name of a file for which to set the attribute.
	  intAttrib is the attribute to set for the file

Returns   The original file attribute.
	  -2 if the file wasn't found.
	  -5 if permission was denied.

Notes
	  To set a file to be hidden:
 
	  intAttr = GetFileAttr("someFileName")
	  intAttr = intAttr OR ATTR_HIDDEN
	  intAttr = SetFileAttr("someFileName", intAttr)
 
	  or

	  intAttr = SetFileAttr("someFileName", GetFileAttr("someFileName") OR ATTR_HIDDEN)


GetFileSize()
-------------

Syntax    GetFileSize(sFileName)

	  sFileName is the name of a file to examine.

Returns   a long integer representing the size of the file.

Notes     A full path may be necessary.  The function only looks for files
	  with normal attributes.  Hidden or system files will not be
	  searched for with this function.


GetDiskFree()
-------------

Syntax    GetDiskFree(nDrive)

	  nDrive is a number, where 1=A, 2=B, 3=C, etc.

Returns   a long integer representing the amount of disk space available on
	  the designated drive.

Notes     nDrive can also be 0, which means default drive.  Huge drives may
	  not be representable with a long integer, since longs are signed
	  under Access.


GetFileDateTime()
-----------------

Syntax    GetFileDateTime(sFileName)

	  sFileName is the name of a file to examine.

Returns   a double value, which is the internal representation of a date/time
	  under Access.

Notes     A full path may be necessary.  The date/time returned is a double,
	  but can be converted to a readable format with the Format function:

	     Format(GetFileDateTime("MSACCESS.EXE"), "Long Date")

SetFileDateTime()

Syntax	SetFileDateTime(sFileName, intYear, intMonth, intDay, intHour, intMinute, intSecond)

Returns	True/False, depending on its success

Notes	Don't call this function directly.  FATTR.MDB contains a wrapper function,
	SetFileDate(), which accepts a file name and an Access date/time value, which
	is far easier to use. Call it as:

	intSuccess = SetFileDate(strFileName, varDate)

	You CAN call SetFileDateTime() directly, but it's a bit more work.

DosFindFirst()
--------------

Syntax    DosFindFirst(sFileSpec, nAttrib, ffStruct)

	  sFileSpec is a valid DOS filespec, possibly including wildcards.
	  nAttrib can be one or more of the following OR'd together:
	    ATTR_NORMAL, ATTR_RDONLY, ATTR_HIDDEN, ATTR_SYSTEM, ATTR_ARCH, ATTR_VOLID,
	    ATTR_SUBDIR.
	  ffStruct is a variable of type FINDFILE.

Returns   Zero is successful.

Notes     To OR attributes together, either add them together or use the
	  OR operator.  Example:

	     (ATTR_NORMAL OR ATTR_RDONLY OR ATTR_SUBDIR)

	  ffStruct is filled in with the first file that meets the search
	  specification.  To retrieve the next file, use DosFindNext().

	  ffStruct contains the following elements:

	    name - an ASCII 0 terminated filename
	    attrib - a character attribute
	    wr_date/wr_time - the file timestamp
	    size - the file size

	  To convert the wr_date/wr_time format to something readable, you
	  should first call ConvertDosTime().

	  The attrib element will contain any file attributes OR'd together.
	  To extract a particular attribute, AND it with the attribute you
	  are querying.  For example, to determine if a file found is a
	  subdirectory, you can say something like

	    If (Asc(ffStruct.attrib) AND ATTR_SUBDIR) Then
	      MsgBox "It is a subdirectory!"
	    End If

	  Note that Asc() is necessary, because the element is a character.

	  The name element is zero terminated, which means you will need to
	  remove the ASCII 0 from the string.  The following code shows how
	  to do that:

	    If InStr(ffStruct.name, Chr(0)) > 0) Then
	       MyVar = Left(ffStruct.name, InStr(ffStruct.name, Chr(0)) - 1)
	    End If


DosFindNext()
-------------

Syntax    DosFindNext(ffStruct)

	  ffStruct is a variable of type FINDFILE.  It should have been
	  initialized by calling DosFindFirst() first.

Returns   Zero is successful.

Notes     DosFindNext() goes hand-in-hand with DosFindFirst().  A common way
	  to traverse a directory is as follows:

	    Dim status, ffStruct As FINDFILE
	    status = DosFindFirst("*.*", ATTR_NORMAL, ffStruct)
	    While status = 0 Then
	      status = DosFindNext(ffStruct)
	    Wend


ConvertDosTime()
----------------

Syntax    ConvertDosTime(ffStruct)

	  ffStruct is a variable of type FINDFILE.  It should be initialized
	  by DosFindFirst() or DosFindNext().

Returns   a double value, which is the internal representation of a date/time
	  under Access.

Notes     The date/time returned is a double, but can be converted to a
	  readable format with the Format function.  The following example,
	  goes through the Access directory and dumps the name and date of
	  every file to the Immediate Window:

	    Dim status, ffStruct As FINDFILE
	    status = DosFindFirst("*.*", ATTR_NORMAL, ffStruct)
	    While status = 0 Then
	      Debug.Print ffStruct.name &
		Format(ConvertDosTime(ffStruct), "Long Date")
	      status = DosFindNext(ffStruct)
	    Wend


Examples
=======

The following examples come in the FATTR.MDB.  It is a "whereis" program
written in Access Basic that uses the FATTR.DLL.  To use it, go to the Access
Immediate Window and type the following:

  ? whereis("C:\WINDOWS\", "*.DLL")

The program will then dump all files matching the file specification to the
Immediate Window.  whereis() takes two arguments:  the first argument is the
directory to start from.  It must be a valid directory and MUST have a
backslash as the last character.  The second argument is the filespec to
search for.  It can contain the DOS wildcard characters "*" and "?".

The above example finds all DLLs in the WINDOWS directory all directories
underneath.

Function WhereIs (strDirSpec As String, strSpec As String)
    
    Dim ff As FINDFILE
    Dim intStat As Integer
    Dim varRetval As Variant
    Dim varTemp As Variant

    'look for subdirectories first
    Debug.Print "Searching " & strDirSpec & strSpec
    intStat = DosFindFirst(strDirSpec & "*.*", ATTR_SUBDIR, ff)
    While (intStat = 0)
	If (Asc(ff.attrib) And ATTR_SUBDIR) And (Left(ff.name, 1) <> ".") Then
	    'clean ff.name
	    If (InStr(ff.name, Chr(0)) > 0) Then
		varTemp = Left(ff.name, InStr(ff.name, Chr(0)) - 1)
	    Else
		varTemp = ff.name
	    End If
	    varRetval = WhereIs(strDirSpec & varTemp & "\", strSpec)
	End If
	intStat = DosFindNext(ff)
    Wend

    'look specifically for a file type
    intStat = DosFindFirst(strDirSpec & strSpec, 0, ff)
    While (intStat = 0)
	If (InStr(ff.name, Chr(0)) > 0) Then
	    varTemp = Left(ff.name, InStr(ff.name, Chr(0)) - 1)
	Else
	    varTemp = ff.name
	End If
	Debug.Print varTemp, Format(ConvertDosTime(ff), "long date")
	intStat = DosFindNext(ff)
    Wend
    'allow other things to happen
    DoEvents
End Function

This function uses the Dir() function to list all the files in the
C:\ directory, along with their file attributes.

Function TestAttrib ()
    ' Print out a list of files in your root
    ' directory, along with the file attribute of each.

    Dim strName As String

    ' Note:  Dir() won't find hidden or system files.
    strName = Dir("C:\")
    Do While strName <> ""
	Debug.Print strName, GetFileAttr("C:\" & strName)
	strName = Dir
    Loop
End Function

Programming notes
=================

Look at FATTR.C and notice how simple it is to create a DLL that you can use
with Microsoft Access!

The DLL was built with Microsoft Visual C++ using the Large Memory Model and
all default settings and optimizations.  Visual C++ will create a default
WEP and LibMain(), so these aren't included.  Also note that the Large Model
is required because much of the runtime library is not model independent!

To get the internal Access date format, I used the following formula:

  ((time_t - 25200) / 86400) + 25569

where
  time_t is the C time format (number of seconds starting 1/1/70 midnight)
  25200 is the number of seconds in 7 hours
  86400 is the number of seconds in 1 day
  25569 is the Access equivalent of 1/1/70



Legal stuff
===========

Please note that this sample is totally unsupported, and the software is
PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND and in no event shall MS be
liable for any damages whatsoever in connection with your use of the
sample.

However, I'm willing to answer questions about sample and programming DLLs
for Access in general.

Please feel free to copy this and use it, sell it, whatever.

Roger Harui [MSFT], 71742,1177
Ken Getz 76137,3650

