How to get reference to an open Excel spreadsheet from Word? - excel

I have some VBA code that copies stuff from Excel and pastes it into Word. The problem I'm having is how to open the spreadsheet. I can open it using an absolute path reference by
Workbooks.Open "C:\path\filename.xls"
I would prefer to reference the spreadsheet using a relative path reference. I was able to find code for relative path references from an Excel workbook to another one but it doesn't seem to work if you're doing it from Word.

Add a reference to Excel object library, then create an object in code and use that object to control an instance of Excel. Just make sure to avoid things like ActiveWorkbook, just in case.
After adding the reference:
Sub DoStuffWithExcelInWord()
Dim xl As Excel.Application
Dim wkbk As Excel.Workbook
Dim wk As Excel.Worksheet
Set xl = CreateObject("Excel.Application")
Set wkbk = xl.Workbooks.Open("C:\test.csv")
Set wk = wkbk.Sheets(1)
Debug.Print wk.Cells(1, 1).Value
xl.Quit
Set wk = Nothing
Set wkbk = Nothing
Set xl = Nothing
End Sub
You can create something very similar using Excel to automate Word too, if that's more of what you're looking for.

Related

Run Excel VBA in Access

I have been researching this a great deal and I am not finding any leads to how this would work.
I have written code in Excel that I want to run in MS Access. I have pasted the code I wish to run in Access.
All the examples or information I have found is from 2003 Access. I am using 2016 Access.
The Excel code
Public Function getworkbook()
' Get workbook...
Dim ws As Worksheet
Dim Filter As String
Dim targetWorkbook As Workbook, wb As Workbook
Dim Ret As Variant
Application.DisplayAlerts = False
Sheets("DATA").Delete
' Sheets("DATA").Cells.Clear
Set targetWorkbook = Application.ActiveWorkbook
' get the customer workbook
Filter = "Text files (*.xlsx;*.xlsb),*.xlsx;*.xlsb"
Caption = "Please Select an input file "
Ret = Application.GetOpenFilename(Filter, , Caption)
If Ret = False Then Exit Function
Set wb = Workbooks.Open(Ret)
wb.Sheets(1).Move After:=targetWorkbook.Sheets(targetWorkbook.Sheets.Count)
' ActiveSheet.Paste = "DATA"
ActiveSheet.Name = "DATA"
ThisWorkbook.RefreshAll
' Application.Quit
Application.DisplayAlerts = True
End Function
Code I found and tried to use in Access.
Public Function runExcelMacro(wkbookPath)
Dim XL As Object
Set XL = CreateObject("Excel.Application")
With XL
.Visible = False
.displayalerts = False
.Workbooks.Open wkbookPath
'Write your Excel formatting, the line below is an example
.Range("C2").value = "=1+2"
.ActiveWorkbook.Close (True)
.Quit
End With
Set XL = Nothing
End Function
There are few concepts you need to deal with first.
Library references and scope
Your original code was written in Excel. Therefore, in that VBA project, it has Excel object referenced. In your Access VBA project, that is not referenced. You can compare this by looking at Tools -> References.
That brings us to the concept of "early-binding" and "late-binding". When you type in things like Range., you get VBA's intellisense to tell you what you can do with a Range or whatever. But in Access, you don't have Excel object library referenced by default. Therefore, Range. will not yield intellisense and you can't run the code because Access does not have Range in its object model and your VBA project mostly likely don't have a reference that has it.
Therefore, your code need to be adjusted to run late-bound if you do not want to add reference to Excel object model, and you most likely do want that anyway.
Unqualified Reference
Your original Excel code contains unqualified references to various global objects that are available in Excel's object model.
Application.DisplayAlerts = False
...
Sheets("DATA").Delete
...
Set wb = Workbooks.Open(Ret)
...
Those won't necessarily work consistently in VBA projects hosted by other hosts other than Excel and most certainly won't work in late-bound code. Furthermore, if you elect to add a reference to Excel's object model, you still end up leaking Excel instance which can cause ghost instances because unqualified references to the global objects will implicitly create an Excel instance that you can't interact and that can also cause other runtime error down the path. To make your code more late-bindable, you need something like:
Set ExcelApp = CreateObject("Excel.Application")
ExcelApp.DisplayAlerts = False
...
Set MyBook = ExcelApp.Workbooks("Whatever")
MyBook.Sheets("DATA").Delete
...
Set wb = ExcelApp.Workbooks.Open(Ret)
...
Note how all global objects that you could have accessed in a Excel-hosted context now have to be a variable on its own. Furthermore, you won't have access to ThisWorkbook or even Sheet1 in other VBA projects because Excel is no longer the host. You must adjust accordingly.
Switching between early-binding & late-binding
Early-bound code makes it much easier for you to develop since you get full intelisense and object browser helping you write the code. However, when referencing other object models, you might want to distribute your VBA code using late-binding to avoid versioning problems and broken references. But you can have best from both worlds:
#Const EarlyBind = 1
#If EarlyBind Then
Dim ExcelApp As Excel.Application
#Else
Dim ExcelApp As Object
#End If
Set ExcelApp = CreateObject("Excel.Application")
This illustrates the use of conditional compilation argument to allow you to have ExcelApp variable that can be either Excel.Application (aka early-bound) vs. Object (aka late-bound). To change, you simply change the Const LateBind line between 0 or 1.
First, to clear up terminology:
VBA is a separate language and not tied to any MS Office application. Under Tools\References, you will see Visual Basic for Applications is usually the first checked object. What differs between running VBA inside Excel, Access, Word, Outlook, etc. is the default access to their object library. Specifically:
Only Excel sees Workbook, Worksheet, etc. without defining its source
Only Access sees Forms, Reports, etc. without defining its source
Only Word sees Documents, Paragraphs, etc. without defining its source
When running a foreign object library inside an application, such as MS Access accessing Excel objects, you must define and initialize the foreign objects via reference either with early or late binding:
' EARLY BINDING, REQUIRES EXCEL OFFICE LIBRARY UNDER REFERENCES
Dim xlApp As Excel.Application
Dim wb As Excel.Workbook
Dim ws As Excel.Worksheet
Set xlApp = New Excel.Application
Set wb = xlApp.Workbooks.Open(...)
Set ws = wb.Worksheets(1)
' LATE BINDING, DOES NOT REQUIRE EXCEL OFFICE LIBRARY UNDER REFERENCES
Dim xlApp As Object, wb As Object, ws As Object
Set xlApp = CreateObject("Excel.Application")
Set wb = xlApp.Workbooks.Open(...)
Set ws = wb.Worksheets(1)
With that said, simply keep original code nearly intact but change definitions and initializations. Notably, all Application calls now point to Excel.Application object and not to be confused with Access' application. Plus, best practices of avoiding .Select/ .Activate/ Selection/ ActiveCell/ ActiveSheet/ ActiveWorkbook.
Public Function getworkbook()
' Get workbook...
Dim xlApp As Object, targetWorkbook As Object, wb As Object, ws As Object
Dim Filter As String, Caption As String
Dim Ret As Variant
Set xlApp = CreateObject("Excel.Application")
Set targetWorkbook = xlApp.Workbooks.Open("C:\Path\To\Workbook.xlsx")
xlApp.DisplayAlerts = False
targetWorkbook.Sheets("DATA").Delete
' get the customer workbook
Filter = "Text files (*.xlsx;*.xlsb),*.xlsx;*.xlsb"
Caption = "Please Select an input file "
Ret = xlApp.GetOpenFilename(Filter, , Caption)
If Ret = False Then Exit Function
Set wb = xlApp.Workbooks.Open(Ret)
wb.Sheets(1).Move After:=targetWorkbook.Sheets(targetWorkbook.Sheets.Count)
Set ws = targetWorkbook.Worksheets(targetWorkbook.Sheets.Count)
ws.Name = "DATA"
targetWorkbook.RefreshAll
xlApp.DisplayAlerts = True
xlApp.Visible = True ' LAUNCH EXCEL APP TO SCREEN
' xlApp.Quit
' RELEASE RESOURCEES
Set ws = Nothing: Set wb = Nothing: Set targetWorkbook = Nothing: Set xlApp = Nothing
End Function
By the way, above can be run in any MS Office application as no object of the parent application (here being MS Access) is used!

