Searching Heading Styles in VB6 for Unique String - vba

I'm a third year software design student. I'm currently in the middle of my work placement. I had been asked to create a tool to parse word documents for relevant tabular data and export it to ms excel. I had never had any dealings with VB but based on the research I carried out I decided that was the route to take. Anyway I managed to execute this successfully. Now, however, I have been asked to expand the program to parse paragraphs also. The documents are broken down into chapters. Each chapter heading is in 'h2' style, my idea is to try to search all text in 'h2' style for a unique string and if found, which should be the required heading, then process the text underneath.
Can this be done?? If so, can you please let me know how, this has been a steep learning curve, and I was delighted with what I had achieved, now, I'm stuck dead. I have the methodology, it's finding the correct way to implement it. This will also allow me to create a search form which I intend to integrate to allow the user search for the chapter they want to parse...
If anyone can help me get out of this hole I would greatly appreciate it.

Take your Pick
VBA WORD CODE (Place this in a module)
Option Explicit
Sub VBASample()
Dim para As Paragraph
Dim strParaText As String
Dim searchString As String
searchString = "Sample"
For Each para In ActiveDocument.Paragraphs
If para.Style = "Heading 2" Then
strParaText = para.Range.Text
If InStr(1, strParaText, searchString, vbTextCompare) Then
'~~> You code here if the text is found
MsgBox "Found"
End If
End If
Next para
End Sub
VB6 CODE
Option Explicit
'~~> Using Late Binding so no reference to Word object is required.
Sub VB6Sample()
Dim oWordApp As Object, oWordDoc As Object, oWordPara As Object
Dim FlName As String, strParaText As String, searchString As String
'~> File Name where you want to check the paragraphs
FlName = "C:\Documents and Settings\Siddharth Rout\Desktop\Sample.doc"
'~~> Establish an Word application object
On Error Resume Next
Set oWordApp = GetObject(, "Word.Application")
If Err.Number <> 0 Then
Set oWordApp = CreateObject("Word.Application")
End If
Err.Clear
On Error GoTo 0
oWordApp.Visible = True
Set oWordDoc = oWordApp.Documents.Open(FlName)
'~~> String that you want to search
searchString = "Sample"
For Each oWordPara In oWordDoc.Paragraphs
If oWordPara.Style = "Heading 2" Then
strParaText = oWordPara.Range.Text
If InStr(1, strParaText, searchString, vbTextCompare) Then
'~~> You code here if the text is found
MsgBox "Found"
End If
End If
Next oWordPara
End Sub

Related

Search currently viewed email for a specific phrase, fetch a string to copy to clipboard

