How to unlock Excel file after opening it trought VBA Word - excel

I'm working on a VBA Word macro to create a personalized agenda. This is done trought the steps:
From VBA Word, open an Excel Spreadsheet
Copy a pre-defined range from the spreadsheet, into an array in Word
Create new Word document, inserting every row from the array on an individual page.
Thanks to the help I found here and on a few websites, I wrote a piece of code that executes these three steps.
After running the code and even closing Word, I get a message everytime I open the spreadsheet in Excel. The message is:
File.xlsm is blocked for edition by 'User' ; (my user)
I think it might be related to:
Calling Excel from VBA Word: I call Excel by creating an ApplicationObject (app_Excel) and using CreateObject method; to finish the application, I used Set app_Excel = Nothing, and then app_Excel.Quit, as seen in the code; Or
Opening a spreadsheet from VBA Word: In the first attempts I was using Excel.Workbooks.Open(,,,ReadOnly = False), then I changed it to True, with the same result.
Sub main()
'Main procedure
Word.Application.ScreenUpdating = False
Dim app_Excel As Excel.Application
Set app_Excel = CreateObject("Excel.Application")
Dim wbk_srce As Workbook
Set wbk_srce = app_Excel.Workbooks.Open("C:\0_portolon\Dias.xlsm", , True)
Dim wsh_srce As Worksheet
Set wsh_srce = wbk_srce.Worksheets(3)
wsh_srce.Activate
cell_1 = CStr("A1")
cell_2 = CStr("D216")
Dim header_range As Excel.Range
wsh_srce.Range(cell_1, cell_2).Select
Set header_range = Excel.Selection
Dim header_array() As Variant
header_array = header_range.Value
Set header_range = Nothing
Set wsh_srce = Nothing
Set sbk_srce = Nothing
app_Excel.Quit
'Creates Word document
Call create_agenda(header_array)
End Sub
How can I unlock the spreadsheet after copying its data into Word?
Thanks in advance,
Tiago

Following the suggestion given in the comments, I changed Set wbk = Nothing to wbk.Close; the code works correctly now.
Thanks.
Sub main()
'Main procedure
Word.Application.ScreenUpdating = False
Dim app_Excel As Excel.Application
Set app_Excel = CreateObject("Excel.Application")
Dim wbk_srce As Workbook
Set wbk_srce = app_Excel.Workbooks.Open("C:\0_portolon\Dias.xlsm", , True)
Dim wsh_srce As Worksheet
Set wsh_srce = wbk_srce.Worksheets(3)
wsh_srce.Activate
cell_1 = CStr("A1")
cell_2 = CStr("D216")
Dim header_range As Excel.Range
wsh_srce.Range(cell_1, cell_2).Select
Set header_range = Excel.Selection
Dim header_array() As Variant
header_array = header_range.Value
Set header_range = Nothing
Set wsh_srce = Nothing
wbk_srce.Close 'change
app_Excel.Quit
'Creates Word document
Call create_agenda(header_array)
End Sub

Related

Using VBA for-loops to edit ActiveX Control label captions

