Actually, I'm not a beginner. I know nothing about them, though I do have some programming background.
This is the thing: I have a couple of Word documents and an Excel spreadsheets. The documents need to grab some data from the spreadsheet and then print. There needs to be one document per spreadsheet row, and they need to be printed all together.
I'm not asking for code or anything; I just want to know what's the right tool for the job, and if someone could point me to a tutorial or reference or something.
This is for Office 2003 (or XP, I'm not sure).
EDIT: It seems like there are many ways to do this, so it'd be great if someone listed the pros and cons of each solution. Keep in mind that it's something that will be done many times, and once programmed/recorded/whatever it should be easy to use for someone who is not a programmer.
Javier,
Couldn't find a good tutorial, but something like this should help you get going:
You can enable the developer toolbar, if it's not available from Word options. Then, click on the Visual Basic button and add a procedure or function that can be called from your document or a command button in the Word UI.
Sample showing some super basic Excel integration:
Public Function GetValue()
Dim myExcel As Excel.Application
Dim myWorkbook As Excel.Workbook
Dim myWorkSheet As Excel.Worksheet
Set myExcel = CreateObject("Excel.Application")
Set myWorkbook = myExcel.Workbooks.Open("c:\temp\myworkbook.xlsx")
Set myWorkSheet = myWorkbook.Worksheets(1)
Dim cellValue As String
cellValue = myWorkSheet.Cells(1, 1).Value
GetValue = cellValue
End Function
This will require you add a reference to Excel object library (type library) from the Excel developer IDE.
You can load your Excel spreadsheets via VBA in an ADODB and read the ADODB row by row.
How To Use ADO with Excel Data from Visual Basic or VBA
You can accomplish this with the built-in mail merge facility in Word. There's a walkthrough of how to use it in Word 2003 here
edit: further to the question in the comments, once you have set up the mail merge document, you can save it complete with its link to the data source. This means that when the document is opened again the user just needs to say "Yes" to the choice of data being merged.
The user can (independently) also choose to have the mail merge toolbar displayed. Clicking on the "Merge to new document" button on the Mail Merge toolbar would cause the merged letters to be generated. If the toolbar isn't displayed then they need to go Tools > Letters and Mailings > Mail Merge and use the wizard to complete the job
Related
I am looking at inserting/pasting a range of text data (40 columns) from Excel into bookmarks in Word. Most of the answers are done using Excel VBA, which is so not practical for my use case as I will have the Word document open, add a button that would run this 'import data' macro. I actually already have a button in the doc that inserts images into bookmarks, so that's one more reason I don't want to do it via Excel VBA.
I know this is not great code, but for the lack of definite leads, I'm throwing it here and hope that this gives you an idea of what I'm trying to achieve:
Sub ImportData()
Workbooks.Open ("\Book2.xlsm")
ActiveWindow.WindowState = xlMinimized
ThisWorkbook.Activate
Windows("Book2.xlsm").Activate
Range("A1:AF1").Select
Selection.Copy
Documents("test.docm").Activate
Selection.GoTo What:=wdGoToBookmark, Name:="Overlay_1"
Selection.Paste
End Sub
PS: It would be great if I could sort of 'transpose' the 40 columns into rows as it is pasted in Word.
Here's an update to my code based off #Variatus 's advice:
Sub ImportData()
Dim wb As Workbooks
Dim ws As Worksheets
Dim objSheet As Object
Dim objWord As Object
Set objWord = CreateObject("Word.Application")
wb.Open ("C:\Users\pc\Documents\Book2.xlsm")
Set objSheet = CreateObject("Excel.Application")
ActiveWindow.WindowState = xlMinimized
Set ws = Workbooks("Book2.xlsm").Sheets("Sheet1")
ws.Range("A1").Value.Copy
With objWord.ActiveDocument
.Bookmarks("Bookmark_1").Range.Text = ws.Range("A1").Value
End With
End Sub
I'm getting this error:
Runtime Error '91':
Object variable or With block variable not set.
Notice how I stuck with a single cell reference for now (A1). I'll just update my code as I learn along the way :)
When you click the button in your Word document you want the following sequence to be initiated.
Create an Excel application object. Make sure that a reference to Excel has been set (VBE > Tools > References) so that Excel's VBA objects are available.
Using the Excel application object, open the workbook. Create an object. Place the object in an invisible window.
Definitely forget about activating or selecting anything in either the workbook or your Word document. The latter is active and remains active from beginning to end. The bookmarks are points in your document you can reference and manipulate by name without selecting them. The Excel workbook is invisible. You can access any part of it using the Range object.
The data you want from your workbook are contained in Worksheets. Be sure to create an object for the worksheet you are about to draw data from.
Excel tables don't translate very well into Word tables. If you do want to go that way I suggest that you use VBA to create the table you want in Excel (transpose the data before you import them into Word). However, you may find it easier to first create the tables you want in Word and then just copy values from your Excel source into the word tables. That would involve taking one cell value at a time and placing it into one Word table cell. Transposing would be done by the algorithm you employ.
Close the workbook. Quit the Excel application. Set the Excel application = Nothing. At the end of your macro everything is as it was before except that your document has data in it which it didn't have before.
Each of the above six points will lead you to at least one question which you can ask here after you have googled the subject and written some code. In fact, I strongly urge you to create one Main procedure (the one which responds to your button click) and let that procedure call various subs which carry out the individual tasks and functions to support the subs. The smaller the parts you create the easier it is to write the code, to find questions to ask and get answers to them. If you plan your project well expect to have about 12 procedures in it by the time you are done. Good luck!
I am trying to look up some data in an excel sheet to populate a field in a Lotus Notes app on demand. I am using an Action button with LotusScript like so:
Dim v As String
Dim v2 As String
'Open XL sheet for access to data
Set oExcel = CreateObject ( "Excel.Application" )
v="\\msp2\mi\CSD\Confidential\IT and PPST budget.xlsm"
Msgbox("opening " & v)
Set oWorkbook = oExcel.workbooks.open(v)
Set oWorkSheet= oWorkbook.worksheets (4)
v2=Cstr(oWorkSheet.Cells(1,1).value)
Messagebox(v2)
This code does work in that it pulls data from cell A1 - but which sheet?
The sheet containing the data I want is "Sheet4" renamed as "Logic-Detail" but if I use 4 as a parameter as above I get data from the 4th sheet from the left. I need to be able to cope with sheets being hidden as well. I spent 20 minutes on MSDN's excel object model "help" getting nowhere :-(
I feel sure it must be dead easy when you know the answer !
Guessing at the correct syntax is frustrating, isn't it? When referring to sheets in Excel-VBA there are several options:
You can list them by index-number, as you already did in the code-sample in your question
You can refer to it by its name, in your case this would probably be oWorkbook.Worksheets("Logic-Detail")
You can refer to it by its codename, in your case this would probably be oWorkbook.Sheet4. The codename can be changed when you view the properties of the worksheet in the VBA editor.
There may be even more ways to refer to the sheet, but these are the ones which come to mind at the moment. As we know from the question and comments, at least the two first options also work in LotusScript.
I am using VBScript to make lots of calculations on different sheets on the same workbook. Now one concern is if somehow someone deleted any of the sheet, the script would then lead to massive data loss. Is there any way to protect it from users?
(Make sure you read the edit at the end of this answer)
I have similar workbooks I have made that use sheets like databases, so I understand your concern of protecting the information. If you are protecting the Workbook, it will prevent your macro from performing certain changes to the sheets/book. However, if you only want to protect the sheet contents, you can use the setting UserInterfaceOnly, which will allow your macro to run freely while still protecting the sheets from the users. You can detect if the sheets are protected when opened, and if not, protect them.
Sub test()
dim mySheet as worksheet
dim myPass as string
myPass = "password"
set mySheet = Excel.ActiveSheet
if mySheet.ProtectContents = False then
mySheet.Protect Password:=myPass, UserInterfaceOnly:=True
end if
'Enter your code here
mySheet.Unprotect Password:=myPass
End Sub
Furthermore, if you want to give the user the ability to unprotect the sheets after being warned, then you can use Custom UI Editor to remove the protect/unprotect sheets group from the review tab and then replace it with a customized button. I've done this in the past and it actually helped a lot with maintaining the sheets later. I've included a couple links on Custom UI Editor below.
Custom UI Editor Download
Custom UI Editor Tutorial - Change the Ribbon in Excel 2007 or
2010
EDIT:
At first glance I thought this question pertained to VBA (my bad). I believe the above code can still apply, just place the code within the tags and set the workbook and worksheet variables properly (not the way they are set above). If you don't already know how to set/reference your workbook/worksheetsheet objects, this forum post shows how. Albeit I don't normally work with VBscript, but the forum looks correct. Good luck!
i nw this was a few years ago, but i ran into it when searching for the answer, hopefully someone fins this helpfull.
First add a password to your workbook that way other users will only be able to open as read only.
http://www.k2e.com/tech-update/tips/728-tips-adding-a-password-to-make-an-excel-workbook-read-only
then to make as part of the vbscript when opening the excel file(s)
Set oExcel = CreateObject("Excel.Application")
Set oWorkbook = oExcel.Workbooks.Open(file.path,,,,"password","password",True,,True,True)
full list of switches can be found here:
http://msdn.microsoft.com/en-us/library/office/ff194819%28v=office.15%29.aspx
hope that helps, took me hours to figure this out.
I'm trying to modify an embedded excel table in a word document programmatically. To do this, I have modified the docx file and the embedded excel file.
The significant part of the main document is the following:
<w:object w:dxaOrig="8406" w:dyaOrig="2056">
<v:shape id="_x0000_i1028" type="#_x0000_t75"
style="width:390.75pt;height:95.25pt" o:ole=""><v:imagedata r:id="rId14"
o:title=""/>
</v:shape>
<o:OLEObject Type="Embed" ProgID="Excel.Sheet.12" ShapeID="_x0000_i1028"
DrawAspect="Content" ObjectID="_1349794876" r:id="rId15"
UpdateMode="Always"/>
</w:object>
The word document uses an OLEObject to link to the embedded excel document. For displaying purposes,
a .wmf file is used (using the v:shape element). I have modified the excel document, which outdated this preview.
This results in some strange behaviour in the document:
The preview of the embedded (excel) table shows the wrong data
Double clicking on the embedded table opens the table in an embedded excel and shows the correct data
Closing the embedded editor triggers the generation of a new preview, showing the correct data
Of course, I want the table to show the correct table when the document is opened. How can I trigger Word to discard the image and redraw the preview?
An ideal solution for me would be to trigger the regeneration of the preview just by modifying the contents of the docx, but solutions using a small script would also help.
There is no perfect solution to this, but one that works most of the time is to force an open/close of the OLEFormat.Object. It doesn't matter if you are rehydrating the embedded Excel worksheet from outside of Word (i.e. manipulating the Open XML format) or doing it through the object model. What it involves is opening the embedded Excel spreadsheet from within Word and then closing that object for the image to be changed to the current values in the embedded spreadsheet and the new image to be created.
It depends just a bit if you are doing this on many Word documents or just one. In the former case, a global template (such as normal.dot or a custom one you create and put in the STARTUP folder) or in the later case, just run code behind of one document. Both have a different way to getting things to run, but essentially you will be hooking the Document_Open event and from there checking if the current document has OLE Embedded objects and if so, opening and closing them.
Without going into the hook, like I said, the code isn't pretty. Basically because it uses SendKeys. Most of the time, this will work. Some of the time, it won't. That is the nature of SendKeys and other programs receiving the focus without consent (such as an instant messenger program).
If Word has the focus (which means you can't open the VBE and press F5), this code should do the trick:
Sub UpdateEmbeddedXLSX()
Dim workbook As InlineShape
For Each workbook In ActiveDocument.InlineShapes
With workbook
If .Type = wdInlineShapeEmbeddedOLEObject Then
''# Excel.Sheet.12 for Excel 2007
If .OLEFormat.ClassType = "Excel.Sheet.12" Then
''# Open Object as spreadsheet
.OLEFormat.DoVerb wdOLEVerbPrimary
''# If you want, you can also do any updates here like
.OLEFormat.Object.ActiveSheet.Cells(2, 2).Value = ".1"
''# Nasty - but it works - SendKeys
SendKeys "{ESC}", True
End If
End If
End With
Next
End Sub
At the very least, you could put this code in your normal.dot and assign it to the QAT to be run as a macro.
Note that the code doesn't get around Excel opening, the values changing and then closing - that is part and parcel of using embedded objects. Using linking instead of embedding would be a much smoother way to do all of this, but I realize it's not always an option.
Just to add to an old post in the event someone stumbles upon this like I did:
The above code works great, but I modified it to use bookmarks instead of using SendKeys. The SendKeys statement really messes with the NumLock on my keyboard. Just one of the quirks of that command.
What I did was create bookmarks in my Word Doc Template. Then in my code, I created a pointer to the bookmark:
Dim bMark as bookmark
Set bMark as ActiveDocument.Bookmarks("NameOfBookmark")
Then in place of the SendKeys statement, I did the following:
bMark.Range.Select
Selection.EndKey
This basically pulled the focus out of the embedded worksheet, and onto the bookmark of the page. Then the .EndKey statement simply removed the selection. You don't really even need it.
Hope this helps!
If anyone's coming here looking for how to update an Excel Object embedded in a Visio document via VBA macros without double-clicking, you just need to call Save on the embedded workbook.
Dim wb As Excel.Workbook
Set wb = ThisDocument.Pages("MyPageName").Shapes("NameOfWorksheetShape").Object
'Calling me updates the visible worksheets.
wb.Save
I need a way to programatically launch the macro-recorder in Excel, and supply the name for the new macro that will get created.
This can be from VSTO or VBA, or using the Office interop assemblies.
Any ideas how this can be accomplished?
In VBA:
Dim ctrlStart As CommandBarControl, ctrlStop As CommandBarControl
Set ctrlStart = Application.CommandBars.FindControl(ID:=184)
Set ctrlStop = Application.CommandBars.FindControl(ID:=2186)
ctrlStart.Execute
'name part would go here, but first you have to deal with a modal dialog
ctrlStop.Execute
It looks like the Execute method on the RecordMacro control opens a modal dialog. There is no way to feed a parameter to this, or to do anything like SendKeys. The only way I see to do it is to write a sub that will rename the macro after the fact. It will be a little complicated to determine what the name of the new macro is, and you will still have a dialog box to deal with.