I get assignments in emails that come to a shared Outlook mailbox.
In a typical email there are multiple strings and variables regarding a client, including their name, date and ID with a hyphen that I also want to get rid of.
There are two types of IDs. Both consist of 8 numbers and a hyphen, e.g. 1234567-8 and 123456-78. Sometimes there is a character in front of the number so I believe storing data in string is a must. I want to make several copies of the macro for each type of data. I want it all in a simple string form as I want to copy it to clipboard and paste elsewhere and have no need to process it further.
The code below does all I want except it stores the data in variables instead of string and does not remove the hyphen.
Code courtesy of vbaexpress' gmayor.
Option Explicit
Sub GetCustomer()
Dim olItem As Outlook.MailItem
Dim olInsp As Outlook.Inspector
Dim dCust As DataObject
Dim wdDoc As Object
Dim oRng As Object
Dim sCustomer As String
Dim bFound As Boolean
On Error GoTo lbl_Exit
Set olItem = ActiveExplorer.Selection.Item(1)
With olItem
Set olInsp = .GetInspector
Set wdDoc = olInsp.WordEditor
Set oRng = wdDoc.Range
With oRng.Find
Do While .Execute(findText:="Customer #:[ 0-9]{2,}", MatchWildcards:=True)
sCustomer = Trim(Split(oRng.Text, Chr(58))(1))
bFound = True
Set dCust = New DataObject
dCust.SetText sCustomer
dCust.PutInClipboard
MsgBox "Customer number '" & sCustomer & "' copied to clipboard"
Exit Do
Loop
End With
If Not bFound Then MsgBox "Customer number not found"
End With
lbl_Exit:
Set olItem = Nothing
Set olInsp = Nothing
Set wdDoc = Nothing
Set oRng = Nothing
Set dCust = Nothing
Exit Sub
End Sub
I want to search the currently previewed email (if that is possible), without actually opening it in another separate window, for a phrase like
"Customer ID: 123456-78"
and reformat the last part by simply removing the hyphen and disregarding the first part
"Customer ID: "
(there is a giant space between the Customer ID and the number).
I also want to reformat the date from 11.22.2019 to 2019-22-11 and also copy it to clipboard.
Searches based on wildcards are limited to what wildcards can provide, which is better than nothing, but still not very much.
Outlook uses Word functions for this, so that the VBA documentation for Word applies. Applicable wildcards themselves are can be seen using the "Special" button in the "Find" dialog (F4 in Outlook), after "use wildcards" has been checked.
To my knowledge there is no concept of "optional" parts in wildcard searches, which means you need to try more than one wildcard pattern to cover your "sometimes there is a letter in front" case.
So the general approach, based this knowledge and on your sample code, would be
Pick the currently selected MailItem in the ActiveExplorer
For each predefined wildcard pattern
reset the search range to the whole email
execute wildcard search
as long as there are search hits
display result, let user pick or cancel the search
This way multiple patterns can be defined and you have a chance to continue to the next hit if the first hit is a false positive.
I found the pattern [0-9-]{8;9} plus MatchWholeWord to work reasonably well (blocks of digits and dashes, between 8 or 9 characters long), but real life data often has surprises. You will probably need to add more patterns. Watch out: for me, Outlook wants ; instead of ,. This might be dependent on the system locale, I'm not sure.
Also I'm not a fan of a "silent" On Error Resume. If there is an error, I prefer to see an error actual message. If there is a condition that can be checked in order to prevent an error, I prefer to check for this condition explicitly. This makes the code more robust and debugging easier. My Sub does not contain an On Error line for that reason.
In code, this would look like this:
Sub GetCustomer()
Dim olItem As Outlook.MailItem
Dim oRng As Object
Dim sCustomer As String
Dim patterns As Variant, pattern As Variant
Dim answer As VbMsgBoxResult
' bail out if the preconditions are not right
If ActiveExplorer.Selection.Count = 0 Then Exit Sub
If Not (TypeOf ActiveExplorer.Selection.item(1) Is MailItem) Then Exit Sub
Set olItem = ActiveExplorer.Selection.item(1)
Set oRng = olItem.GetInspector.WordEditor.Range
' add more wildcard patterns in descending order of likelyhood
patterns = Array("[0-9-]{8;9}", "[A-Z][0-9-]{8;9}")
For Each pattern In patterns
oRng.WholeStory
While oRng.Find.Execute(findText:=pattern, MatchWildcards:=True, MatchWholeWord:=True)
answer = MsgBox(oRng.Text, vbYesNoCancel + vbQuestion, "Customer Number")
If answer = vbYes Then
With New DataObject
.SetText oRng.Text
.PutInClipboard
End With
Exit For
ElseIf answer = vbCancel Then
Exit For
End If
Wend
Next pattern
End Sub
Setting variables to Nothing at the end of the function is superfluous.

VBA to open the first link in the Outlook email then the next link

Please advise me on parts of this or the whole thing if possible. I basically have an email every morning with 5-8 links to reports (on Sharepoint) and have to click each one, which then opens an excel document with the report, click refresh all, save then go back to outlook and click the next link. Is there a way to open the first link in Outlook, go to excel refresh all, save, then go back to Outlook and open the next link and repeat until all links have been pressed in VBA? Any and all help is greatly appreciated, Thank you.
Function GetCurrentItem() As Object
Dim objApp As Outlook.Application
Set objApp = Application
On Error Resume Next
Select Case TypeName(objApp.ActiveWindow)
Case "Explorer"
Set GetCurrentItem = objApp.ActiveExplorer.Selection.Item(1)
Case "Inspector"
Set GetCurrentItem = objApp.ActiveInspector.CurrentItem
End Select
Set objApp = Nothing
End Function
Sub Hyperlink(itm As MailItem)
Dim bodyString As String
Dim bodyStringSplitLine
Dim bodyStringSplitWord
Dim splitLine
Dim splitWord
bodyString = itm.Body
bodyStringSplitLine = Split(bodyString, vbCrLf)
For Each splitLine In bodyStringSplitLine
bodyStringSplitWord = Split(splitLine, " ")
For Each splitWord In bodyStringSplitWord
splitWord.Hyperlink.Select
Next
Next
Set itm = Nothing
End Sub
Sub test()
Dim currItem As MailItem
Set currItem = GetCurrentItem
Hyperlink currItem
End Sub
This is what I have come up with so far. Definitely contains errors. I just run the sub test() in the end.
There is a .Follow in Word.
Sub Hyperlink(itm As mailitem)
Dim oDoc As Object
Dim h As Hyperlink
If itm.GetInspector.EditorType = olEditorWord Then
Set oDoc = itm.GetInspector.WordEditor
For Each h In oDoc.Hyperlinks
Debug.Print h.Name
If Right(h.Name, 5) = ".xlsx" Then
h.Follow
End If
Next
End If
Set oDoc = Nothing
End Sub
You can handle the NewMailEx event of the Application class to handle all incoming emails. Then in the event handler you can parse the HTMLBody property value and extract links. Then you can do whatever you need with links - open them in the browser and etc.
I'd recommend starting from the Getting Started with VBA in Outlook 2010 article in MSDN. Then you may find a lot of HOWTO articles in the Concepts (Outlook 2013 developer reference) section.
Your problem is a bit too large, and although not too difficult, it involves multiple object library references (Regular Expressions, Internet Explorer, Excel). It is unlikely you that you will get a full solution to your problem. VBA is a really powerful and cool scripting language and not too difficult to learn. I highly recommend you divide your problem into smaller tasks, and try to work each task separately and come back with more specific questions.