I have a set of word documents that I want to auto-fill for different clients and I am trying to write a VBA application to accomplish that. I have information about the client, such as today's date and their name, stored in an Excel sheet, and I want to copy that information on multiple Word documents with labels on them. The goal is for every new client, the user would only need to update the client information on the Excel sheet to auto-fill the Word documents.
The below code is what I have right now. objDocument represents the Word document that I am trying to fill in and exWb is the Excel sheet in which I am trying to copy client information from. The Excel sheet has cells named TodayDate and ClientName which stores the respective client information. The Word document has ActiveX control labels named TodayDate, ClientName, and ClientName1 which will be filled in with the corresponding information from the Excel Sheet. ClientName and ClientName1 both contain the information from the "ClientName" cell, but because I cannot have 2 labels of the same name in Word, they are named as such.
Dim objDocument As Document
Set objDocument = Documents.Open(strPath)
objDocument.Activate
Dim objExcel As New Excel.Application
Dim exWb As Excel.Workbook
Set exWb = objExcel.Workbooks.Open(selectMasterPath)
On Error Resume Next
objDocument.TodayDate.Caption = exWb.Sheets("Sheet1").Range("TodayDate").Value
On Error Resume Next
objDocument.ClientName.Caption = exWb.Sheets("Sheet1").Range("ClientName").Value
On Error Resume Next
objDocument.ClientName1.Caption = exWb.Sheets("Sheet1").Range("ClientName").Value
On Error Resume Next
To make the code more readable, I would like to format it into a for loop, but I am not sure how to declare a variable that can refer to the names of Word document labels in a for loop. I was thinking of using arrays to store the names of Word labels and Excel cells and loop through the list. I suppose it would look something like this:
Dim objDocument As Document
Set objDocument = Documents.Open(strPath)
objDocument.Activate
Dim objExcel As New Excel.Application
Dim exWb As Excel.Workbook
Set exWb = objExcel.Workbooks.Open(selectMasterPath)
WordLabelList = [TodayDate, ClientName, ClientName1]
ExcelNames = ["TodayDate", "ClientName", "ClientName"]
Dim i as Integer
for i in range(1, length(WordLabelList))
On Error Resume Next
objDocument.WordLabelList[i].Caption = exWb.Sheets("Sheet1").Range(ExcelNames[i]).Value
Next
Or to make it even better, use a dictionary with ExcelNames as the key and WordLabelList as the values so that I do not have to repeat values in the ExcelNames array:
Dim objDocument As Document
Set objDocument = Documents.Open(strPath)
objDocument.Activate
Dim objExcel As New Excel.Application
Dim exWb As Excel.Workbook
Set exWb = objExcel.Workbooks.Open(selectMasterPath)
ClientInfo = {"TodayDate":[TodayDate], "ClientName": [ClientName, ClientName1]}
for info in ClientInfo
for label in ClientInfo[info].value
On Error Resume Next
objDocument.label.Caption = exWb.Sheets("Sheet1").Range(info).Value
Next
Please let me know how I can achieve any of the above with proper VBA syntax or if you have a more efficient suggestion that is better than re-writing multiple lines in original code.
The only thing you're missing seem to be a way to address an ActiveX control by its name? Once you have that your code gets much simpler.
For example:
Sub Tester()
Dim doc As Object, lbl As Object, nm
Set doc = ThisDocument
For Each nm In Array("TodayDate", "ClientName")
Set lbl = DocActiveX(doc, nm) 'get a reference to an embedded ActiveX control
If Not lbl Is Nothing Then
lbl.Caption = "this is - " & nm
Else
Debug.Print "Control '" & nm & "' not found"
End If
Next nm
End Sub
'return a reference to a named ActiveX control in document `doc`
' (or Nothing if not found)
Function DocActiveX(doc As Document, xName) As Object
Dim obj As Object
On Error Resume Next
Set obj = CallByName(doc, xName, VbGet)
On Error GoTo 0
Set DocActiveX = obj
End Function

Pull particular Excel cell value into Word document using Word VBA