Using VBScript to Change Excel View to Page Layout

I need to use VBScript to change all of the sheets in an excel workbook to Page Layout View instead of the default view. However, I cannot figure out how to do that in VBS. With VBA, the code I've been using (with a while loop to go over each sheet) is
With ActiveWindow
.View = xlPageLayoutView
End With
which serves my purposes fine. But I need to do this in VBS. I think it has something to do with the Application object, though I'm not sure. Any help would be appreciated.
Edit: here's a sample of the code I've written with declarations and things. It's basically iterating over a number of sheets in a workbook and setting them all (or trying to) to Page Layout view. Missing from this segment is the sub where I populate the workbook with new sheets matching the entries from Names().
Dim destFile, objWorkbook
Set destFile = CreateObject("Excel.Application")
Set objWorkbook = destFile.Workbooks.Add()
objWorkBook.SaveAs(strPath)
Sub OverNames()
For i = 1 to 9
SetPagelayout(i)
Next
End Sub
Sub SetPageLayout(hNum)
Dim houseSheet, sheetName
'retrieves sheet name from array Names()
sheetName = Names(hNum, 0)
Set houseSheet = destFile.Worksheets(sheetName)
houseSheet.Window.View = xlPageLayoutView
End Sub
VBA already has excel and the workbook loaded. With VBS, you need to create an excel object and open your workbook with it. Also, VBA has static variables defined for excel settings, which you will have to define yourself in VBS.
Dim objExcel
Dim excelPath
Dim xlPageLayoutView=3 ' https://msdn.microsoft.com/en-us/library/office/ff838200.aspx
excelPath = "C:\scripts\servers.xlsx"
objExcel.DisplayAlerts = 0
Set objExcel = CreateObject("Excel.Application")
In order to change the state of a window, you have to access the window object. In excel there are Workbooks, which contain collections of Worksheets and Windows. The application also contains a collection of all windows in all worksheets. In the workbook window collection, the active window is always accessed through index 1.
Set currentWorkBook = objExcel.ActiveWorkbook
Set currentWorkSheet = currentWorkBook.Worksheets("Sheet Name Here")
currentWorkSheet.Activate
Set currentWindow = currentWorkBook.Windows(1)
currentWindow.View = xlPageLayoutView

