Stuart McCall's Microsoft Access Pages - Misc API

Home
Determine a drive's Volume name and Serial number

Declare Function GetVolumeInformation _
     Lib "KERNEL32" Alias "GetVolumeInformationA" _
    (ByVal lpRootPathName As String, _
     ByVal lpVolumeNameBuffer As String, _
     ByVal nVolumeNameSize As Long, _
     lpVolumeSerialNumber As Long, _
     lpMaximumComponentLength As Long, _
     lpFileSystemFlags As Long, _
     ByVal lpFileSystemNameBuffer As String, _
     ByVal nFileSystemNameSize As Long) As Long
Paste these Declarations into the top of a standard module (ie before any procedures).
Public Sub GetVolumeInfo(Path As String, Volume As String, Serial As String)
'Extracts Volume name and Serial number
'from info returned by API
    Dim n As Long
    
    Volume = Space$(14)
    If GetVolumeInformation( _
        Path, Volume, 14, n, _
        0&, 0&, vbNullString, 0& _
    ) = 0 Then Exit Sub
    Volume = Left$(Volume, InStr(Volume, vbNullChar) - 1)
    Serial = Format$(Hex(HiWord(n)), "0000") & _
        "-" & Format$(Hex(LoWord(n)), "0000")
End Sub

Private Function HiWord(Dword As Long) As Integer
'Returns the high word of a doubleword value
    If Dword And &H80000000 Then
        HiWord = (Dword \ &HFFFF&) - 1
    Else
        HiWord = Dword \ &HFFFF&
    End If
End Function

Private Function LoWord(Dword As Long) As Integer
'Returns the low word of a doubleword value
    If Dword And &H8000& Then
        LoWord = &H8000 Or (Dword And &H7FFF)
    Else
        LoWord = Dword And &H7FFF
    End If
End Function
Paste this Code into the same module.
Usage:
Dim v As String, s As String

GetVolumeInfo "c:\", v, s
MsgBox "Volume: " & v & vbcrlf & "Serial: " & s
Home Contents

File Open Dialog

Private Declare Function GetOpenFileName Lib "comdlg32.dll" Alias "GetOpenFileNameA" (ofn As OPENFILENAME) As Boolean
Private Declare Function GetSaveFileName Lib "comdlg32.dll" Alias "GetSaveFileNameA" (ofn As OPENFILENAME) As Boolean

Private Type OPENFILENAME
    lStructSize As Long
    hWndOwner As Long
    hInstance As Long
    strFilter As String
    strCustomFilter As String
    nMaxCustFilter As Long
    NFilterIndex As Long
    strFile As String
    nMaxFile As Long
    strFileTitle As String
    nMaxFileTitle As Long
    strInitialDir As String
    strTitle As String
    Flags As Long
    nFileOffset As Integer
    nFileExtension As Integer
    strDefExt As String
    lCustData As Long
    lpfnHook As Long
    lpTemplateName As String
End Type
'
Public Const OFN_READONLY = &H1
Public Const OFN_OVERWRITEPROMPT = &H2
Public Const OFN_HIDEREADONLY = &H4
Public Const OFN_NOCHANGEDIR = &H8
Public Const OFN_SHOWHELP = &H10
Public Const OFN_NOVALIDATE = &H100
Public Const OFN_ALLOWMULTISELECT = &H200
Public Const OFN_EXTENSIONDIFFERENT = &H400
Public Const OFN_PATHMUSTEXIST = &H800
Public Const OFN_FILEMUSTEXIST = &H1000
Public Const OFN_CREATEPROMPT = &H2000
Public Const OFN_SHAREAWARE = &H4000
Public Const OFN_NOREADONLYRETURN = &H8000
Public Const OFN_NOTESTFILECREATE = &H10000
Public Const OFN_NONETWORKBUTTON = &H20000
Public Const OFN_NOLONGNAMES = &H40000
Public Const OFN_EXPLORER = &H80000
Public Const OFN_NODEREFERENCELINKS = &H100000
Public Const OFN_LONGNAMES = &H200000
Paste this Declaration into the top of a standard module (ie before any procedures).
Public Function sjmFileOpen( _
                            Optional ByVal OpenDialog, _
                            Optional ByRef Flags, _
                            Optional ByVal InitDir, _
                            Optional ByVal FileName, _
                            Optional ByVal BoxTitle, _
                            Optional ByVal Filters, _
                            Optional ByVal DefaultFilter, _
                            Optional ByVal DefaultExt _
                ) As String

