Make Individual Serial for Print documents in Word - vba

Dear Readers
I am trying to make individual Serial numbers ( incrementing number) for some Forms in Microsoft Word, so we can track each one of them much simpler between people.
I used this link and it did work,
but it needs always running Macro and I couldn't figure out how to make it automatic with just a simple Ctrl+P shortcut, so I used this second link for that reason,
finally, it looked so great but there is a problem since the second link is a just "before Print" code, there is always one extra print at the end since the Printing process starts exactly after macro ended. any cancel print process code out there?
how can I overcome this one?
Codes under the document
Private Sub Document_Open()
Register_Event_Handler
End Sub
Codes under the Module
Dim X As New EventClassModule
Sub Register_Event_Handler()
Set X.App = Word.Application
End Sub
Codes under the class
Public WithEvents App As Word.Application
Private Sub App_DocumentBeforePrint(ByVal Doc As Document, Cancel As Boolean)
' Run code directly inside this Sub OR
MsgBox "Before Print"
' Call another Sub here, note, Sub and Module name can't match
Call FilePrint
' See https://www.freesoftwareservers.com/wiki/compile-error-expected-variable-or-procedure-not-module-macros-microsoft-office-29982732.html
End Sub
and finally Codes of FilePrint section as a Module
Sub FilePrint()
Dim i As Long, j As Long
With ActiveDocument
j = CLng(InputBox("How many copies to print?", "Print Copies"))
For i = 1 To j
With .CustomDocumentProperties("Counter")
.Value = .Value + 1
End With
.Fields.Update
ActiveDocument.PrintOut Copies:=1
Next
.Save
End With
End Sub

Related

Document_Open() does not work in other files

I am writing a VBA project containing 1 module (m1) and 1 userform (uf).
In "ThisDocument" I am calling a public sub from "m1" that initializes a collection I then refer to in the userform. This works perfectly fine until I deploy this project to other files.
I save the file as a .dotm in the %Appdata%/Microsoft/word/startup folder so I can use the project in all of my word files. But as soon as I try to use my project in other files the userform opens itself as designed but the collection is empty.
What could be the problem here?
Manually calling the initialization method from the userform works fine.
'----------------------------------------------ThisDocument
Private Sub Document_Open()
initBetaCollection
End Sub
'----------------------------------------------m1
Option Explicit
Public beta As Collection
Sub initBetaCollection()
Set beta = New Collection
beta.Add Array("0041", "A"), Key:="0041"
'...
End Sub
'----------------------------------------------uf
Option Explicit
Private Sub txtSearch_Change()
Dim arr As Variant
Dim search As String
'Defining the textinput as "search"
search = txtSearch.Value
For Each arr In beta
If search <> "" Then 'No empty search field
If arr(1) Like "*" & search & "*" Then 'Match found
lbResults.AddItem arr(0)
End If
End If
Next
End Sub
I get the: Run Time Error '424' object required
The problem with using Document_Open in the ThisDocument class or a macro named AutoOpen in a regular module is that both execute specifically for this document (or documents created from the template), only.
In order to have an application-level event, that fires for all documents opened, it's necessary to work with application-level events.
For this, first a class module is required. In the class module, the following code is needed:
'Class module named: Class1
Public WithEvents app As Word.Application
Private Sub app_DocumentOpen(ByVal Doc As Document)
'MsgBox Doc.FullName & ": on Open"
'Code here that should fire when a document is opened
'If something needs to be done with this document, use
'the Doc parameter passed to the event, don't try to use ActiveDocument
End Sub
Then, in a regular module, an AutoExec macro can be used to initialize the class with event handling. (AutoExec: fires when Word starts and loads a template with a macro of this name.)
Option Explicit
Dim theApp As New Class1
Sub AutoExec()
'MsgBox "AutoExec"
Set theApp.app = Word.Application
End Sub
'Sub AutoOpen()
' MsgBox "Open in AutoOpen" - fires only for this document
'End Sub

How to schedule an async macro from WORD

