Counting how many time a template is accessed

L

Lee

I am needing to find out how many times each template is
accessed/used.

Can anyone tell me how I would go about writing code or
getting code for this please?

I thought that code could be placed into every template so
that when it is accessed, it appends a number in a
logfile, e.g. create a file called <template_name>.log if
one doesn't exist (in the templates folder), read the
file, add 1 to it, close the file.

It probably is pretty simply code but as I am only
learning, I'm not sure where to start.

Thanks in advance
 
J

Jezebel

Do you mean every time the template is accessed, or every time a document is
created using the template?

You can write macros called AutoNew and AutoOpen ... these run when a
document is created and opened. In the macro you can check the attached
template of the document created or opened.

Instead of putting the macros into every template, you could put them into
an add-in (a template saved in Word's start-up folder). Then you'd need only
one copy; they'll run whatever template is used. Rather than using a
separate logfile for each template, you could store a document property or
variable in the template itself, or use a single logfile for all templates.
 
D

Doug Robbins - Word MVP

See the article "Creating sequentially numbered documents (such as
invoices)" at:

http://word.mvps.org/FAQs/MacrosVBA/NumberDocs.htm


--
Please post any further questions or followup to the newsgroups for the
benefit of others who may be interested. Unsolicited questions forwarded
directly to me will only be answered on a paid consulting basis.

Hope this helps
Doug Robbins - Word MVP
 
L

Lee

Thank you for replying to my post.
Every time a new document is created based on that
template. Within most of my templates I have a macro
called AutoNew but I sort of understand what you mean by
storing the coding into an add-in... The thing is I am not
sure where/how to even start coding this. It was my
thought to have some code that would add the number of
times each template was accessed and to save it to a
logfile BUT how would it work if I only had one log file??
Kinda confused...
Lee
 
L

Lee

Thanks.
This sort of helps but I don't want the number to appear
anywhere on the created document. I want to save it to a
logfile or something like that but am unsure on how to do
that.
Cheers
Lee
 
D

Doug Robbins - Word MVP

The following will create a log file to which will be added a number each
time the template is used:

Sub autonew()
'
' Test Macro created by Doug Robbins
'
Dim Order As Long, Log As Document
Order = Val(System.PrivateProfileString("C:\Settings.Txt", _
"MacroSettings", "Order"))
If Order = 0 Then
Order = 1
Set Log = Documents.Add
Log.Range.Text = Order
Log.SaveAs "C:\log.doc"
Else
Order = Order + 1
Set Log = Documents.Open("C:\log.doc")
Log.Range.InsertAfter vbCr & Order
End If
System.PrivateProfileString("C:\Settings.txt", "MacroSettings", _
"Order") = Order
Log.Close wdSaveChanges

End Sub


--
Please post any further questions or followup to the newsgroups for the
benefit of others who may be interested. Unsolicited questions forwarded
directly to me will only be answered on a paid consulting basis.

Hope this helps
Doug Robbins - Word MVP
 
P

Peter Hewett

Hi Lee

An AddIn is a template that is generally loaded Automatically when Word starts. You
generally store the AddIn in the folder specified in Tools>Options>File Locations>Startup.

Here's the code you'll need to construct an addin to count the usage of *any* template
used to create a new document while the AddIn is loaded. To use this code you need to
create a new template "count template usage.dot". To this template from within the VBA
IDE (editor) create a new Module. To this new module add the following code (cut and
paste it):

'<----------------------Start of Module Code---------------------------->
Option Explicit

Public gccTemplateUsageCounter As clsCounter

Public Sub AutoExec()
Const cCounterFileFullPath As String = "c:\template usage count.cnt"

' Instantiate class to perform template usage counting
Set gccTemplateUsageCounter = New clsCounter

' Hook up event handler to that we can catch application level events
Set gccTemplateUsageCounter.appWord = Word.Application

' Log the existing counter file (if any)
gccTemplateUsageCounter.Initialise cCounterFileFullPath
End Sub
'<----------------------End of Module Code---------------------------->

Now add a new Class Module to your project, this class module *must* be named
"clsCounter". To this new class module add the following code (cut and paste it):

'<--------------Start of Class Module clsCounter Code--------------------->
Option Explicit

