Wrox Programmer Forums
Go Back   Wrox Programmer Forums > Microsoft Office > Excel VBA > Excel VBA
|
Excel VBA Discuss using VBA for Excel programming.
Welcome to the p2p.wrox.com Forums.

You are currently viewing the Excel VBA section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
 
Old March 7th, 2007, 11:45 PM
Authorized User
 
Join Date: Mar 2007
Posts: 11
Thanks: 0
Thanked 0 Times in 0 Posts
Default Generate summ rpt,auto send fr various excel files

Hi,
     I need help desperately for 2 items using excel 2000 & Visual Basic.
I need to retrieve common fields from various excel files & from their various worksheet in each excel file in order to churn out a summary report(which contains the common fields from the various worksheets from the various excel files).

Based on the sumamry report generated, i need to auto send out reminder emails to respective people,2 weeks before the action_due_date(1 of the common field that could be found in the summary report generated).

Please kindly help.Thanks a million
 
Old March 8th, 2007, 06:29 AM
Friend of Wrox
 
Join Date: Jun 2003
Posts: 173
Thanks: 0
Thanked 3 Times in 3 Posts
Default

This is a two part problem that relies on two fairly standard Excel VBA solutions. Part 1 relates to cycling through a number of workbooks to extract information, part 2 relates to e-mailing information.

Part 1. The exact coding will mainly depend on how you've got your search files set up. I've posted a bit of code below that will open all Excel files within a folder. If you only want to open files named a certain way then you'll need to put a defensive If ... Then ... Else statement in to filter out the files you're interested in. If you want to search all subfolders as well as the root folder provided then you'll need to use a recursive algorithm to search. Don't worry about the name, the additional coding is pretty simple. If this is what you want then just post back and ask, I'm pretty sure I've posted on recursive searching of all subfolders previously. What you will need to do to get this to work is add a reference to your VBA project for Microsoft Scripting Runtime (Tools -> References... from the menus system in the VBE)

Code:
Option Explicit
Option Base 1

Sub SearchFiles()

Dim scrFSO As Scripting.FileSystemObject
Dim scrFolder As Scripting.Folder
Dim scrFile As Scripting.File

Dim wb As Workbook
Dim varResults() As Variant
Dim intFilesFound As Integer
Dim i As Integer

Dim booDispAlerts As Boolean
Dim booScrUpdate As Boolean
Dim booEnEvents As Boolean
Dim xltCalc  As XlCalculation

Const strFolderPath As String = "C:\My Search Folder"

    ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ' Set up
    ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    ' Keep the user updated
    Application.StatusBar = "Setting up..."

    ' Record the state of & then turn off Excel functionality to make sub run faster
    booDispAlerts = Application.DisplayAlerts
    booScrUpdate = Application.ScreenUpdating
    booEnEvents = Application.EnableEvents
    xltCalc = Application.Calculation

    Application.DisplayAlerts = False
    Application.ScreenUpdating = False
    Application.EnableEvents = False
    Application.Calculation = xlCalculationManual

    ' Initiate a FileSystemObject
    Set scrFSO = New Scripting.FileSystemObject

    ' Reset files found counter
    intFilesFound = 0

    ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ' Main Program
    ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    ' Set the Folder object
    Set scrFolder = scrFSO.GetFolder(FolderPath:=strFolderPath)

    ' Loop through every file in the folder
    For Each scrFile In scrFolder.Files

        ' Only look at Excel files by inspecting the file extension
        If Right(scrFile.Name, 4) = ".xls" Then

            ' Keep the user updated
            Application.StatusBar = "Processing " & scrFile.Name & "..."

            ' Increment files found counter
            intFilesFound = intFilesFound + 1

            ' Redimension output array
            ReDim Preserve varResults(3, intFilesFound)

            ' Open the file
            Set wb = Workbooks.Open(Filename:=scrFile.Path, UpdateLinks:=False, ReadOnly:=True)

            ' Extract info - need to code to reach correct cells
            varResults(1, intFilesFound) = scrFile.Name
            varResults(2, intFilesFound) = wb.Sheets("Sheet1").Range("C3").Value
            varResults(3, intFilesFound) = wb.Sheets("Sheet2").Range("A1").Value

            ' Close the file
            wb.Close SaveChanges:=False

        End If

    Next scrFile

    ' Keep the user updated
    Application.StatusBar = "Results..."

    ' Show answers
    For i = 1 To intFilesFound
        MsgBox varResults(1, i) & " - " & varResults(2, i) & ", " & varResults(3, i)
    Next i

    ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ' Tidy up
    ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    ' Dereference variables
    Set scrFSO = Nothing
    Set scrFolder = Nothing
    Set scrFile = Nothing

    Application.DisplayAlerts = booDispAlerts
    Application.ScreenUpdating = booScrUpdate
    Application.EnableEvents = booEnEvents
    Application.Calculation = xltCalc
    Application.StatusBar = False