VBA code to read a word doc

Is there any way to create a VBA code to read a word document via audio? as if the computer was reading the whatever is on the document. (of course all text).
I found this searching on google. http://vbadud.blogspot.com/2010/06/vba-how-to-convert-text-file-to-speech.html
Sub Speech_FromFile_Example()
Dim oVoice As SpVoice
Voice Object Dim oVoiceFile As SpFileStream
File Stream Object Dim sFile As String
File Name Set oVoice = New SpVoice
Set oVoiceFile = New SpFileStream
oVoice.Speak "This is an example for reading out a file"
sFile = "C:\ShasurData\ForBlogger\SpeechSample.txt"
oVoiceFile.Open sFile
oVoice.SpeakStream oVoiceFile
End Sub
The code requires Microsoft Speech Object Library
VBA macro for Word:
Dim speech as SpVoice
Sub SpeakText()
On Error Resume Next
Set speech = New SpVoice
If Len(Selection.Text) > 1 Then 'speak selection
speech.Speak Selection.Text
SVSFlagsAsync + SVSFPurgeBeforeSpeak
Else 'speak whole document
speech.Speak ActiveDocument.Range(0, ActiveDocument.Characters.Count).Text
SVSFlagsAsync + SVSFPurgeBeforeSpeak
End If
Do
DoEvents
Loop Until speech.WaitUntilDone(10)
Set speech = Nothing
End Sub
Sub StopSpeaking()
'Based on a macro by Mathew Heikkila
'used to interrupt any running speech to text
On Error Resume Next
speech.Speak vbNullString, SVSFPurgeBeforeSpeak
Set speech = Nothing
End Sub
Be careful if you are using Windows 10 - I had two libraries with the same name "Microsoft Speech Object Library" - make sure you select the one which points to Windows/system32/Speech/Common/sapi.dll

Word.GetAddress in Excel / The "Check Names" dialog displays in background