Private Const mcInitialSize As Long = 50
Private Const mcIncrementSize As Long = 10

Private Type UsageCounter
Template As String
Count As Long
End Type

Public WithEvents appWord As Word.Application

Private maucCounters() As UsageCounter
Private mlngCountersMax As Long
Private mstrCounterFile As String

Public Sub Initialise(ByVal strCounterFile As String)
Dim lngIndex As Long
Dim strData As String
Dim astrData() As String

' Set array to it's initial sizing
ReDim maucCounters(0 To mcInitialSize - 1) As UsageCounter
mlngCountersMax = -1

' Save the counter file name for when we need to update it
mstrCounterFile = strCounterFile

' Read the counter file and load the contents into the array
strData = ReadFile(strCounterFile)

' Parse the counter file a line at a time
astrData = Split(strData, vbCrLf)
For lngIndex = 0 To UBound(astrData)

' Now parse out the data: Path, Template, Counter
AddExistingCounter astrData(lngIndex)
Next

' Make sure the array if not too flabby
If mcInitialSize - mlngCountersMax > mcIncrementSize - 1 Then
ReDim Preserve maucCounters(0 To mlngCountersMax + mcIncrementSize)
End If
End Sub

Private Sub appWord_NewDocument(ByVal Doc As Document)

' Count the usage of the current template
CountCurrentTemplate Doc.AttachedTemplate
End Sub

Private Function ReadFile(ByVal strInputFile As String) As String
Dim strInput As String
Dim hFile As Long

' Next available file number
hFile = FreeFile

' Open and read the entire file
Open strInputFile For Binary Access Read Shared As hFile
ReadFile = Input(LOF(hFile), hFile)

' All done - so close the file
Close hFile
End Function

Private Sub WriteFile(ByRef rstrData As String)
Dim hFile As Long

' Next available file number
hFile = FreeFile

' Open and write the entire file
Open mstrCounterFile For Binary Access Write Shared As hFile
Put hFile, , rstrData

' All done - so close the file
Close hFile
End Sub

Private Sub AddExistingCounter(ByVal strData As String)
Dim astrDatum() As String

' The array must be large enough to hold the data
MakeSpaceInArray

' Parse out the data (FullPath, Counter) and add it to the array
astrDatum = Split(strData, ",")
With maucCounters(mlngCountersMax)
.Template = astrDatum(0)
.Count = CLng(astrDatum(1))
End With
End Sub

Private Sub CountCurrentTemplate(ByVal tplTemplate As Word.Template)
Dim lngIndex As Long
Dim boolFound As Boolean

' Try to locate and use an existing counter before creating a new one
If mlngCountersMax >= 0 Then
For lngIndex = 0 To mlngCountersMax
With maucCounters(lngIndex)
If StrComp(.Template, tplTemplate.FullName, vbTextCompare) = 0 Then
.Count = .Count + 1
boolFound = True
End If
End With
Next
End If

' Add a new counter
If boolFound = False Then

' The array must be large enough to hold the data
MakeSpaceInArray
With maucCounters(mlngCountersMax)
.Template = tplTemplate.FullName
.Count = .Count + 1
End With
End If

' Save the template usage count information
SaveCounterInformation
End Sub

Private Sub MakeSpaceInArray()

' Make sure the array is large enough to hold the next piece of data
' if not then increase its size by the specified increment size
mlngCountersMax = mlngCountersMax + 1
If mlngCountersMax > UBound(maucCounters) Then
ReDim Preserve _
maucCounters(0 To UBound(maucCounters) + mcIncrementSize) As UsageCounter
End If
End Sub

Private Sub SaveCounterInformation()
Dim lngIndex As Long
Dim strData As String

' Concatenate all data into one string, separate the Template
' and Counter using a comma and each line using vbCr
If mlngCountersMax >= 0 Then
For lngIndex = 0 To mlngCountersMax
With maucCounters(lngIndex)
If lngIndex > 0 Then
strData = strData & (vbCrLf & .Template & "," & CStr(.Count))
Else
strData = (.Template & "," & CStr(.Count))
End If
End With
Next
End If

' Write the data to the counter file
WriteFile strData
End Sub
'<----------------------End of Class Module Code---------------------------->