I am new to VBA and macros.
I got the repeated task of copy data from Excel and paste it in a particular location in the word document.
For example, my excel sheet has the data like this:
Col1
Col2
ID_1
I'm_One
ID_2
I'm_Two
ID_3
I'm_Three
Now i'm looking for a Word macro
Get text in Word table with cell position 3
Find the same text in Excel Col1
Get the value of Col2 from Excel
Paste the value of Col2 in word table with cell position 10
Repeat the same process for another table in Word document
[Update]
I have tried with multiple code snippets by google search but unable to construct the working macro.
Sub pull_from_Excel2()
'ref: https://www.macworld.com/article/211753/excelwordvisualbasic.html
Dim Month As String
ID_Range = "A2:A6" 'Select this as range like "A2:A16"
Offset_to_fetch = 1 'Select this to fetch comments etc. value starts with
Set xlSheet = GetObject("D:\Excel.xlsx")
'Snippets:
'Debug.Print VarType(xlSheet.Worksheets("Sheet1").Range("A3:A5").Value)
'8204
Dim Cell As Range, rng As Range
Debug.Print VarType(xlSheet.Worksheets("Sheet1").Range(ID_Range).Value2)
Set rng = xlSheet.Worksheets(1).Range(ID_Range)
For Each Cell In rng
Debug.Print Cell.Text
Next Cell
End Sub
I used this url to construct my skeleton code: https://www.macworld.com/article/211753/excelwordvisualbasic.html
When i try to get the values from the range of cells in excel, i got the following error for the code.
Set rng = xlSheet.Worksheets(1).Range(ID_Range).Value2
The above line gives "Object required" error when running.
Set rng = xlSheet.Worksheets(1).Range(ID_Range)
The above line gives "Type Mismatch" error when running.
Notes: For this error, I tried to use for each loop as this is array but the error is showing before executing the for loop.
Kindly assist.
I recommend to use Option Explicit and declare all your varibales properly. This way it is less likely that you end up with unseen errors.
To activate it for all new codes that you add in the future, you can activate it directly in Excel and Word. This is a good practice and will protect you from doing it wrong by notifying you of not declared variables:
In the VBA editor go to Tools › Options › Require Variable Declaration.
This will add Option Explicit to new modules only. In existing modules Option Explicit needs to be added manually as first line.
Further I highly recommend to name your variables according what they contain because otherwise it gets very confusing. You named your variable xlSheet but you load a workbook into it and not a worksheet.
The next issue is that your code is in Word and if you declare rng As Range then this is of type Word.Range and not Excel.Range and those are diffetent types so that is why you get a "Type Mismatch" error.
To solve this you either go in Word VBA to Extras › Refereces … and set a reference to the Excel library so you can declare your variable Dim xlRng As Excel.Range or if you don't set a reference you declare it as Object or Variant like in below example:
' This code is in Word!
Option Explicit
Public Sub pull_from_Excel2()
'declare constants
Const ID_Range As Sting = "A2:A6" 'Select this as range like "A2:A16"
Const Offset_to_fetch As Long = 1 'Select this to fetch comments etc. value starts with
Dim xlWorkbook As Object
Set xlWorkbook = GetObject("D:\Excel.xlsx") 'This expects the Excel to be already open! If not open you need to use CreateObject("Excel.Application")
Dim xlRng As Object
Set xlRng = xlWorkbook.Worksheets(1).Range(ID_Range)
Dim xlCell As Object
For Each xlCell In xlRng
Debug.Print xlCell.Text
Next xlCell
End Sub
Note if your workbook Set xlWorkbook = GetObject("D:\Excel.xlsx") is not open in Excel you need to use CreateObject("Excel.Application") and open it.
Dim xlApp As Object
Set xlApp = CreateObject("Excel.Application")
Dim xlWorkbook As Object
Set xlWorkbook = xlApp.Workbooks.Open(FileName:="D:\Excel.xlsx") 'will open the workbook
xlApp.Visible = True 'make it false to open Excel invisible in the background
'your code here …
'in the end close workbook and Excel (espaciall if you had it invisible!)
xlWorkbook.Close SaveChanges:=False
xlApp.Quit 'close Excel
Option Explicit
Sub UpdateTables()
Const XLSX = "D:\Excel.xlsx"
Dim xlApp, wb, ws
Dim rngSearch, rngFound
Dim iLastRow As Long, n As Integer
' open spreadsheet
'Set xlApp = New Excel.Application
Set xlApp = CreateObject("Excel.Application")
xlApp.Visible = True
Set wb = xlApp.Workbooks.Open(XLSX, 1, 1)
Set ws = wb.Sheets(1)
iLastRow = ws.Cells(ws.Rows.Count, "A").End(-4162).Row 'xlUp
Set rngSearch = ws.Range("A2:A" & iLastRow)
' update tables
Dim doc As Document, tbl As Table, s As String
Set doc = ThisDocument
For Each tbl In doc.Tables
s = tbl.Cell(1, 1).Range.Text
s = Left(s, Len(s) - 2)
Set rngFound = rngSearch.Find(s, LookIn:=-4163, LookAt:=1) ' xlValues, xlWhole
If rngFound Is Nothing Then
MsgBox "'" & s & "' not found in table " & tbl.Title, vbExclamation
Else
tbl.Range.Cells(3).Range.Text = rngFound.Offset(0, 1)
n = n + 1
End If
Next
wb.Close False
xlApp.Quit
MsgBox n & " tables updated", vbInformation
End Sub

Extract Outlook body to Excel VBA

after searching multiple things, and getting errors
How do I upon pressing "f5" in a vba script copy the body of an email into an excel sheet /csv
where every line = a new cell below.
Thanks
Sorry, this is causing me nothing but trouble.
What I have tried so far
http://smallbusiness.chron.com/export-outlook-emails-excel-spreadsheets-41441.html
How to copy Outlook mail message into excel using VBA or Macros
http://www.vbforums.com/showthread.php?415518-RESOLVED-outlook-the-macros-in-this-project-are-disabled
http://www.ozgrid.com/forum/showthread.php?t=181512
and a few more, last year.
This will work for you. we are basically splitting the email body into an array based on a new line. Notice that this will yield blank cells if you had a blank line in the email body.
Public Sub SplitEmail() ' Ensure reference to Word and Excel Object model is set
Dim rpl As Outlook.MailItem
Dim itm As Object
Set itm = GetCurrentItem()
If Not itm Is Nothing Then
Set rpl = itm.Reply
rpl.BodyFormat = olFormatHTML
'rpl.Display
End If
Dim objDoc As Word.Document
Set objDoc = rpl.GetInspector.WordEditor
Dim txt As String
txt = objDoc.Content.text
Dim xlApp As Excel.Application
Set xlApp = CreateObject("Excel.application")
xlApp.Visible = True
Dim wb As Excel.Workbook
Set wb = xlApp.Workbooks.Add
Dim i As Long
For i = LBound(Split(txt, Chr(13)), 1) To UBound(Split(txt, Chr(13)), 1)
wb.Worksheets(1).Range("A" & i + 1).Value = Split(txt, Chr(13))(i)
Next i
End Sub
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
GetCurrentItem.UnRead = False
Set objApp = Nothing
End Function
The Outlook object model doesn't recognize lines in the body. You can try to resize any inspector window in Outlook and see how the body lines are changed.
Anyway, you may try to use the Word object model to get the exact lines. Outlook uses Word as an email editor. The WordEditor property of the Inspector class returns an instance of the Document class which represents the message body. You can read more about all possible ways in the Chapter 17: Working with Item Bodies article.
The How to automate Microsoft Excel from Visual Basic article explains how to automate Excel from any external application.