End Sub
Part 2. I've got a class module which you should be able to copy into your VBA project which wraps up CDO calls such that Excel can simply send e-mail. It assumes you've got Outlook on your computer. I use CDO because on my system (although not all) it circumvents the Outlook "virus might be trying to send an e-mail" warning pop-up. The code posted is in two parts, the most complicated bit should be copied verbatim into a newly inserted Class module, called clsMAPIWrapper. The second part is an example of code you can write to interact with the new class module. You should amend the second bit to integrate it into your project. You will also need to add a reference to your VBA project for Microsoft CDO 1.21 Library to get this part to work.

Class module code (clsMAPIWrapper):
Code:
Option Explicit

' *********************************************************************
' Internal Class variables
' *********************************************************************

Private mobjSession As MAPI.Session
Private mbooLoggedOn As Boolean

' *********************************************************************
' Win API constants
' *********************************************************************

Private Type OSVERSIONINFO
    dwOSVersionInfoSize As Long
    dwMajorVersion As Long
    dwMinorVersion As Long
    dwBuildNumber As Long
    dwPlatformId As Long
    szCSDVersion As String * 128
End Type

Const REG_SZ As Long = 1
Const REG_DWORD As Long = 4
Const HKEY_CURRENT_USER = &H80000001
Const ERROR_NONE = 0
Const ERROR_BADDB = 1
Const ERROR_BADKEY = 2
Const ERROR_CANTOPEN = 3
Const ERROR_CANTREAD = 4
Const ERROR_CANTWRITE = 5
Const ERROR_OUTOFMEMORY = 6
Const ERROR_INVALID_PARAMETER = 7
Const ERROR_ACCESS_DENIED = 8
Const ERROR_INVALID_PARAMETERS = 87
Const ERROR_NO_MORE_ITEMS = 259

Const KEY_ALL_ACCESS = &H3F

Const REG_OPTION_NON_VOLATILE = 0

' *********************************************************************
' Win API Calls
' *********************************************************************

Private Declare Function GetVersionEx Lib "kernel32" _
    Alias "GetVersionExA" _
    (ByRef lpVersionInformation As OSVERSIONINFO) As Long

Private Declare Function RegCloseKey Lib "advapi32.dll" _
    (ByVal hKey As Long) As Long

Private Declare Function RegOpenKeyEx Lib "advapi32.dll" _
    Alias "RegOpenKeyExA" _
    (ByVal hKey As Long, _
    ByVal lpSubKey As String, _
    ByVal ulOptions As Long, _
    ByVal samDesired As Long, _
    phkResult As Long) As Long

Private Declare Function RegQueryValueExString Lib "advapi32.dll" _
    Alias "RegQueryValueExA" _
    (ByVal hKey As Long, _
    ByVal lpValueName As String, _
    ByVal lpReserved As Long, _
    lpType As Long, _
    ByVal lpData As String, _
    lpcbData As Long) As Long

Private Declare Function RegQueryValueExLong Lib "advapi32.dll" _
    Alias "RegQueryValueExA" _
    (ByVal hKey As Long, _
    ByVal lpValueName As String, _
    ByVal lpReserved As Long, _
    lpType As Long, lpData As Long, _
    lpcbData As Long) As Long

Private Declare Function RegQueryValueExNULL Lib "advapi32.dll" _
    Alias "RegQueryValueExA" _
    (ByVal hKey As Long, _
    ByVal lpValueName As String, _
    ByVal lpReserved As Long, _
    lpType As Long, _
    ByVal lpData As Long, _
    lpcbData As Long) As Long

' *********************************************************************
' Wrapper functions to read the registry
' *********************************************************************

Private Function QueryValue(sKeyName As String, sValueName As String)

Dim lRetVal As Long     'result of the API functions
Dim hKey As Long        'handle of opened key
Dim vValue As Variant   'setting of queried value

    lRetVal = RegOpenKeyEx(HKEY_CURRENT_USER, sKeyName, 0, KEY_ALL_ACCESS, hKey)

    lRetVal = QueryValueEx(hKey, sValueName, vValue)
    QueryValue = vValue
    RegCloseKey (hKey)

End Function

Private Function QueryValueEx(ByVal lhKey As Long, ByVal szValueName As String, vValue As Variant) As Long

Dim cch As Long
Dim lrc As Long
Dim lType As Long
Dim lValue As Long
Dim sValue As String

    On Error GoTo QueryValueExError

    ' Determine the size and type of data to be read
    lrc = RegQueryValueExNULL(lhKey, szValueName, 0&, lType, 0&, cch)
    If lrc <> ERROR_NONE Then Error 5

    Select Case lType
        ' For strings
        Case REG_SZ:
            sValue = String(cch, 0)
            lrc = RegQueryValueExString(lhKey, szValueName, 0&, lType, sValue, cch)
            If lrc = ERROR_NONE Then
                vValue = Left$(sValue, cch)
            Else
                vValue = Empty
            End If

        ' For DWORDS
        Case REG_DWORD:
            lrc = RegQueryValueExLong(lhKey, szValueName, 0&, lType, lValue, cch)
            If lrc = ERROR_NONE Then vValue = lValue

        Case Else
            'all other data types not supported
            lrc = -1

    End Select