I am using the Word.GetAddress function in an Excel document to retrieve the first & last names of someone if he is in the GAL.
From what I have understand, the only way to have the built-in "Check Names" dialog is to use the Word.GetAddress function.
When the name entered matches more than entry, the "Check Names" displays but in the background. I have to Alt+Tab to get it.
I have tried to use the "Activate" function or the "WindowsState" property to bring it upfront but I am stuck ...
Function getFirstAndLastNames(pName As String) As String
Dim oWord As Word.Application
Dim strAddress As String
On Error GoTo getFirstAndLastNames_Error
'If the search doesn't work, returns the argument
getFirstAndLastNames = pName
'Create the Word object to use GetAddress
Set oWord = CreateObject("Word.Application")
'Search
strAddress = oWord.GetAddress(Name:=pName, CheckNamesDialog:=True, AddressProperties:="<PR_GIVEN_NAME> <PR_SURNAME>")
'If there is a result, the function returns it
If strAddress <> "" Then getFirstAndLastNames = strAddress
'Quit Word
oWord.Quit
Set oWord = Nothing
On Error GoTo 0
Exit Function
getFirstAndLastNames_Error:
MsgBox "Error " & Err.Number & " (" & Err.Description & ") in procedure getFirstAndLastNames of Module Test"
If Not (oWord Is Nothing) Then oWord.Quit
End Function
I have seen this post where there was a similar issue resolved but it doesn't say how ...
Thanks in advance for your help.
The edit to the other post does not state that they found a resolution for the box not coming to the front; only that it could be made visible using alt-tab to bring it to the front.
You have a deadlock in that your Excel code is stopped, waiting for Word and you need an action to have the Word (or rather Outlook) window brought to the front so the user can find it.
You could minimize and restore the Excel window but it is kludge and if there are other windows on screen then it'll be unreliable as the dialog you need will be hidden behind those too.
What you need to do is a bit ugly but will work. Which is to have a helper script or application which you can fire off asynchronously using Application.Run which will start the app and continue to execute in VBA. That script/app will wait for a little while (to give VBA time to run the GetAddress line) and then bring that dialog to the front using the windows API.
Most scripting or programming languages will be good enough and which one you choose depends on what you are most comfortable with. StackOverflow has an example for Powershell that you can adjust to your needs.
Finally, I found an article on the support of Microsoft.com that explain how to use CheckSpelling outside of Word. I adapted it to my use.
The code position the Word window off the screen but the dialogs appears in the foreground.
Function getFirstAndLastNames(pName As String) As String
Dim oWord As Word.Application
Dim strAddress As String
Dim lOrigTop As Long
Dim lOrigState As Byte
'Display the "Check names" dialog (available only with Word.Application ...)
On Error GoTo getFirstAndLastNames_Error
'If the search doesn't work, returns the argument
getFirstAndLastNames = pName
'Create the Word object to use GetAddress
Set oWord = CreateObject("Word.Application")
'Position Word off screen to avoid having document visible
'http://support.microsoft.com/kb/243844/en-us
lOrigTop = oWord.Top
lOrigState = oWord.WindowState
oWord.Top = -3000
oWord.Visible = True
oWord.WindowState = wdWindowStateMinimize
oWord.Activate
'Search
strAddress = oWord.GetAddress(Name:=pName, CheckNamesDialog:=True, AddressProperties:="<PR_GIVEN_NAME> <PR_SURNAME>")
'If there is a result, the function returns it
If strAddress <> "" Then getFirstAndLastNames = strAddress
'Reset the position and state of Word and quit the application
oWord.Visible = False
oWord.Top = lOrigTop
oWord.WindowState = lOrigState
oWord.Quit
Set oWord = Nothing
On Error GoTo 0
Exit Function
getFirstAndLastNames_Error:
MsgBox "Error " & Err.Number & " (" & Err.Description & ") in procedure getFirstAndLastNames of Module Test"
'If an error raised, Reset the position and state of Word and quit the application
If Not (oWord Is Nothing) Then
oWord.Top = lOrigTop
oWord.WindowState = lOrigState
oWord.Quit
End If
End Function

MS Word's grammar checker launches with VBA delete all line breaks in MS Access form

I have this code in VBA which launches MS Word spelling and grammar checker after I exit text box of a ms Access form.
After the check is run, and the text sent back to the form, all the line breaks of my text are gone. My data look like a single paragraph instead of having nice formatting.
This happen on the Access side as the .doc that I see just at the end of the spelling check still has the line breaks.
Thanks a lot for your help!
Option Compare Database
Private Sub Description_Exit(Cancel As Integer)
Call SpellIt(Description)
End Sub
Public Function SpellIt(ctrl As Control)
Dim wdApp As Word.Application
Dim wdDoc As Word.Document
On Error GoTo SpellIt_Err
Set wdApp = New Word.Application
wdApp.Visible = True
wdApp.Activate
If Not IsNull(ctrl) Then
Set wdDoc = wdApp.Documents.Add
wdApp.Selection.Text = ctrl
wdApp.Dialogs(wdDialogToolsSpellingAndGrammar).Show
If Len(wdApp.Selection.Text) <> 1 Then
ctrl = wdApp.Selection.Text
Else
wdDoc.Close wdDoNotSaveChanges
wdApp.Quit
Set wdApp = Nothing
Exit Function
End If
wdDoc.Close wdDoNotSaveChanges
End If
wdApp.Quit
Set wdApp = Nothing
MsgBox "Spelling and Grammar Check Complete.", vbInformation, "Microsoft Word Spelling And Grammar:"
Exit Function
SpellIt_Err:
Err.Clear
ctrl.Undo
MsgBox "We encountered an error in it's conversation with Microsoft Word regarding your comment." & vbCrLf & _
"As a precaution, any changes made within the grammar and spelling dialog box have not been retained.", _
vbCritical, "Spelling and Grammar Check NOT Complete:"
End Function
Looks like MS Word is using different linebreak characters than Access textbox controls. You can revert the characters back to their original used in Access after spellcheck by replacing this line:
ctrl = wdApp.Selection.Text
with:
ctrl = Replace(wdApp.Selection.Text, vbCr, vbCrLf)