' Parameters:
' OpenDialog: False = Open, True = Save
' Flags: Standard api flag constants. (modified by reference)
' InitDir: Initial dir to show
' FileName: Default file name
' BoxTitle: Dialog's Caption
' Filters: Standard file filters ('|' delimited string)
' DefaultFilter: Default Filter to use
' DefaultExt: Default extension to use for save dialog
'
'Return Value:
' Selected file's full path. "" if Cancelled
    Dim dlg As OPENFILENAME
    Dim ret As Boolean
    Dim n As Integer
    
    Const BufferLen As Integer = 512
    
    If IsMissing(OpenDialog) Then OpenDialog = False
    If IsMissing(Flags) Then Flags = OFN_HIDEREADONLY
    If IsMissing(InitDir) Then InitDir = CurDir
    If IsMissing(FileName) Then FileName = ""
    If IsMissing(BoxTitle) Then BoxTitle = ""
    If IsMissing(Filters) Then Filters = "All Files (*.*)|*.*|"
    If IsMissing(DefaultFilter) Then DefaultFilter = 1
    If IsMissing(DefaultExt) Then DefaultExt = ""
    FileName = Left$(FileName & String$(BufferLen, vbNullChar), BufferLen)
    
    Filters = Replace(Filters, "|", vbNullChar)
    
    With dlg
        .lStructSize = Len(dlg)
        .hWndOwner = Application.hWndAccessApp
        .strFilter = Filters
        .NFilterIndex = DefaultFilter
        .strFile = FileName
        .nMaxFile = BufferLen
        .strTitle = BoxTitle
        .Flags = Flags
        .strDefExt = DefaultExt
        .strInitialDir = InitDir
        .nMaxCustFilter = BufferLen
        .strCustomFilter = String$(BufferLen, vbNullChar)
    End With
    If OpenDialog Then
        ret = GetSaveFileName(dlg)
    Else
        ret = GetOpenFileName(dlg)
    End If
    If ret Then
        sjmFileOpen = Left(dlg.strFile, InStr(dlg.strFile, vbNullChar) - 1)
        Flags = dlg.Flags
    End If
End Function
Paste this Code into the same module.
Home Contents

Browse for folder

Private Type BROWSEINFO
    hOwner As Long
    pidlRoot As Long
    pszDisplayName As String
    lpszTitle As String
    ulFlags As Long
    lpfn As Long
    lParam As Long
    iImage As Long
End Type
'
Private Declare Function SHGetPathFromIDListA Lib "shell32.dll" (ByVal pidl As Long, ByVal pszPath As String) As Long
Private Declare Function SHBrowseForFolderA Lib "shell32.dll" (lpBrowseInfo As BROWSEINFO) As Long
Paste these Declarations into the top of a standard module (ie before any procedures).
Public Function SelectFolder(ByVal strPrompt As String) As String
    Dim bi As BROWSEINFO
    
    bi.ulFlags = 1
    bi.lpszTitle = strPrompt
    strPrompt = Space$(512)
    If SHGetPathFromIDListA(SHBrowseForFolderA(bi), strPrompt) Then
    SelectFolder = Left(strPrompt, InStr(strPrompt, vbNullChar) - 1)
    End If
End Function
Paste this Code into the same module.
Home Contents

Screen-scrape a web page

Declare Function URLDownloadToFile Lib "urlmon" Alias "URLDownloadToFileA" _
    (ByVal pCaller As Long, ByVal szURL As String, _
    ByVal szFileName As String, ByVal dwReserved As Long, _
    ByVal lpfnCB As Long) As Long
Paste these Declarations into the top of a standard module (ie before any procedures).
Function DownloadURL(sSourceUrl As String, sLocalFile As String) As Boolean
    DownloadURL = (URLDownloadToFile(0&, sSourceUrl, sLocalFile, 0&, 0&) = 0)
End Function
Paste this Code into the same module.
Usage:
Dim success As Boolean
success = DownloadURL("http://www.microsoft.com", "c:\temp\myfile.txt")
Home Contents

