Loaders vs Front Loaders
Both Loaders and Front Loaders are standalone solutions, developed with tools like classic VB and VB.NET, which target to manipulate other files via automation with a predefined number of actions.
The difference here in this context is that while Front Loaders have a visualized user interface Loaders don’t have it and therefore Loaders are always used in silent mode.
Using Loaders and Front Loaders are, at least for me, one of the more powerful solutions when it comes to manipulating Excel workbooks. Up to this date I have delivered more then 80 clients solutions based on different kind of Loaders and Front Loaders where the majority still are in use.
The real power is achieved when using Loaders together with Windows Scheduled Tasks tool on a Windows server.
Creating a Loader by using VB.NET 2005
The case is based on a scenario where we schedule a task to be executed every Sunday night so when the co-workers start their work on Mondays they have the latest update when they open the workbooks in Excel.
The two Excel workbooks in use are located in the same folder and they should be populated with the latest data from a central production’s database. None of the workbooks contain any code.
The Loader should do the following:
- Start MS Excel
- Open every workbook in the folder
- Add data to the workbooks
- Save and Close the workbooks
- Close MS Excel
- Report status after the processing above by writing to a log file.
The case does not require any user interface as all execution will be done via automation, i e the scheduled task starts the Loader which in return manipulate the workbooks as described above.
In order to keep the solution flexible ( i e hard code the generic but avoid to hard code the less general information) the case require a text file which should contain the following information:
- The full pathway to the folder
- The SQL queries
A XML-file may be nice to use here but I still prefer to work with ‘traditional’ text files for two reasons:
- They usually don’t contain a large amount of information and therefore not require a structure as XML-files offer.
- I’m both old fashioned and have not yet achieved all the knowledge to fully work with XML-files.
Below is the information that the text file ‘Loader.txt’ contains:
c:\Test\
SELECT * FROM Orders WHERE EmployeeID=SELECT * FROM Orders WHERE EmployeeID=
Using classic ADO or ADO.NET?
The decision in this case is quite easy to do. As long as the Range’s method CopyFromRecordset only support classic ADO (which is also true for Excel 2007!) and we have a larger amount of data classic ADO is the natural choice.
The Code
The code is placed in two modules:
In the Main module:
Module Main
Sub Main()
Dim cl As New clLoader
If cl.Update_Workbooks() Then cl.Write_Log (True)
cl = Nothing
End Sub
End Module
In a class module:
Imports System
Imports System.IO
Imports System.Runtime.InteropServices
Imports Excel = Microsoft.Office.Interop.Excel
Friend Class clLoader
Implements IDisposable
Public Sub New()
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
Static Disposed As Boolean
If Not Disposed Then
Disposed = True
GC.SuppressFinalize (Me)
End If
End Sub
Protected Overrides Sub Finalize()
Dispose()
End Sub
Friend Function Update_Workbooks() As Boolean
Const Con As String = “Provider=SQLNCLI.1;” & _
“Integrated Security=SSPI;” &
“Persist Security Info=False;” & _
“Initial Catalog=NorthWind;” & _
“Data Source=IBM\SQLExpress”
Dim cnt As New ADODB.Connection
Dim rst As ADODB.Recordset = Nothing
Dim xlApp As New Excel.Application
Dim xlWbook As Excel.Workbook = Nothing
Dim xlWsheet As Excel.Worksheet
Dim xlData As Excel.Range
Dim xlDate As Excel.Range
Dim xlCounter As Short
Try
Dim LoaderFile As String = Environment.CurrentDirectory _
& “\Loader.txt”
If File.Exists(LoaderFile) Then
Dim Reader As New IO.StreamReader(LoaderFile)
Dim GetValues() As String = _
Split(Reader.ReadToEnd, vbNewLine)
Reader.Close()
Dim Dir As DirectoryInfo = _
New DirectoryInfo(GetValues(0))
Dim xlFiles() As FileInfo = Dir.GetFiles(“*.xls”)
If UBound(xlFiles) <> -1 Then
Dim xlFile As FileInfo
With cnt
.CursorLocation = ADODB.CursorLocationEnum.adUseClient
.Open (Con)
End With
For Each xlFile In xlFiles
xlCounter = CShort(xlCounter + 1)
xlWbook = xlApp.Workbooks.Open(xlFile.FullName)
xlWsheet = _
CType(xlWbook.Worksheets(2), Excel.Worksheet)
With xlWsheet
xlData = .Range(“D3”)
xlDate = .Range(“B2”)
End With
xlDate.Value = Format(Now, “d”)
rst = cnt.Execute(GetValues(xlCounter))
rst.MoveFirst()
If rst.RecordCount <> -1 Then
With xlData
.CurrentRegion.Delete()
.CopyFromRecordset (rst)
End With
End If
rst.Close()
rst = Nothing
xlWbook.Close(SaveChanges:=True)
Next
Else
Write_Log(False, “No Excel files are located in ” _
& Dir.FullName)
Return False
End If
End If
xlApp.Quit()
Return True
Catch ex As Exception
If ex.Message Like “*BADINDEX” Then
Write_Log(False, xlWbook.FullName & _
” The required worksheet does not exist.”)
Else
Write_Log(False, ex.Message)
End If
GC.Collect()
GC.WaitForPendingFinalizers()
xlWbook.Close(SaveChanges:=False)
Marshal.FinalReleaseComObject (xlWbook)
xlApp.Quit()
Marshal.FinalReleaseComObject (xlApp)
Return False
Finally
xlData = Nothing
xlDate = Nothing
xlWsheet = Nothing
xlWbook = Nothing
xlApp = Nothing
If CBool (rst.State And _
ADODB.ObjectStateEnum.adStateOpen) = _
True Then rst.Close()
rst = Nothing
If CBool (cnt.State And _
ADODB.ObjectStateEnum.adStateOpen) = _
True Then cnt.Close()
cnt = Nothing
End Try
End Function
Friend Sub Write_Log(ByVal Status As Boolean, _
Optional ByVal Source As String = “”)
Dim Writer As StreamWriter = File.AppendText(“Log.txt”)
With Writer
If Status Then
.WriteLine (Now & ” – OK “)
Else
.WriteLine (Now & ” **********Error********** ” & Source)
End If
.Flush()
.Close()
End With
Writer = Nothing
End Sub
End Class
In general we should split up the code in smaller procedures but I made one procedure. Constructors, destructors and IDispose are general requirements when it comes to classes in VB.NET. In this case they are included but not fully used. What is important is to be aware of that IDispose and the Finalize methods can only handle so called unmanaged resources.
In addition to the main task, i e update the workbooks, the case also shows how we can handle files and directories.
Using .NET Framework in this scenario should not be a problem as it only requires to be installed on the Windows Server.
For all code generating I use a nice utility by the name of VS.NETcodePrint 2005
Please feel free to comment it and also suggest improvements for the solution.
Kind regards,
Dennis