I'm facing an annoying issue where I simply want to schedule an asynchronous macro from another instance of Word, which happens to be the same .doc file.
Meaning, in the ThisDocument namespace I have the following code snippet:
Public Sub Document_Open()
Set Obj = New Word.Application
Obj.OnTime Now + TimeValue("00:00:01"), "Module1.Test"
End Sub
I've declared a new object of Word due to the following reasons:
My macro may block user's I\O
The user may close the document before the macro finishes its task
And declared a module named Module1 with a simple MsgBox
Public Sub Test()
MsgBox "hhh"
End Sub
Needless to say, nothing happened, and I'm unable to check what OnTime function returns.
I've also tried the following combinations:
"!Module1.Test"
"c:\\....\\file.doc!Module1.Test"
What am I missing here?
Your newly created Word application, represented by a Word.Application object, doesn't have the document open. Thus there's no "Module1" as far as he's aware. The fact that you want to run code from the same document is immaterial. It's a different instance of Word.
Something like this works:
'''''''' ThisDocument
Option Explicit
Private Sub Document_Open()
Dim res As VbMsgBoxResult
Dim Obj As Word.Application
If Application.Visible Then
res = MsgBox("Hello", vbOKCancel, "Hi!")
Else
Exit Sub
End If
If res = vbOK Then
Set Obj = New Word.Application
Obj.Documents.Open "C:\Users\conio\Desktop\Hello.docm", , True
Obj.OnTime Now + TimeValue("00:00:01"), "Module1.Foo"
End If
End Sub
'''''''' Module1
Public Sub Foo()
If Not Application.Visible Then
MsgBox "Foo"
Application.Quit
End If
End Sub
Maybe you'd want to use a different check to differentiate between the interactive run and the unattended run.

Document_New event on launching Word

I have a VBA addin which I want to run every time someone opens a document. It's working fine for opening existing documents (AutoOpen) and creating new documents from the File > New menu (AutoNew) but when I just open Word up for the first time, neither of these events are firing. The only event I can seem to hook into is the AutoExec event and this is not great as the document doesn't exist yet so ActiveWindow is null.
Can anyone help?
Sub AutoNew
MsgBox "New"
End Sub
Sub AutoOpen
MsgBox "Open"
End Sub
Sub AutoExec
MsgBox "Exec"
End Sub
I would start with DocumentOpen and NewDocument. An additional level of complexity exists if you need to support ProtectedView documents; Word triggers a different event. I've found that if I try to check for that event (and it doesn't occur) it raises an error. I didn't had much luck and eventually it wasn't worth the time I was spending. I've posted an example below of some code that opens the Style Pane when a document is opened or a new one created (assuming the add-in is loading) and expands the style margin in draft view if not already expanded.
In my UI module:
Dim X As New clsAppEvent 'This is in the declarations
Public Sub OnRibbonLoad(objRibbon As IRibbonUI)
Do While Documents.Count = 0
DoEvents
Loop ' I find this useful as sometimes it seems my ribbon loads before the document.
Call Register_Event_Handler
' Other stuff
End Sub
Private Sub Register_Event_Handler()
Set X.App = Word.Application
End Sub
Then, in a class module I call clsAppEvent:
Option Explicit
Public WithEvents App As Word.Application
Private Sub App_DocumentOpen(ByVal Doc As Document)
App.TaskPanes(wdTaskPaneFormatting).visible = True
End Sub
Private Sub App_NewDocument(ByVal Doc As Document)
App.TaskPanes(wdTaskPaneFormatting).visible = True
End Sub
Private Sub App_WindowActivate(ByVal Doc As Document, ByVal Wn As Window)
If Wn.StyleAreaWidth <= 0 Then
Wn.StyleAreaWidth = 60
End If
End Sub
Other than the caveats I've noted above, the one problem I've had is if a user has Auto code in their Normal template as well. This has only come up once so I haven't investigated it.
I wish I could find the site where I learned about this (and from which the Register_Event_Handler was derived. If I find it I'll add a comment.

how to check if word document has printed already

I want to enable another function "code" only if the document has been printed already, i was thinking something along the lines of
Sub Testing
Dim hasPrinted as boolean
If ActiveDocument.PrintOut = True Then
hasPrinted = True
call code here...
Else
hasPrinted = False
MsgBox "Please Print Before Adding"
End If
End Sub
i receive an error that says "Compile Error, expected function or variable" on the "ActiveDocument.PrintOut" line. Could anyone give me some directions?
Capturing the print events is not an easy job in Word VBA. However here is a neat trick :)
For this do the following
Create a class module say Class1 and paste this code
Option Explicit
Public WithEvents oApp As Word.Application
Private Sub oApp_DocumentBeforePrint(ByVal Doc As Document, Cancel As Boolean)
ActiveDocument.Bookmarks("DocWasPrinted").Delete
With ActiveDocument.Bookmarks
.Add Range:=Selection.Range, Name:="DocWasPrinted"
.DefaultSorting = wdSortByName
.ShowHidden = True
End With
End Sub
Now insert a module and paste this code
Option Explicit
Dim oAppClass As New Class1
Public Sub AutoExec()
Set oAppClass.oApp = Word.Application
End Sub
Sub Testing()
If hasPrinted = True Then
MsgBox "Document was printed"
'~~> Call your code
Else
MsgBox "Please Print Before Adding"
End If
End Sub
Function hasPrinted() As Boolean
If ActiveDocument.Bookmarks.Exists("DocWasPrinted") = True Then
hasPrinted = True
End If
End Function
Close your document and reopen it. Now test it.
LOGIC:
What this code does is the moment the user prints the document, the code creates a hidden bookmark called DocWasPrinted And in my code I check if the bookmark was created or not.
Remember to delete the bookmark on Document Exit.
Private Sub Document_Close()
ActiveDocument.Bookmarks("DoWasPrinted").Delete
End Sub
This question provides information about creating a make-shift Document After Print event.
Once you've done that, you can have a boolean value updated to true to indicate the document has printed. Word does not store this information natively.