Determine UNC path of mapped drive

Private Const ERROR_BAD_DEVICE = 1200&
Private Const ERROR_CONNECTION_UNAVAIL = 1201&
Private Const ERROR_EXTENDED_ERROR = 1208&
Private Const ERROR_MORE_DATA = 234
Private Const ERROR_NOT_SUPPORTED = 50&
Private Const ERROR_NO_NET_OR_BAD_PATH = 1203&
Private Const ERROR_NO_NETWORK = 1222&
Private Const ERROR_NOT_CONNECTED = 2250&
Private Const NO_ERROR = 0

Private Declare Function WNetGetConnectionA Lib "mpr.dll" (ByVal lpszLocalName As String, ByVal lpszRemoteName As String, cbRemoteName As Long) As Long
Paste these Declarations into the top of a standard module (ie before any procedures).
Public Function UNCPath(ByVal pstrDriveLetter As String) As String
' Returns UNC path associated with
' mapped drive pstrDriveLetter

    Dim strName As String
    Dim lngReturn As Long
    '
    Const BUFLEN As Long = 255
    '
    strName = Space$(BUFLEN)
    lngReturn = WNetGetConnectionA(pstrDriveLetter, strName, BUFLEN)
    Select Case lngReturn
        Case ERROR_BAD_DEVICE
            UNCPath = "Error: Bad Device"
        Case ERROR_CONNECTION_UNAVAIL
            UNCPath = "Error: Connection Un-Available"
        Case ERROR_EXTENDED_ERROR
            UNCPath = "Error: Extended Error"
        Case ERROR_MORE_DATA
            UNCPath = "Error: More Data"
        Case ERROR_NOT_SUPPORTED
            UNCPath = "Error: Feature not Supported"
        Case ERROR_NO_NET_OR_BAD_PATH
            UNCPath = "Error: No Network Available or Bad Path"
        Case ERROR_NO_NETWORK
            UNCPath = "Error: No Network Available"
        Case ERROR_NOT_CONNECTED
            UNCPath = "Error: Not Connected"
        Case NO_ERROR
            UNCPath = Left$(strName, InStr(1, strName, vbNullChar) - 1)
    End Select

End Function
Paste this Code into the same module.
Usage:
Debug.Print UNCPath("Z:")
Home Contents

Text to/from Clipboard

Private Declare Function OpenClipboard Lib "User32" (ByVal hwnd&) As Long
Private Declare Function EmptyClipboard Lib "User32" () As Long
Private Declare Function GetClipboardData Lib "User32" (ByVal wFormat&) As Long
Private Declare Function SetClipboardData Lib "User32" (ByVal wFormat&, ByVal hMem&) As Long
Private Declare Function CloseClipboard Lib "User32" () As Long

Private Declare Function GlobalAlloc Lib "kernel32" (ByVal wFlags&, ByVal dwBytes&) As Long
Private Declare Function GlobalLock Lib "kernel32" (ByVal hMem&) As Long
Private Declare Function GlobalUnlock Lib "kernel32" (ByVal hMem&) As Long

Private Declare Function lstrcpy Lib "kernel32" (ByVal lpString1 As Any, ByVal lpString2 As Any) As Long

Private Const CF_TEXT = 1
Paste these Declarations into the top of a standard module (ie before any procedures).
Function clipGetText() As String
' Retrieve text from the clipboard
' If clipboard is empty, or contents
' are not textual, returns ""
    Dim hMem As Long
    Dim lpMem As Long
    Dim strResult As String
    Const BUF_SIZE = 4096
    
    If OpenClipboard(0&) = 0 Then Exit Function
    
    hMem = GetClipboardData(CF_TEXT)
    If hMem = 0 Then GoTo clipGetText_Exit
    
    lpMem = GlobalLock(hMem)
    If lpMem Then
        strResult = Space$(BUF_SIZE)
        lstrcpy strResult, lpMem
        GlobalUnlock hMem
        strResult = Left$(strResult, InStr(1, strResult, vbNullChar, 0) - 1)
    End If

clipGetText_Exit:
    CloseClipboard
    clipGetText = strResult
End Function