If you get really stuck email me and I'll email you the template that contains the above
code. But it would be a good idea to become familiar with Word/VBA and the VBA
environment yourself. My email address is:

nospaminnerword at xtra dot co dot nz

remove the "nospam" and replace dot with . and at with @. Also because I run two spam
filters (one at my ISP and one on my PC) you message will NOT get through unless you mark
the subject line: "microsoft.public.word.vba.general - AddIn"

HTH + Cheers - Peter


Thank you for replying to my post.
Every time a new document is created based on that
template. Within most of my templates I have a macro
called AutoNew but I sort of understand what you mean by
storing the coding into an add-in... The thing is I am not
sure where/how to even start coding this. It was my
thought to have some code that would add the number of
times each template was accessed and to save it to a
logfile BUT how would it work if I only had one log file??
Kinda confused...
Lee

HTH + Cheers - Peter
 
L

Lee

Thanks Peter

I will try this and if I get stuck, I'll email you. I did
get some coding from another person which worked as well
but I have been trying to manipulate it so that each
template writes the count to the same log file as we have
about 50 templates that I need to count!!

Thanks once again Peter
Lee
-----Original Message-----
Hi Lee

An AddIn is a template that is generally loaded
Automatically when Word starts. You
generally store the AddIn in the folder specified in
Tools>Options>File Locations>Startup.
Here's the code you'll need to construct an addin to
count the usage of *any* template
used to create a new document while the AddIn is loaded. To use this code you need to
create a new template "count template usage.dot". To
this template from within the VBA
IDE (editor) create a new Module. To this new module add the following code (cut and
paste it):

'<----------------------Start of Module Code-------------- -------------->
Option Explicit

Public gccTemplateUsageCounter As clsCounter

Public Sub AutoExec()
Const cCounterFileFullPath As String = "c:\template usage count.cnt"

' Instantiate class to perform template usage counting
Set gccTemplateUsageCounter = New clsCounter

' Hook up event handler to that we can catch application level events
Set gccTemplateUsageCounter.appWord = Word.Application

' Log the existing counter file (if any)
gccTemplateUsageCounter.Initialise cCounterFileFullPath
End Sub
'<----------------------End of Module Code---------------- ------------>

Now add a new Class Module to your project, this class module *must* be named
"clsCounter". To this new class module add the following code (cut and paste it):

'<--------------Start of Class Module clsCounter Code----- ---------------->
Option Explicit

Private Const mcInitialSize As Long = 50
Private Const mcIncrementSize As Long = 10

Private Type UsageCounter
Template As String
Count As Long
End Type

Public WithEvents appWord As Word.Application

Private maucCounters() As UsageCounter
Private mlngCountersMax As Long
Private mstrCounterFile As String

Public Sub Initialise(ByVal strCounterFile As String)
Dim lngIndex As Long
Dim strData As String
Dim astrData() As String

' Set array to it's initial sizing
ReDim maucCounters(0 To mcInitialSize - 1) As UsageCounter
mlngCountersMax = -1

' Save the counter file name for when we need to update it
mstrCounterFile = strCounterFile

' Read the counter file and load the contents into the array
strData = ReadFile(strCounterFile)

' Parse the counter file a line at a time
astrData = Split(strData, vbCrLf)
For lngIndex = 0 To UBound(astrData)

' Now parse out the data: Path, Template, Counter
AddExistingCounter astrData(lngIndex)
Next

' Make sure the array if not too flabby
If mcInitialSize - mlngCountersMax > mcIncrementSize - 1 Then
ReDim Preserve maucCounters(0 To mlngCountersMax + mcIncrementSize)
End If
End Sub

Private Sub appWord_NewDocument(ByVal Doc As Document)

' Count the usage of the current template
CountCurrentTemplate Doc.AttachedTemplate
End Sub

Private Function ReadFile(ByVal strInputFile As String) As String
Dim strInput As String
Dim hFile As Long

' Next available file number
hFile = FreeFile

' Open and read the entire file
Open strInputFile For Binary Access Read Shared As hFile
ReadFile = Input(LOF(hFile), hFile)

' All done - so close the file
Close hFile
End Function

Private Sub WriteFile(ByRef rstrData As String)
Dim hFile As Long

' Next available file number
hFile = FreeFile

' Open and write the entire file
Open mstrCounterFile For Binary Access Write Shared As hFile
Put hFile, , rstrData