Trigger MS Word macro after save event

My MS Word 2007 template has a footer with the filename in it. The user is going to open the template and do a "Save As..." to make their document.
I want the filename shown in the footer to update immediately to the new filename.
Is there an AfterSaveEvent or something that I can use as a hook to start my VBA script that does the update?
Or is there a much easier way?
Just create a macro like this (I believe it works better if included in the Normal.dot)
Sub FileSaveAs()
'
' FileSaveAs Macro
' Saves a copy of the document in a separate file
'
Dialogs(wdDialogFileSaveAs).Show
'returns the name including the .doc extension
ChosenFileNameAndExtension = ActiveDocument.Name 'Or use .FullName
' Your code here
End Sub
It will be triggered whenever the user selects "File Save As"
HTH!
This worked based on #belisarius' answer:
Sub UpdateAll()
Dim oStory As Object
Dim oToc As Object
'Exit if no document is open
If Documents.Count = 0 Then Exit Sub
Application.ScreenUpdating = False
For Each oStory In ActiveDocument.StoryRanges
oStory.Fields.Update 'Update fields in all stories
Next oStory
For Each oToc In ActiveDocument.TablesOfContents
oToc.Update 'Update table of contents
Next oToc
Application.ScreenUpdating = True
End Sub
Sub FileSaveAs()
'
' FileSaveAs Macro
' Saves a copy of the document in a separate file
'
Dialogs(wdDialogFileSaveAs).Show
UpdateAll
End Sub
We know that the Aftersave event isn't available for Microsoft Word. But Word allows us to use BeforeSave event. I have implemented this solution and it works fine.
First we have to implement Application.onTime method in Word BeforeSave event as follows
Private Sub mobjWord_DocumentBeforeSave(ByVal Doc As Word.Document, SaveAsUI As Boolean, Cancel As Boolean)
Word.Application.OnTime Now + TimeValue("00:00:02"), "AfterSave"
End Sub
This method will call the method called AfterSave after 2 seconds.
Public Sub AfterSave()
While Word.ActiveDocument.Application.BackgroundSavingStatus <> 0
DoEvents
Wend
'Implement your code here
End Sub
In this method the while loop will be circulated until the document save process is completed. So you can implement you code after the while loop.