Sub clipPutText(theText As String)
' Stores text on the clipboard
    Dim hMem As Long
    Const GHND = &H42
    
    hMem = GlobalAlloc(GHND, Len(theText) + 1)
    lstrcpy GlobalLock(hMem), theText
    If GlobalUnlock(hMem) <> 0 Then Exit Sub
    If OpenClipboard(0&) = 0 Then Exit Sub
    EmptyClipboard
    SetClipboardData CF_TEXT, hMem
    CloseClipboard
End Sub
Paste this Code into the same module.
Home Contents

Determine if current database is open exclusive

Public Function dbOpenExcl() As Boolean
' Determine if current database is open exclusive.
' True = open exclusive
    Dim fh As Integer
    
    fh = FreeFile
    On Error Resume Next
    Open CurrentDb.Name For Binary Access Read Write Shared As fh
    dbOpenExcl = (Err.Number > 0)
    Close fh
End Function
Paste this function into a standard module.
Home Contents

Auto-Dial a phone number using a modem

Declare Function WriteFile& Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToWrite&, lpNumberOfBytesWritten&, ByVal lpOverlapped&)
Declare Function CreateFile& Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName$, ByVal dwDesiredAccess&, ByVal dwShareMode&, ByVal lpSecurityAttributes&, ByVal dwCreationDisposition&, ByVal dwFlagsAndAttributes&, ByVal hTemplateFile&)
Declare Function CloseHandle& Lib "kernel32" (ByVal hObject&)
Declare Function FlushFileBuffers& Lib "kernel32" (ByVal hFile&)
Paste these Declarations into the top of a standard module (ie before any procedures).
Function DialNumber(PhoneNumber, Optional CommPort As String = "COM2", Optional WaitSeconds As Long = 4)
' PhoneNumber: The phone number to dial
' CommPort: The comm port the modem is connected
'           to. Typically, modems are found on COM2, however,
'           they can be configured for any COM port.
' WaitSeconds: The number of seconds to wait for the modem to
'           finish dialling before resetting the modem. If the phone
'           hangs up prematurely, try increasing this value by small increments.
    Dim openPort&, retVal&
    Dim startTime
    
    ' Ask the user to pick up the phone.
    If MsgBox("Please pickup the phone and choose OK to dial " & PhoneNumber & ".", _
        vbInformation + vbOKCancel, "Dial Number") = vbCancel Then Exit Function
    
    ' Open the Com port for read/write (&HC0000000).
    ' Must specify existing file (3).
    openPort = CreateFile(CommPort, &HC0000000, 0, 0, 3, 0, 0)
    If openPort = -1 Then
       MsgBox "Unable to open communication port " & CommPort, vbCritical, "Dial Number Error"
       Exit Function
    End If
    
    ' Write modem command to the Com port.
    retVal = WriteBytes(openPort, "ATDT" & PhoneNumber & vbCrLf)
    If retVal = 0 Then
       MsgBox "Unable to dial number " & PhoneNumber, vbCritical, "Dial Number Error"
       Exit Function
    End If
    
    ' Wait WaitSeconds for the phone to finish dialling.
    startTime = Timer
    Do While Timer < startTime + WaitSeconds
       DoEvents
    Loop
    
    ' Reset the modem and take it off line.
    WriteBytes openPort, "ATH0" & vbCrLf
    ' Close the Com port.
    CloseHandle openPort
End Function

Private Function WriteBytes(openPort, cmd$) As Long
    Dim a(256) As Byte, retBytes&, i&
    
    For i = 0 To Len(cmd) - 1
       a(i) = Asc(Mid(cmd, i + 1, 1))
    Next
    WriteBytes = WriteFile(openPort, a(0), Len(cmd), retBytes, 0)
    FlushFileBuffers openPort
End Function
Paste this Code into the same module.
Home Contents

Create and delete a user or system DSN

