How to determine if text is selected in Microsoft Word VBA..? - vba

In Word VBA, I would like to know the proper method to determine if text is selected. I may have the answer (shown below), but I want to ask if it's correct.
This is confusing, because most of the properties show no difference between nothing selected and one character selected.
An obvious possibility is If Selection.End - Selection.Start > 0, but this seems unnecessary. Is there not a specific property that is True or False..?
I see the property Selection.Type, but the documentation is very thin and unhelpful. It does not explain any details, such as the definitions of Normal, Inline, Block or any of the others. And searching Google for these answers was not helpful.
Through experimentation, I may have found the answer:
Selection.Type=wdSelectionIP seems to be when nothing is selected.
Selection.Type=wdSelectionNormal seems to be when any text is selected.
Is this the correct & reliable way to do it..?

Compare Selection.Type against wdSelectionIP. I have provided the code sample as below:
.
'Simple check if text is selected:
If (Selection.Type <> wdSelectionIP) Then
Debug.Print "You have selected: " & Selection.Text
Else
Debug.Print "No text is selected."
End If
.
'Graceful exit with message - if no selection found:
If Not (Selection.Type <> wdSelectionIP) Then
MsgBox "Text not selected." & vbNewLine & vbNewLine & "Please select text before proceeding", vbOKOnly & vbExclamation, "Selection not found"
Exit Sub
End If
.
This was also righty suggested by #Cindy Meister.
Reference: Microsoft Documentation (Selection.Type property).

Related

"ActiveWindow.ScrollIntoView Selection.Range, True" does not work