Retrieve Cell Value from another workbook using a reference cell location

So I've done some digging and found the pieces I think are necessary to achieve my goal but I am having trouble putting the pieces together in the correct order. I have achieved referencing a cell value from a different workbook using its file location and copying that value to my active workbook.
My problem comes when I want that file location to come from a reference cell within my active workbook, NOT from a file location embedded in the code itself. The idea is that other users can simply copy their file location to the reference cell and the macro pulls the necessary values from that file.
Here is my code that works using with the location coming from the code itself
Private Sub CommandButton1_Click()
Dim XL As Excel.Application
Dim WBK As Excel.Workbook
Set XL = CreateObject("Excel.Application")
Set WBK = XL.Workbooks.Open("R:\Branches\XXX\XXX\XXX\MASTER LOAN MEMO 8-14.xlsx")
ActiveWorkbook.Sheets("Sheet1").Range("H3") = WBK.Sheets("Master Input").Range("B58").Value
WBK.Close
Set XL = Nothing
End Sub
Here is my modified version to try to accomplish what I explained earlier:
Private Sub CommandButton2_Click()
Dim XL As Excel.Application
Dim WBK As Excel.Workbook
Dim Location As String
Location = ActiveWorkbook.Sheets("Sheet2").Range("B2").Value
Set XL = CreateObject("Excel.Application")
Set WBK = XL.Workbooks.Open(Location)
ActiveWorkbook.Sheets("Sheet1").Range("H3") = WBK.Sheets("Master Input").Range("B58").Value
WBK.Close
Set XL = Nothing
End Sub
I'm getting a Runtime Error 1004 stating the file location cannot be found. Any help would be much appreciated.
I can't replicate the problem EXCEPT when I use a deliberately bad file location (i.e., a location that doesn't exist in my environment). Since it looks like your directory structure can be many levels deep, and since you're referencing a drive letter instead of a server name, perhaps the location is mis-spelled? Try moving the file you're looking for to your C drive, change the value in Sheet2.B2 accordingly and test that.
BTW, I'm not having problems copying values that have use various functions, ampersands and concatenations.

Excel VBA Run-time error '424': Object Required when trying to copy TextBox