Private Const ODBC_ADD_DSN = 1
Private Const ODBC_CONFIG_DSN = 2
Private Const ODBC_REMOVE_DSN = 3
Private Const ODBC_ADD_SYS_DSN = 4
Private Const ODBC_CONFIG_SYS_DSN = 5
Private Const ODBC_REMOVE_SYS_DSN = 6
Private Declare Function SQLConfigDataSource Lib "ODBCCP32.DLL" (ByVal hwndParent As Long, ByVal fRequest As Long, ByVal lpszDriver As String, ByVal lpszAttributes As String) As Long
Paste these Declarations into the top of a standard module (ie before any procedures).
Public Function DSNCreate(ByVal Description$, ByVal DSN$, ByVal Driver$, ByVal Database$, ByVal UserID$, ByVal Password$, ByVal Path$, SystemDSN As Boolean) As Boolean
'Creates a user or system DSN via parameters
'which it uses to build a connect string
'It then calls function CreateDSN (below)
'Requires nReplace
    Const con = "DBQ=%1;DSN=%2;UID=%3;PWD=%4;DESCRIPTION=%5;DIR=%6"
    Dim Connect$, req&
    Connect = nReplace(con, Database, DSN, UserID, Password, Description, Path)
    DSNCreate = CreateDSN(Driver, Connect, SystemDSN)
End Function

Public Function CreateDSN(ByVal Driver$, ByVal Connect$, SystemDSN As Boolean) As Boolean
'Creates a user or system DSN via a connect string
'Returns True for success
    Connect = Replace(Connect, ";", vbNullChar)
    CreateDSN = SQLConfigDataSource(0&, IIf(SystemDSN, ODBC_ADD_SYS_DSN, ODBC_ADD_DSN), Driver, Connect)
End Function

Public Function DSNDelete(ByVal DSN$, ByVal Driver$, Optional SystemDSN As Boolean = False) As Boolean
'Deletes a user or system DSN by name
'Returns True for success
    Dim Connect$
    Connect = "DSN=" & DSN & vbNullChar
    DeleteDSN = SQLConfigDataSource(0&, IIf(SystemDSN, ODBC_REMOVE_SYS_DSN, ODBC_REMOVE_DSN), Driver, Connect)
End Function
Paste this Code into the same module.
Home Contents

DSN listing functions

Private Declare Function SQLDataSources Lib "ODBC32.DLL" (ByVal henv As Long, ByVal fDirection As Integer, ByVal szDSN As String, ByVal cbDSNMax As Integer, pcbDSN As Integer, ByVal szDescription As String, ByVal cbDescriptionMax As Integer, pcbDescription As Integer) As Integer
Private Declare Function SQLAllocEnv Lib "ODBC32.DLL" (env As Long) As Integer
Private Const SQL_SUCCESS As Long = 0
Private Const SQL_FETCH_NEXT As Long = 1
Paste these Declarations into the top of a standard module (ie before any procedures).
Public Function DSNList(col As Collection, Optional ByVal DriverName$ = "All") As Boolean
'Fills the collection col with a list of DSNs
'Returns True for success
    Dim DSNItem As String * 1024, DRVItem As String * 1024
    Dim EnvHwnd&, ret&, DSNLen%, DRVLen%
    
    On Error GoTo ExitPoint
    If SQLAllocEnv(EnvHwnd) <> -1 Then
        Set col = New Collection
        Do Until ret& <> SQL_SUCCESS
            ret& = SQLDataSources(EnvHwnd, SQL_FETCH_NEXT, DSNItem, 1024, DSNLen, DRVItem, 1024, DRVLen)
            If DriverName = Left$(DRVItem, DRVLen) Or DriverName = "All" Then
                col.Add Left$(DSNItem, DSNLen)
            End If
        Loop
    End If
    DSNList = True
ExitPoint:
End Function


Public Function DRVList(col As Collection) As Boolean
'Fills the collection col with a list of Drivers
'Returns True for success
    Dim DRVItem As String * 1024, DSNItem As String * 1024
    Dim EnvHwnd&, ret&, DRV$, DSNLen%, DRVLen%
    '
    On Error GoTo ExitPoint
    If SQLAllocEnv(EnvHwnd) <> -1 Then
        Set col = New Collection
        Do Until ret& <> SQL_SUCCESS
            ret = SQLDataSources(EnvHwnd, SQL_FETCH_NEXT, DSNItem, 1024, DSNLen, DRVItem, 1024, DRVLen)
            col.Add Left$(DRVItem, DRVLen)
        Loop
    End If
    DRVList = True
ExitPoint:
End Function