I need VBA (Word) to scroll to a certain location in the document before a messagebox (msgbox) in the macro is displayed.
I have tried:
ActiveWindow.ScrollIntoView Selection.Range, True
I have added DoEvents before the Msgbox call. Didn't work.
I have added a bookmark and then selected the bookmark before the Msgbox
I have added a sleeptimer, and other delays, before the Msgbox. Didn't work.
I have tried Application.Screenrefresh
Nothing works. Msgbox always displays with the cursor in the location it was located before the macro ran.
HOWEVER, if I step through the code in the VBA editor, all works fine. It's only when I am running the code 'straight through' that it never observes the ScrollIntoView command before showing the msgbox.
(Start at top of document)
(Search for text on, let's say page 3; if found . . .)
ActiveWindow.ScrollIntoView Selection.Range, True
DoEvents
Application.ScreenRefresh
Selection.Bookmarks.Add "Prompt"
Selection.Bookmarks("Prompt").Select
DoEvents
Selection.Range.Select
MsgBox " TASK: " & PromptIs & String(2, 13) & " Click OK below and perform the stated task."
The cursor should be at the found text and the text should be 'in view' before the message box is displayed. It's not.

VBA Access to Word error when creating numbered list

I have an Access database from which I create Word documents. I'm using Office 2016. When I run the code, I either get
Error 462 "Remote server machine does not exist or is unavailable"
or
Error -2147023170 "Error: Automation error, The remote procedure call
failed"
and Word closes.
On Error GoTo Err_CMD_Test
'Open Word document
Set GBL_objWord = CreateObject("Word.Application")
GBL_objWord.Visible = True
GBL_objWord.Activate
Set GBL_objDoc = GBL_objWord.Documents.Add
GBL_objDoc.Activate
'Traitement
GBL_objWord.Selection.TypeText Text:="List of something :"
GBL_objWord.Selection.TypeParagraph
GBL_objWord.Selection.TypeText Text:="Number one"
GBL_objWord.Selection.Range.ListFormat.ApplyListTemplate ListTemplate:=ListGalleries(2).ListTemplates(1), ContinuePreviousList:=True, ApplyTo:=0, DefaultListBehavior:=2
GBL_objWord.Selection.TypeParagraph
GBL_objWord.Selection.TypeText Text:="Number two"
GBL_objWord.Selection.Range.ListFormat.ApplyListTemplateWithLevel ListTemplate:=ListGalleries(wdNumberGallery).ListTemplates(1), ContinuePreviousList:=False, ApplyTo:=wdListApplyToWholeList, DefaultListBehavior:=wdWord10ListBehavior
Exit_CMD_Test:
Exit Sub
Err_CMD_Test:
Select Case Err.Number
Case Else
MsgBox "Erreur : " & Err.Description & vbCrLf & _
"Numéro : " & Err.Number & vbCrLf & _
"Procédure : CMD_Test", vbCritical, ""
Resume Next
End Select
The code breaks on
GBL_objWord.Selection.Range.ListFormat.ApplyListTemplate _
ListTemplate:=ListGalleries(2).ListTemplates(1), _
ContinuePreviousList:=True, ApplyTo:=0, DefaultListBehavior:=2
and on
GBL_objWord.Selection.Range.ListFormat.ApplyListTemplateWithLevel _
ListTemplate:=ListGalleries(wdNumberGallery).ListTemplates(1), _
ContinuePreviousList:=False, ApplyTo:=wdListApplyToWholeList, _
DefaultListBehavior:=wdWord10ListBehavior**"
I use the methods ApplyListTemplate and ApplyListTemplateWithLevel just to try both and the result is the same: an error. On the first one I changed he variables wdNumberGallery, wdListApplyToWholeList, wdWord10ListBehavior with their enumeration values available on MSDN website in attempt to pinpoint the error.
Unfortunately I was unable to achieve this task. What I'm looking for is to have a Word document with the following text :
List of something :
Number one
Number two
...
Thank you all for your help
The problem comes from Access VBA not recognizing ListGalleries when late-binding is used. If that is fully qualified with the Word.Application object, the code works for me:
Set GBL_objWord = CreateObject("Word.Application")
GBL_objWord.Visible = True
GBL_objWord.Activate
Set GBL_objDoc = GBL_objWord.Documents.Add
GBL_objDoc.Activate
'Traitement
GBL_objWord.Selection.TypeText Text:="List of something :"
GBL_objWord.Selection.TypeParagraph
GBL_objWord.Selection.TypeText Text:="Number one"
GBL_objWord.Selection.Range.ListFormat.ApplyListTemplate _
ListTemplate:=GBL_objWord.ListGalleries(2).ListTemplates(1), _
ContinuePreviousList:=True, ApplyTo:=0, DefaultListBehavior:=2
GBL_objWord.Selection.TypeParagraph
GBL_objWord.Selection.TypeText Text:="Number two"
I've done some researches and here is what I found.
First, I forgot to put the variable declaration in my first post. Here is what I missed :
Option explicit
Public GBL_objWord As Object
Public GBL_objDoc As Object
Also, I did not mentionned that the Microsoft Word 16.0 Object Library, among others, was selected in Tools/References.
Next, I've learned the difference between Early-binding and Late-binding. My variables should have been :
Public GBL_objWord As Word.Application
Public GBL_objDoc As Word.Document
This change has not corrected the error but when I run very long procedures in which the result is a 7 pages Word Document, the process seems to have speeded-up quite a bit.
Now that I have access to all the Word functions, I tried
GBL_objWord.Selection.Range.ListFormat.ApplyNumberDefault
And it works perfectly!!!
Even if none of your answer was the good one, I would like to thank you both for your help and your guidance as these answers have sent me on the right track.
Thank you,
Sincerely
I was having some errors too and here's how I fixed it:
You need to first construct the object after you've constructed your word application like this
Set GBL_objWord = CreateObject("Word.Application")
GBL_objWord.Visible = True
GBL_objWord.Activate
Set GBL_objDoc = GBL_objWord.Documents.Add
GBL_objDoc.Activate
Dim formatter As Object
Set formatter = GBL_objWord.ListGalleries(2).ListTemplates(1)
Then replace the list template with the object and this section should no longer return an error:
GBL_objWord.Selection.Range.ListFormat.ApplyListTemplate _
ListTemplate:=formatter, _
ContinuePreviousList:=True, ApplyTo:=0, DefaultListBehavior:=2

VBA "Compile Error: Label not defined"

I have a VBA macro which gave me that error message.
Sub Function1()
' Give the user macro options based on how fast or slow the computer
' is using advanced conditional compiling
vuserChoice = MsgBox("This macro by default treats all numbers as decimals for maximum precision. If you are running this macro on an old computer, you may want to declare numbers as singles, to speed up the macro.")
MsgBox ("Decimal: recommended for maximum precision. Also slower." & vbNewLine & "Long: not recommended. Rounds to nearest integer." & vbNewLine & "Single: not recommended. A lightweight double." & vbNewLine & "Integer: not recommended. Quick and low-precision.")
If vuserChoice = "Decimal" Or "decimal" Then
GoTo FunctionDecimal
ElseIf vuserChoice = "Double" Or "double" Then
GoTo FunctionDouble
ElseIf vuserChoice = "Single" Or "single" Then
GoTo FunctionSingle
ElseIf vuserChoice = "Long" Or "long" Then
GoTo FunctionLong
Else
GoTo FunctionNotValidVarType
End If
' MEeff = measure of efflux due to crudely purified HDL in scintillation
MsgBox "For additional information about this macro:" & vbNewLine & "1. Go to tab Developer" & vbNewLine & "2. Select Visual Basic or Macro." & vbNewLine & "See the comments or MsgBoxes (message boxes)."
End Sub
The offending line is:
GoTo FunctionNotValidVarType
I have the function FunctionNotValidVarType below this code. I have it as:
Public Sub FunctionNotValidVarType()
MsgBox "VarType " & VarType & " is not supported. Please check spelling."
End Sub
What do I need to do to let the first function recognize FunctionNotValidVarType? Thanks.
GoTo will try and transfer the code execution to a different position in the current Subroutine with the given label.
Specifically, GoTo FunctionNotValidVarType will try and execute the line:
FunctionNotValidVarType: 'Do stuff here
which doesn't exist in your current code.
If you want to call another function use Call FunctionNotValidVarType
Remove the word GoTo
GoTo tells the code to jump to a label, you want it to enter a new procedure, not go to a label
Remove Goto from the call to your Sub()
If you really wanted to use a Goto (and you shouldn't), you would
goto Label
Label:
where the label is defined by the trailing colon :
GoTo transitions to a label, a label is defined with :
For example:
Sub G()
On Error GoTo err_handling
a=1/0
Exit Sub
err_handling:
MsgBox "Holy Shit, an error occurred !"
End Sub
To apply GoTo on a Sub you need call it and exit:
Call FunctionNotValidVarType
Exit Sub
(Technically, it is not the same as GoTo if you take the call stack into consideration, but the end result is the same)
GoTo is not considered a good practice, but if that doesn't concern you, take a look also at GoSub at the official docs.

I'd like to make "Any Part of Field" Default (Access VBA)

In a simple Find action dialog box on an MSAccess (2007) form I want to make "Any Part of Field" the default value when the Find and Replace box appears.
The actual default value is "whole field". I though that I could change that with the following line:
DoCmd.FindRecord " ", acAnywhere, , , , , False
But that doesn't make any difference. The rest of the code works fine (associated with a command button). But that above line does nothing whether it's there or not. Please help. I have the following code:
Private Sub AppNAppFind_Click()
On Error GoTo AppNAppFind_Click_Err
On Error Resume Next
Err.Clear
DoCmd.FindRecord " ", acAnywhere, , , , , False
DoCmd.RunCommand acCmdFind
If (MacroError <> 0) Then
Beep
MsgBox MacroError.Description, vbOKOnly, ""
End If
AppNAppFind_Click_Exit:
Exit Sub
AppNAppFind_Click_Err:
MsgBox Error$
Resume AppNAppFind_Click_Exit
I'm using Access 2007.
The following code works for me in Access 2010.
Private Sub myFind_Click()
DoCmd.GoToControl "=[Screen].[PreviousControl].[Name]"
DoCmd.FindRecord " ", acAnywhere, False, acSearchAll, False, acCurrent, False
DoCmd.RunCommand acCmdFind
End Sub
I verified that the Access default for "Find" is "Whole Field" on this machine, yet when I click my button the Find dialog has "Any Part of Field" selected for "Match".
I'm not sure if this is an option in Access 2007, but in Access 2016, you can go to File > Options > Client Settings and look for Default find/replace behaviour and change it from Fast search to General search and it will set the default find settings to Look in: Current document and match in Any Part of Field.
This setting is for the client and will be effective in any access db you open and is persistent.

How do I get a value indicating whether Recordset.Find found anything?

I wrote a program that would add, delete, save and search through records in a database (recordset). However I was doing it in a team. My task was to add the search function to the program, which I have; however I am having problems with adding an error message for when somebody types a word/anything that isn't in the database/recordset.
So for example in the textbox(txtFindBox.Text) if they type "ashbndash" it would come up with an error message. I've commented out my own error message boxes but tell me where I'm going wrong please :(
Here's the code for the find button.
Private Sub cmdFindDB_Click()
adoCustomer.Recordset.MoveFirst
If optLastName.Value = True Then
adoCustomer.Recordset.Find "LastName='" & txtFindBox.Text & "'"
'Else
'MsgBox ("NO RECORD FOUND")
End If
If OptFirstName.Value = True Then
adoCustomer.Recordset.Find "FirstName='" & txtFindBox.Text & "'"
'Else
'MsgBox ("NO RECORD FOUND")
End If
End Sub
edit: Just like to say the problem is that every time I hit the button 'find' it comes up with the message "NO RECORD FOUND" in a msgbox even though it finds the answer, it also comes up with that msgbox if you type in gibberish too.
Thanks for your time
Regards Haroon
Here is an example of how to do what you are trying to do: METHOD: Recordset::Find
Example for your code:
adoCustomer.Recordset.MoveFirst
adoCustomer.Recordset.Find "LastName='" & txtFindBox.Text & "'"
If (adoCustomer.Recordset.BOF = True) OR (adoCustomer.Recordset.EOF = True) Then
MsgBox "Record not found"
End If
Instead of checking that the Value property is true, you need to check EOF and BOF. These stand for End Of File and Beginning Of File. So if either is true, then you are not "inside" the recordset, meaning you did not find anything.