ms-access vba - read from excel and also update that excel

Created a simple access DB with only 1 form and 1 one button to run code that opens an existing empty excel (with 1 worksheet) and writes "X" in its 1st cell. It does the job but the workbook is hidden and I have to manually unhide it. That is, after the VBA code is executed I open the excel file and it is all grayed out. I have to click the "view" tab and then select the "Unhide" option and all is fine and I can see that the cell was updated as needed. If I take out the VBA line that writes "X" in the excel file, it doesn't hide the workbook. How do I solve the problem of the workbook being hidden?
Windows 7 and Office2013.
Thank you!!!
Here is the code:
Private Sub Command0_Click()
Dim my_xl_app As Object
Dim my_xl_worksheet As Object
Dim my_xl_workbook As Object
Set my_xl_app = CreateObject("Excel.Application")
my_xl_app.UserControl = True
my_xl_app.Visible = False ' yes. I know it's the default
Set my_xl_workbook = GetObject("D:\Dropbox\MASAV\HIYUVIM\AAA.xlsx")
Set my_xl_worksheet = my_xl_workbook.Worksheets(1)
my_xl_worksheet.Cells(1, "A") = "V"
my_xl_workbook.Close SaveChanges:=True
Set my_xl_app = Nothing
Set my_xl_workbook = Nothing
Set my_xl_worksheet = Nothing
End Sub
S o l v e d !!!
Here is the code that works without hiding my entire workbook :
Private Sub Command0_Click()
Dim my_xl_app As Object
Dim my_xl_worksheet As Object
Dim my_xl_workbook As Object
Set my_xl_app = CreateObject("Excel.Application")
Set my_xl_workbook = my_xl_app.Workbooks.Open("D:\Dropbox\MASAV\HIYUVIM\AAA.xlsx")
Set my_xl_worksheet = my_xl_workbook.Worksheets(1)
my_xl_workbook.Sheets(1).Range("A1").Value = "V"
my_xl_workbook.Close SaveChanges:=True
Set my_xl_app = Nothing
End Sub
Got the answer right here in this this forum, in another thread which escaped my eyes...
Thanks a lot to all in this wonderful forum!!!!
Use this:
Workbooks(1).Windows(1).Visible = True

MS Access 2003 - Embedded Excel Spreadsheet on Access form

Let's say I have an embedded Excel Spreadsheet on a Microsoft Access form. I call the object frame
ExcelFrame
and I add a text box on the form called
txtA1
and I add a button on the form called
cmdInsert
I want to type "Hello World" into the text box, click the button and have it appear in the A1 cell on that spreadsheet. What VBA do I use to accomplish this?
Thanks
You can automate Excel, write your value to the worksheet, then update the object frame.
Private Sub cmdInsert_Click()
Dim strPath As String
Dim oExcel As Object
Dim oSheet As Object
Set oExcel = CreateObject("Excel.Application")
oExcel.Visible = True
strPath = Me.ExcelFrame.SourceDoc
'Debug.Print strPath '
oExcel.Workbooks.Open strPath
Set oSheet = oExcel.ActiveSheet
'Debug.Print oSheet.Name '
oSheet.Range("A1").Value = Me.txtA1
oExcel.ActiveWorkbook.Save
oExcel.Quit
Set oSheet = Nothing
Set oExcel = Nothing
'acOLEUpdate action requires Enabled = True '
'and Locked = False '
Me.ExcelFrame.Enabled = True
Me.ExcelFrame.Locked = False
Me.ExcelFrame.Action = acOLEUpdate
Me.txtA1.SetFocus
Me.ExcelFrame.Enabled = False
Me.ExcelFrame.Locked = True
End Sub
Edit: The example was based on an external workbook file which is linked as the source for the form's object frame.
To link a worksheet, choose the "Create from File" radio button, check the "Link" check box, and browse to select the workbook. That's the way I did it with Access 2007. As I recall, it was similar with Access 2003.
It's never too late, right ?
Provide that you have already created the Excel object (as in OP):
Dim wb As Excel.Workbook, ws As Excel.Worksheet
Set wb = Me.ExcelFrame.Object
Set ws = wb.Worksheets(1)
ws.range("a1")= "Hello world"
Note that this code requires a reference to MS Excel in VBA.

Resources