QueryValueExExit:
    QueryValueEx = lrc
    Exit Function

QueryValueExError:
    Resume QueryValueExExit

End Function

' *********************************************************************
' Class Initialisation & Termination routines
' *********************************************************************

Private Sub Class_Initialize()

    ' Logon at start
    Call LogonToSession

End Sub


Private Sub Class_Terminate()

    ' Log off if logged on
    If mbooLoggedOn Then mobjSession.Logoff

End Sub

' *********************************************************************
' Logon routine
' *********************************************************************

Private Sub LogonToSession()

Dim sKeyName As String
Dim sValueName As String
Dim sDefaultUserProfile As String
Dim osinfo As OSVERSIONINFO
Dim retvalue As Integer

    On Error GoTo ErrorHandler
    Set mobjSession = CreateObject("MAPI.Session")

    'Try to logon.  If it fails, the most likely reason is that you do
    'not have an open session.  Error -2147221231  MAPI_E_LOGON_FAILED
    'will return.  Trap the error in the ErrorHandler
    mobjSession.Logon ShowDialog:=False, NewSession:=False
    mbooLoggedOn = True
    Exit Sub

ErrorHandler:

    Select Case Err.Number
        Case -2147221231  'MAPI_E_LOGON_FAILED
            'Need to find out what OS is in use, the keys are different for WinNT and Win95.
            osinfo.dwOSVersionInfoSize = 148
            osinfo.szCSDVersion = Space$(128)
            retvalue = GetVersionEx(osinfo)

            Select Case osinfo.dwPlatformId
                Case 0   'Unidentified
                    MsgBox "Unidentified Operating System.  " & _
                    "Can't log onto messaging."
                    Exit Sub

                Case 1   ' 95, 98, ME
                    sKeyName = "Software\Microsoft\" & _
                    "Windows Messaging Subsystem\Profiles"

                Case 2   ' NT, 2000, XP, Sever 2003, Server Longhorn, Vista
                    sKeyName = "Software\Microsoft\Windows NT\" & _
                    "CurrentVersion\" & _
                    "Windows Messaging Subsystem\Profiles"

            End Select

            sValueName = "DefaultProfile"
            sDefaultUserProfile = QueryValue(sKeyName, sValueName)
            mobjSession.Logon ProfileName:=sDefaultUserProfile, ShowDialog:=False
            mbooLoggedOn = True
            Exit Sub

        Case Else
            MsgBox "An error has occured while attempting" & Chr(10) & _
            "To create and logon to a new CDO (1.x) session." & _
            Chr(10) & "Please report the following error to your " & _
            "System Administrator." & Chr(10) & Chr(10) & _
            "Error Location: frmMain.StartMessagingAndLogon" & _
            Chr(10) & "Error Number: " & Err.Number & Chr(10) & _
            "Description: " & Err.Description

    End Select

End Sub

' *********************************************************************
' Send e-mail routine
' *********************************************************************

Public Function SendMail(strTo As String, strTitle As String, strBody As String) As Boolean

Dim objNewMessage As MAPI.Message
Dim objRecipient As MAPI.Recipient

    ' Logon if not logged on
    If Not mbooLoggedOn Then Call LogonToSession

    ' Create a new message
    Set objNewMessage = mobjSession.Outbox.Messages.Add

    ' Add a subject
    objNewMessage.Subject = strTitle

    ' Add text to the message body
    ' Note that CDO 1.x cannot add text formatted with RTF or HTML
    ' Only Plain Text is supported in the current version
    objNewMessage.Text = strBody

    ' Add recipient and resolve against the directory
    Set objRecipient = objNewMessage.Recipients.Add
    objRecipient.Name = strTo
    objRecipient.Resolve

    ' Send message
    objNewMessage.Update
    objNewMessage.Send

End Function
Example interaction code:
Code:
Option Explicit

Sub Test()

Dim clsMAPI As New clsMAPIWrapper
Dim booRtn As Boolean

    ' Send an e-mail
    booRtn = clsMAPI.SendMail(Application.UserName, "MAPI Test", "Hello")

    ' De-reference variable
    Set clsMAPI = Nothing

End Sub
 
Old March 29th, 2007, 03:45 AM
Authorized User
 
Join Date: Mar 2007
Posts: 11
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Hi Maccas,
             Thanks for the great help.However, I'm still stuck.Could i email you my sample input files instead so that you can guide me along.Thanks in advanced.Could you kindly give me your email address pls?Thanks
My email address is [email protected]






Similar Threads
Thread Thread Starter Forum Replies Last Post
Generate summ rpt,auto send fr various excel files miracles Excel VBA 0 March 28th, 2007 02:56 AM
Auto generate no mateenmohd Classic ASP Basics 3 June 11th, 2006 07:06 AM
Auto generate? nikryden BOOK: Beginning VB.NET Databases 2 December 19th, 2005 12:43 PM
Setup project with Crystal rpt. files drasko Crystal Reports 2 April 1st, 2005 07:46 AM
auto generate an number utarian Access 2 March 28th, 2005 02:24 AM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.