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

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

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.

From Access, create a new module, and choose "Load Text..." from the File
menu.  Load the file "FATTR.DEF" that comes with this file.

The file FATTR.DEF contains the following declarations:

Global Const FF_NORMAL = 0  'Normal file
Global Const FF_RDONLY = 1  'Read only file
Global Const FF_HIDDEN = 2  'Hidden file
Global Const FF_SYSTEM = 4  'System file
Global Const FF_VOLID = 8   'Volume ID file
Global Const FF_SUBDIR = 16 'Subdirectory
Global Const FF_ARCH = 32   'Archive file

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

Declare Function ConvertDosTime Lib "\b\fattr\fattr.dll" (ff As FINDFILE) As Double
Declare Function DosFindFirst Lib "\b\fattr\fattr.dll" (ByVal FileName$, ByVal attrib%, ff As FINDFILE) As Integer
Declare Function DosFindNext Lib "\b\fattr\fattr.dll" (ff As FINDFILE) As Integer
Declare Function GetFileDateTime Lib "\b\fattr\fattr.dll" (ByVal FileName$) As Double
Declare Function GetDiskFree Lib "\b\fattr\fattr.dll" (ByVal drive%) As Long
Declare Function GetFileSize Lib "\b\fattr\fattr.dll" (ByVal FileName$) As Long

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

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")


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:  
            FF_NORMAL, FF_RDONLY, FF_HIDDEN, FF_SYSTEM, FF_ARCH, FF_VOLID,
            FF_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:

             (FF_NORMAL OR FF_RDONLY OR FF_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 FF_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("*.*", FF_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("*.*", FF_NORMAL, ffStruct)
            While status = 0 Then
              Debug.Print ffStruct.name & 
                Format(ConvertDosTime(ffStruct), "Long Date")
              status = DosFindNext(ffStruct)
            Wend


Example
=======

The following example comes in the FATTR.DEF.  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 (dirspec, spec)
    Dim ff As FINDFILE, stat As Integer, ret, temp

    'look for subdirectories first
    Debug.Print "Searching " & dirspec & spec
    stat = DosFindFirst(dirspec & "*.*", FF_SUBDIR, ff)
    While (stat = 0)
        If (Asc(ff.attrib) And FF_SUBDIR) And (Left(ff.name, 1) <> ".") Then
            'clean ff.name
            If (InStr(ff.name, Chr(0)) > 0) Then
                temp = Left(ff.name, InStr(ff.name, Chr(0)) - 1)
            Else
                temp = ff.name
            End If
            ret = whereis(dirspec & temp & "\", spec)
        End If
        stat = DosFindNext(ff)
    Wend

    'look specifically for a file type
    stat = DosFindFirst(dirspec & spec, 0, ff)
    While (stat = 0)
        If (InStr(ff.name, Chr(0)) > 0) Then
            temp = Left(ff.name, InStr(ff.name, Chr(0)) - 1)
        Else
            temp = ff.name
        End If
        Debug.Print temp, Format(ConvertDosTime(ff), "long date")
        stat = DosFindNext(ff)
    Wend
    'allow other things to happen
    DoEvents
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