Public Function DSNRowSource() As String
'Returns a semicolon-delimited list of DSNs
'for use as a combo or listbox 'Value List'
'Demonstrates use of DSNList
    Dim c As Collection, itm As Variant, rtn$
    If DSNList(c) Then
        If c.Count = 0 Then Exit Function
        For Each itm In c
            rtn = rtn & ";" & itm
        Next
    End If
    DSNRowSource = Mid$(rtn, 2)
End Function

Public Function DRVRowSource() As String
'Returns a semicolon-delimited list of drivers
'for use as a combo or listbox 'Value List'
'Demonstrates use of DRVList
    Dim c As Collection, itm As Variant, rtn$
    If DRVList(c) Then
        If c.Count = 0 Then Exit Function
        For Each itm In c
            rtn = rtn & ";" & itm
        Next
    End If
    DRVRowSource = Mid$(rtn, 2)
End Function

Public Function IsDSN(ByVal DSN$, Optional ByVal DriverName$ = "All") As Boolean
'Determines whether DSN already exists
'Demonstrates use of DSNList
Dim col As Collection, itm As Variant If DSNList(col, DriverName) Then For Each itm In col If itm = DSN Then IsDSN = True Exit For End If Next End If End Function
Paste this Code into the same module.
Home Contents

Fill a Value-List Listbox with Data Source Names

Requires: DSNRowSource

Public Function DSNListbox(lst As Access.ListBox, Optional ByVal DriverName$ = "All")
    lst.RowSource = DSNRowSource()
End Function
Paste this Code into a standard module.
Usage:
DSNListbox Me.List0
  1. Create a form and put a listbox on it. Call it List0.
  2. Set the listbox's Row Source Type property to Value List.
  3. Paste the usage example into the Form_Load event.
  4. Open the form to test.
Home Contents

Send a message to another workstation

Private Declare Function CloseHandle Lib "kernel32" _
  (ByVal hHandle As Long) As Long

Private Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" _
  (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, _
   ByVal dwShareMode As Long, ByVal lpSecurityAttributes As Long, _
   ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, _
   ByVal hTemplateFile As Long) As Long

Private Declare Function WriteFile Lib "kernel32" _
  (ByVal hFile As Long, ByVal lpBuffer As Any, ByVal nNumberOfBytesToWrite As Long, _
   lpNumberOfBytesWritten As Long, ByVal lpOverlapped As Long) As Long
   
Private Const FILE_ATTRIBUTE_NORMAL = &H80
Private Const FILE_SHARE_READ = &H1
Private Const GENERIC_WRITE = &H40000000
Private Const OPEN_EXISTING = &H3
Paste these Declarations into the top of a standard module (ie before any procedures).
Public Function NetSendMsg(FromName As String, MachineName As String, Message As String) As Boolean
    Const NUL = vbNullChar
    Dim buf          As String
    Dim bytesWritten As Long
    Dim hFile        As Long
    Dim SlotName     As String
    '
    buf = FromName & NUL & MachineName & NUL & Message & NUL & NUL
    SlotName = "\\" & MachineName & "\mailslot\messngr"
    '
    hFile = CreateFile(SlotName, GENERIC_WRITE, FILE_SHARE_READ, 0&, _
      OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0&)
    If hFile Then
        NetSendMsg = CBool(WriteFile(hFile, buf, Len(buf), bytesWritten, 0&))
        CloseHandle hFile
    End If
End Function
Paste this Code into the same module.
Usage:
success = NetSendMsg("Stuart", "WS03", "Please call me ASAP")
This sends a message from me to the workstation named WS03.
Home Contents

Get/set File date and time stamps

Private Type FILE_TIME
    dwLowDateTime  As Long
    dwHighDateTime As Long
End Type

Private Type SYSTEM_TIME
    wYear         As Integer
    wMonth        As Integer
    wDayOfWeek    As Integer
    wDay          As Integer
    wHour         As Integer
    wMinute       As Integer
    wSecond       As Integer
    wMilliseconds As Integer
End Type