I'm attempting to copy the contents of a text box from one workbook to another. I have no problem copying cell values from the first workbook to the 2nd, but I get an object required error when I attempt to copy the text box. This macro is being run from the workbook containing the data I want copied. Using Excel 2007 Code:
Sub UploadData()
Dim xlo As New Excel.Application
Dim xlw As New Excel.Workbook
Set xlw = xlo.Workbooks.Open("c:\myworkbook.xlsx")
xlo.Worksheets(1).Cells(2, 1) = Range("d4").Value 'Copy cell content (this works fine)
xlo.Worksheets(1).Cells(2, 2) = TextBox1.Text 'This gives me the object required error
xlw.Save
xlw.Close
Set xlo = Nothing
Set xlw = Nothing
End Sub
Thanks for any help.
The problem with your macro is that once you have opened your destination Workbook (xlw in your code sample), it is set as the ActiveWorkbook object and you get an error because TextBox1 doesn't exist in that specific Workbook. To resolve this issue, you could define a reference object to your actual Workbook before opening the other one.
Sub UploadData()
Dim xlo As New Excel.Application
Dim xlw As New Excel.Workbook
Dim myWb as Excel.Workbook
Set myWb = ActiveWorkbook
Set xlw = xlo.Workbooks.Open("c:\myworkbook.xlsx")
xlo.Worksheets(1).Cells(2, 1) = myWb.ActiveSheet.Range("d4").Value
xlo.Worksheets(1).Cells(2, 2) = myWb.ActiveSheet.TextBox1.Text
xlw.Save
xlw.Close
Set xlo = Nothing
Set xlw = Nothing
End Sub
If you prefer, you could also use myWb.Activate to put back your main Workbook as active. It will also work if you do it with a Worksheet object. Using one or another mostly depends on what you want to do (if there are multiple sheets, etc.).
I think the reason that this is happening could be because TextBox1 is scoping to the VBA module and its associated sheet, while Range is scoping to the "Active Sheet".
EDIT
It looks like you may be able to use the GetObject function to pull the textbox from the workbook.
The issue is with this line
xlo.Worksheets(1).Cells(2, 2) = TextBox1.Text
You have the textbox defined at some other location which you are not using here. Excel is unable to find the textbox object in the current sheet while this textbox was defined in xlw.
Hence replace this with
xlo.Worksheets(1).Cells(2, 2) = worksheets("xlw").TextBox1.Text

Populate Word Combobox with Excel data through VBA

I'm new to VBA, so I'm struggling with this for a couple of days now.
I have a combobox in Word with contacts, I also have an excel file(contacts.xls) with one column (names of the all the contacts). When I open the Word-document the Macro has to fill in the combobox with all the names from the excel file.
Is it possible to send me a working example of this for word 2007? Seems quite simple, but just can't get this to work...
Thanks in advance!
If you intend on reading from an Excel file in Word you are going to have to open it. It will use code like this:
Dim oExcel As Object
Dim oBook As Object
Dim oSheet As Object
'Start a new workbook in Excel
Set oExcel = CreateObject("Excel.Application")
Set oBook = oExcel.Workbooks.Open("FileName.xlsx")
You will also probably want to go to Tools->References in the VB project and find whatever Excel library is on your machine (and check it of course). There are ways around this if needed, but it is easier.
You then can read the values from the workbook:
oBook.Worksheets(1).cells(1,1)
I'm not totally sure what the syntax to get it into the combo box is. Look up "combobox object members" in the vbe in word. There will be a list property, or something like that.
Sorry, I'm on a linux machine right now, so I can't debug exact code for you.
I have more full code for you now:
Option Explicit
Sub TestDropDownFromExcel()
Dim counter As Long
Dim xlApp As Excel.Application
Dim xlBook As Workbook
Dim oCC As ContentControl
Set oCC = ActiveDocument.ContentControls(1)
Set xlApp = CreateObject("Excel.Application")
Set xlBook = xlApp.Workbooks.Open("C:\Path\To\MyFile.xlsx")
If xlBook Is Nothing Then
Exit Sub
End If
oCC.DropdownListEntries.Clear
For counter = 1 To 10
oCC.DropdownListEntries.Add Text:=xlBook.Worksheets(1).Cells(counter, 1), Value:=CStr(counter)
Next counter
xlApp.Visible = True
Set xlBook = Nothing
Set xlApp = Nothing
End Sub
Be aware that there is very little error checking going on here. Also, rather than the call to .Visible at the end, you can simply call .Close if you do not want the user to see it (for the final project, this is probably preferable. The deferencing (= Nothing) is good practice to have, but VBA cleans up automatically at the end of execution. Obviously I am assuming tyou want the first dropdown (ContentCOntrols(1)) but this may not be true.

Resources