' All done - so close the file
Close hFile
End Sub

Private Sub AddExistingCounter(ByVal strData As String)
Dim astrDatum() As String

' The array must be large enough to hold the data
MakeSpaceInArray

' Parse out the data (FullPath, Counter) and add it to the array
astrDatum = Split(strData, ",")
With maucCounters(mlngCountersMax)
.Template = astrDatum(0)
.Count = CLng(astrDatum(1))
End With
End Sub

Private Sub CountCurrentTemplate(ByVal tplTemplate As Word.Template)
Dim lngIndex As Long
Dim boolFound As Boolean

' Try to locate and use an existing counter before creating a new one
If mlngCountersMax >= 0 Then
For lngIndex = 0 To mlngCountersMax
With maucCounters(lngIndex)
If StrComp(.Template,
tplTemplate.FullName, vbTextCompare) = 0 Then
.Count = .Count + 1
boolFound = True
End If
End With
Next
End If

' Add a new counter
If boolFound = False Then

' The array must be large enough to hold the data
MakeSpaceInArray
With maucCounters(mlngCountersMax)
.Template = tplTemplate.FullName
.Count = .Count + 1
End With
End If

' Save the template usage count information
SaveCounterInformation
End Sub

Private Sub MakeSpaceInArray()

' Make sure the array is large enough to hold the next piece of data
' if not then increase its size by the specified increment size
mlngCountersMax = mlngCountersMax + 1
If mlngCountersMax > UBound(maucCounters) Then
ReDim Preserve _
maucCounters(0 To UBound(maucCounters) +
mcIncrementSize) As UsageCounter
End If
End Sub

Private Sub SaveCounterInformation()
Dim lngIndex As Long
Dim strData As String

' Concatenate all data into one string, separate the Template
' and Counter using a comma and each line using vbCr
If mlngCountersMax >= 0 Then
For lngIndex = 0 To mlngCountersMax
With maucCounters(lngIndex)
If lngIndex > 0 Then
strData = strData & (vbCrLf
& .Template & "," & CStr(.Count))
Else
strData = (.Template & "," & CStr (.Count))
End If
End With
Next
End If

' Write the data to the counter file
WriteFile strData
End Sub
'<----------------------End of Class Module Code---------- ------------------>

If you get really stuck email me and I'll email you the
template that contains the above
code. But it would be a good idea to become familiar with Word/VBA and the VBA
environment yourself. My email address is:

nospaminnerword at xtra dot co dot nz

remove the "nospam" and replace dot with . and at with
@. Also because I run two spam
filters (one at my ISP and one on my PC) you message will
NOT get through unless you mark
 
L

Lee

Thank you Doug

This coding works and I sort of understand how it was
written! (shock horror..haha). I'm just trying to
manipulate it now so that each template will write to the
same log file as I have about 50 templates that need
counting and don't want 50 log files.

Thanks once again Doug - your help is very appreciated.
Lee
-----Original Message-----
The following will create a log file to which will be added a number each
time the template is used:

Sub autonew()
'
' Test Macro created by Doug Robbins
'
Dim Order As Long, Log As Document
Order = Val(System.PrivateProfileString ("C:\Settings.Txt", _
"MacroSettings", "Order"))
If Order = 0 Then
Order = 1
Set Log = Documents.Add
Log.Range.Text = Order
Log.SaveAs "C:\log.doc"
Else
Order = Order + 1
Set Log = Documents.Open("C:\log.doc")
Log.Range.InsertAfter vbCr & Order
End If
System.PrivateProfileString
("C:\Settings.txt", "MacroSettings", _
 
P

Peter Hewett

Hi Lee

The code I supplied is designed and implemented to handle any number of templates (though
it may slow a little if there are many hundreds of them (>500) as it's not optimised).
But 50 is at the bottom end of it capabilities. All counting is done to the same file -
try it.

HTH + Cheers - Peter
 
L

Lee

Hi Peter

Your coding works wonders but the only problem that I am
having now, is that a run-time error '13' Type Mismatch
shows everytime staff open MS Word.

This is weird as it was running okay for the first two
days then started the run-time error.

This template has been loaded onto everyone's
P:\templates\startup and was running okay for a couple of
days but now everyone gets the above error message. We
are running a network and everyone has their own settings
for Word etc hence why we have to save it to everyone's
p:\templates\startup... (P:\ = personal drive). We run MS
Word 2002.

I have changed the source code so that it saves to a
folder that all staff have access to.....

Any ideas? I have emailed this to you as well

Thanks for your time and knowledge
Lee

-----Original Message-----
Hi Lee

The code I supplied is designed and implemented to handle
any number of templates (though
it may slow a little if there are many hundreds of them (>500) as it's not optimised).
But 50 is at the bottom end of it capabilities. All
counting is done to the same file -
 
P

Peter Hewett

Hi Lee

You need to determine on what line the code fails. Even though the Add-In is loaded open
it as a template as well. This will enable you to debug it while it's loaded. Post back
as to where the code is failing.

HTH + Cheers - Peter
 
P

Peter Hewett

Hi Lee

On reading your post again and after looking at my code again I suspect that the problem
is that *all* users are using the same count/log file. The code is *not* designed for
this, it's designed to have one count/log file per user. The solution is to set the path
of the log file to a location that's unique to the user. In most corporate environments
the users can save private documents to the file server, so this would be the ideal place
for this.

HTH + Cheers - Peter
 
L

Lee

Hi Peter

The code is failing in the line marked with 3 *'s.

Public Sub AutoExec()
Const cCounterFileFullPath As String
= "\\alchemy\data\TECHNOLOGY\template_usage\template_usage_
count.cnt"

' Instantiate class to perform template usage counting
Set gccTemplateUsageCounter = New clsCounter

' Hook up event handler to that we can catch
application level events
Set gccTemplateUsageCounter.appWord = Word.Application

' Log the existing counter file (if any)
*** gccTemplateUsageCounter.Initialise
cCounterFileFullPath
End Sub

Cheers
Lee

-----Original Message-----
Hi Lee

You need to determine on what line the code fails. Even
though the Add-In is loaded open
it as a template as well. This will enable you to debug
it while it's loaded. Post back
 
P

Peter Hewett

Hi Lee

The clsCounter initialisation procedure is failing for some reason. Set a breakpoint at
this line and when you get there, use F8 to step into the class module to see where the
code fails. I've been messing with this for a while and I can't make mine fail, but I not
working from a file server.

HTH + Cheers - Peter
 
L

Lee

That's what it could be...
I cannot set the log file to a unique user location as
this means I would not have access to it and I would then
have to tally up 220 log files!!!
What a hassle to try and find out how many templates are
used over a month by staff. I tried sending a survey to
all staff but only 6% of staff answered it. Thought this
might of been an easier way... :eek:)

Cheers
Lee
-----Original Message-----
Hi Lee

On reading your post again and after looking at my code
again I suspect that the problem
is that *all* users are using the same count/log file. The code is *not* designed for
this, it's designed to have one count/log file per user.
The solution is to set the path
of the log file to a location that's unique to the user. In most corporate environments
the users can save private documents to the file server,
so this would be the ideal place
 
L

Lee

Hi Peter
I have run through this to see where its failing... it
steps through many many times and then stops at:

Private Sub AddExistingCounter(ByVal strData As String)
Dim astrDatum() As String

' The array must be large enough to hold the data
MakeSpaceInArray

' Parse out the data (FullPath, Counter) and add it to
the array
astrDatum = Split(strData, ",")
With maucCounters(mlngCountersMax)
.Template = astrDatum(0)
.Count = CLng(astrDatum(1))
End With
End Sub

After it runs .Count = CLng(astrDatum(1)) code, it brings
up the error message. When I press debug, it goes to the

' Log the existing counter file (if any)
line of the Public Sub AutoExec() code.

This code runs through many many times over and over again
before it actually fails... not sure what its doing!!
Cheers
Lee
-----Original Message-----
Hi Lee

The clsCounter initialisation procedure is failing for
some reason. Set a breakpoint at
this line and when you get there, use F8 to step into the class module to see where the
code fails. I've been messing with this for a while and
I can't make mine fail, but I not
 
P

Peter Hewett

Hi Lee

Writing code to aggregate the individual log files is *fairly* trivial given that you can
reuse parts of the existing code.

HTH + Cheers - Peter
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top