Private Declare Function GetFileTime Lib "kernel32" (ByVal hFile As Long, lpCreationTime As FILE_TIME, lpLastAccessTime As FILE_TIME, lpLastWriteTime As FILE_TIME) As Long
Private Declare Function SetFileTime Lib "kernel32" (ByVal hFile As Long, lpCreationTime As FILE_TIME, lpLastAccessTime As FILE_TIME, lpLastWriteTime As FILE_TIME) As Long
Private Declare Function FileTimeToSystemTime Lib "kernel32" (lpFileTime As FILE_TIME, lpSystemTime As SYSTEM_TIME) As Long
Private Declare Function SystemTimeToFileTime Lib "kernel32" (lpSystemTime As SYSTEM_TIME, lpFileTime As FILE_TIME) As Long
Private Declare Function FileTimeToLocalFileTime Lib "kernel32" (lpFileTime As FILE_TIME, lpLocalFileTime As FILE_TIME) As Long
Private Declare Function LocalFileTimeToFileTime Lib "kernel32" (lpLocalFileTime As FILE_TIME, lpFileTime As FILE_TIME) As Long
Private Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, ByVal lpSecurityAttributes As Long, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long

Private Const GENERIC_WRITE    As Long = &H40000000
Private Const FILE_SHARE_READ  As Long = &H1
Private Const FILE_SHARE_WRITE As Long = &H2
Private Const OPEN_EXISTING    As Long = &H3

Public Enum ft_FileTime
    ftCreationTime = 1
    ftAccessedTime = 2
    ftModifiedTime = 3
End Enum
Paste these Declarations into the top of a standard module (ie before any procedures).
Public Function ReadFileTime(FileName As String, WhichTime As ft_FileTime) As Date
    Dim ft1 As FILE_TIME, ft2 As FILE_TIME, ft3 As FILE_TIME, ft4 As FILE_TIME, sysTime As SYSTEM_TIME
    Dim hFile As Long
    On Error GoTo Handler

    hFile = CreateFile(FileName, GENERIC_WRITE, FILE_SHARE_READ Or FILE_SHARE_WRITE, ByVal 0&, OPEN_EXISTING, 0, 0)
    GetFileTime hFile, ft1, ft2, ft3
    CloseHandle hFile
    Select Case WhichTime
        Case ftCreationtime
            FileTimeToLocalFileTime ft1, ft4
            FileTimeToSystemTime ft4, sysTime
        Case ftAccessedtime
            FileTimeToLocalFileTime ft2, ft4
            FileTimeToSystemTime ft4, sysTime
        Case ftModifiedtime
            FileTimeToLocalFileTime ft3, ft4
            FileTimeToSystemTime ft4, sysTime
    End Select
    With sysTime
        ReadFileTime = CDate(.wDay & "/" & .wMonth & "/" & .wYear & " " & .wHour & ":" & .wMinute & ":" & .wSecond)
    End With

ExitPoint:
    Exit Function
Handler:
    MsgBox Err.Description & " (" & Err.Number & ")", vbCritical
    Resume ExitPoint
End Function

Public Function WriteFileTime(FileName As String, WhichTime As ft_FileTime, NewTime As Date) As Boolean
    Dim ft1 As FILE_TIME, ft2 As FILE_TIME, ft3 As FILE_TIME, ft4 As FILE_TIME, sysTime As SYSTEM_TIME
    Dim hFile As Long
    On Error GoTo Handler

    With sysTime
        .wDay = Day(NewTime)
        .wDayOfWeek = Weekday(NewTime) - 1
        .wMonth = Month(NewTime)
        .wYear = Year(NewTime)
        .wHour = Hour(NewTime)
        .wMinute = Minute(NewTime)
        .wSecond = Second(NewTime)
    End With
    hFile = CreateFile(FileName, GENERIC_WRITE, FILE_SHARE_READ Or FILE_SHARE_WRITE, ByVal 0&, OPEN_EXISTING, 0, 0)
    GetFileTime hFile, ft1, ft2, ft3
    Select Case WhichTime
        Case ftCreationtime
            SystemTimeToFileTime sysTime, ft1
            LocalFileTimeToFileTime ft1, ft4
            SetFileTime hFile, ft4, ft2, ft3
        Case ftAccessedtime
            SystemTimeToFileTime sysTime, ft2
            LocalFileTimeToFileTime ft2, ft4
            SetFileTime hFile, ft1, ft4, ft3
        Case ftModifiedtime
            SystemTimeToFileTime sysTime, ft3
            LocalFileTimeToFileTime ft3, ft4
            SetFileTime hFile, ft1, ft2, ft4
    End Select
    WriteFileTime = True

ExitPoint:
    CloseHandle hFile
    Exit Function
Handler:
    MsgBox Err.Description & " (" & Err.Number & ")", vbCritical
    Resume ExitPoint
End Function
Paste this Code into the same module.
Usage:
    Debug.Print ReadFileTime("c:\temp\test.txt", ftModifiedtime)
    'This outputs the given file's last modified time to the immediate window.

WriteFileTime "c:\temp\test.txt", ftCreationtime, Now()) 'This overwrites the given file's creation time with the current date/time.
Home Contents

Determine exe file version

Private Declare Function GetFileVersionInfo Lib "Version.dll" Alias "GetFileVersionInfoA" (ByVal lptstrFilename As String, ByVal dwHandle As Long, ByVal dwLen As Long, lpData As Any) As Long
Private Declare Function GetFileVersionInfoSize Lib "Version.dll" Alias "GetFileVersionInfoSizeA" (ByVal lptstrFilename As String, lpdwHandle As Long) As Long
Private Declare Function VerQueryValue Lib "Version.dll" Alias "VerQueryValueA" (pBlock As Any, ByVal lpSubBlock As String, lplpBuffer As Any, puLen As Long) As Long
Private Declare Sub MoveMemory Lib "kernel32" Alias "RtlMoveMemory" (dest As Any, ByVal Source As Long, ByVal Length As Long)
'
Private Type VS_FIXEDFILEINFO
    dwSignature As Long
    dwStrucVersionl As Integer      ' e.g. = &h0000 = 0
    dwStrucVersionh As Integer      ' e.g. = &h0042 = .42
    dwFileVersionMSl As Integer     ' e.g. = &h0003 = 3
    dwFileVersionMSh As Integer     ' e.g. = &h0075 = .75
    dwFileVersionLSl As Integer     ' e.g. = &h0000 = 0
    dwFileVersionLSh As Integer     ' e.g. = &h0031 = .31
    dwProductVersionMSl As Integer  ' e.g. = &h0003 = 3
    dwProductVersionMSh As Integer  ' e.g. = &h0010 = .1
    dwProductVersionLSl As Integer  ' e.g. = &h0000 = 0
    dwProductVersionLSh As Integer  ' e.g. = &h0031 = .31
    dwFileFlagsMask As Long         ' = &h3F For version "0.42"
    dwFileFlags As Long             ' e.g. VFF_DEBUG Or VFF_PRERELEASE
    dwFileOS As Long                ' e.g. VOS_DOS_WINDOWS32
    dwFileType As Long              ' e.g. VFT_DRIVER
    dwFileSubtype As Long           ' e.g. VFT2_DRV_KEYBOARD
    dwFileDateMS As Long            ' e.g. 0
    dwFileDateLS As Long            ' e.g. 0
End Type
Paste these Declarations into the top of a standard module (ie before any procedures).
Public Function ExeFileVersion(FullPath As Variant) As String
'Returns version of exe file
'or zero length string on error.
    On Error GoTo Out
    '
    Dim lDummy As Long, lSize As Long
    Dim lVerbufferLen As Long, lVerPointer As Long
    Dim sBuffer() As Byte
    Dim udtVerBuffer As VS_FIXEDFILEINFO
    Dim ProdVer As String
    '
    lSize = GetFileVersionInfoSize(FullPath, lDummy)
    If lSize < 1 Then Exit Function
    ReDim sBuffer(lSize)
    GetFileVersionInfo FullPath, 0&, lSize, sBuffer(0)
    VerQueryValue sBuffer(0), "\", lVerPointer, lVerbufferLen
    MoveMemory udtVerBuffer, lVerPointer, Len(udtVerBuffer)
    ExeFileVersion = Format$(udtVerBuffer.dwProductVersionMSh) & _
               "." & Format$(udtVerBuffer.dwProductVersionMSl)
Out:
End Function
Paste this Code into the same module.
Usage:
    Debug.Print ExeFileVersion("C:\Program Files\Microsoft Office11\OFFICE11\MSACCESS.EXE")
    'This outputs the given file's version number to the immediate window.
    Result: 11:0
Home Contents