Creating and Accessing a OLEObject - vba

I have an VBA Macro that at times requires me to create a new slide with a new embedded excel spreadsheet, then edit that spreadsheet. A simplified version of this code:
Dim sld As Slide
Dim shp As shape
Dim pptWorkbook As Object
Set sld = ActivePresentation.slides.add(ActivePresentation.slides.Count + 1, ppLayoutBlank)
Set shp = sld.Shapes.AddOLEObject(100, 100, 100, 100, "Excel.Sheet")
DoEvents
If shp.Type = msoEmbeddedOLEObject Then
'Error thrown here
Set pptWorkbook = shp.OLEFormat.Object
pptWorkbook.Sheets(1).Cells(1, 1).value = "Stuff"
End If
About half of the time running this code results in the error:
Method object of object OLEFormat failed
This occurs on the shp.OLEFormat.Object call, I believe that this is due to "AddOLEObject" not creating the excel object in time to provide access to the property(but this is just a hypothesis). I have tried various ways of getting around this by error handling and sleep functions but so far I have been unable to create a new excel object and modify its contents within the same function without generating some error.
So my question is: How do you, with VBA, add a new embedded excel spreadsheet within a PowerPoint document and edit its contents within the same function/sub?
Update 1
I have successfully run this code on other machines, so this issue may be environmental, related with my system, and not an issue with my methodology. It also could be permission related, similar to This Post.
Update 2
I have reinstalled Office, restarted, run PowerPoint as administrator, and have added logic to account for the issue detailed in This post. Still no progress, I wonder if anyone can replicate the error that I am receiving?

I fixed the issue by resetting all my office settings by deleting all related keys in the registry(As Detailed Here):
HKEY_CURRENT_USER\Software\Microsoft\Office
After further investigation it turned out the reason I was getting this error message was because I had installed the "OLAP PivotTable Extensions"(link) add in to excel, for some reason this was conflicting with the "AddOLEObject" method. So simply deleting the registry key for the extension effectively removed the extension from excel and fixed my issue. The same effect was also observed when the extension was fully uninstalled.
HKEY_CURRENT_USER\Software\Microsoft\Office\Excel\Addins\OlapPivotTableExtensions2016

Related

How to prevent loss of 'link' for embedded chartdata

I'm currently receiving a 'Linked File Not Available' error when trying to manually open datasets for embedded charts in Word after successfully updating these datasets via a VBA script. I am trying to build a project which will allow users to automatically update a series of embedded charts based on a user defined worksheet which is produced monthly.
In order to support this project, I've been trying to find a way in which I can update chart data in Word using VBA while avoiding the ChartData.Activate method (eventually crashes the program due to the burden of successive open / close actions [context: I have around 300 charts in the largest of these reports]).
I've attempted to update the data using a direct call to the ChartData.Workbook and ChartData.ActivateChartDataWindow both of which allow me to successfully update the data. Following the successful update however, I get the below error when trying to access the dataset manually and can no longer access it via the Macro:
Linked File Not Available
I know I am probably missing something simple, or perhaps am approaching this in the wrong way by going through Word but wanted to throw it out there to see if anyone has a solution which could resolve / explain what's causing the loss of these 'links' to embedded datasets?
Chart Screenshot (Front)
Chart Screenshot (Data)
To try and streamline testing; I've created a stripped down version of the overall code which I've been using to try and troubleshoot:
Dim x As Integer 'Counter used to breakout of routine once 1 chart updated.
Dim strChartTitle As String
Dim objChart As InlineShape
Dim objTargetWorkbook As Workbook
Dim objTargetWorksheet As Worksheet
x = 0
For Each objChart In ActiveDocument.InlineShapes
strChartTitle = objChart.Chart.ChartTitle.Text
If x = 1 Then
Exit Sub
ElseIf strChartTitle Like "EHR Transactions Summary (By Endpoint)*" Then
'objChart.Chart.ChartData.Activate
objChart.Chart.ChartData.ActivateChartDataWindow
Set objTargetWorkbook = objChart.Chart.ChartData.Workbook
Set objTargetWorksheet = objTargetWorkbook.ActiveSheet
objTargetWorksheet.Range("C1:D11").Copy objTargetWorksheet.Range("B1")
objTargetWorksheet.Range("D1").Value = DateAdd("m", 1, objTargetWorksheet.Range("C1").Value)
x = 1
objTargetWorkbook.close
End If
Next objChart
Problem:
Couldn't find a way to update data on a large number of charts using vba without utilising the Chart.ChartData.Activate or Chart.ChartData.ActivateChartDataWindow commands which either caused crash due to CPU load on successive load / unload (former method) or broke links between the embedded charts and their datasheets (latter method).
Solution:
Solution was provided in part by #Slightly Snarky in comment to original question / problem post. Despite Microsoft's documentation, it is possible to update data within Chart workbooks without the need to call an activate command by referencing the workbook and worksheet directly.
Re-wrote script to utilise the new method and confirmed not only did this allow me to edit data; it was able to do so while avoiding the performance hit inherent in the repeated open / close events caused by the two above methods.
On testing; one problem did come up in that MS-Word would spin up a new Excel sub-process each time the code referenced a different chart without killing the previous sub-process. Given these reports have up to 300 charts, this inevitably caused the routine to crash once enough sub-processes had built up against the CPU.
To resolve this issue, I tweaked the code to include a ChartData.Workbook.Close command after each chart update completes which has helped keep CPU burden to a minimum and prevented crashes due to overloading with Excel sub-processes.
Dim strChartTitle As String
Dim objChart As InlineShape
For Each objChart In ActiveDocument.InlineShapes
strChartTitle = objChart.Chart.ChartTitle.Text
If strChartTitle Like "EHR Transactions Summary (By Endpoint)*" Then
With objChart.Chart.ChartData.Workbook.Worksheets(1)
.Range("C1:D11").Copy objChart.Chart.ChartData.Workbook.Worksheets(1).Range("B1")
.Range("D1").Value = objChart.Chart.ChartData.Workbook.Worksheets(1).Range("D1").Value = DateAdd("m", 1, objChart.Chart.ChartData.Workbook.Worksheets(1).Range("C1").Value)
End With
objChart.Chart.ChartData.Workbook.close
End If
Next objChart

VBA : Enexpected running VBA from cmd line

I wanted to open an existing ppt using Wscript and modify it. For that I am opening the file in visual studio editor and executing the script from cmd in windows using WScript hi.vbs
But when I ran the same code I am getting error.
Expected end of statement in line 4
Line 4 looks like Dim objNewPowerPoint As Object
However Same case works when I run code in excel VBA editor.
When I am removing the As object I am not getting any error nor any changes are happening in the PPT file.
Wondering what is the possible issue.
I am not using excel vba or word vba i am just running the file from cmd
Sub Open_an_existing_Presentations()
Dim objNewPowerPoint As Object
Dim MyPresentation As Object
Dim pSlides As Object
Set objNewPowerPoint = CreateObject(PowerPoint.Application)
'Make this Application Object Visible
objNewPowerPoint.Visible = True
Please help me how can i modify and more importantly how to see both errors compile and syntax.
FYI : I am completely new into VBA and I am trying to update a PPT and wanted to run vba script from another program so trying something like this. Best suggestions are always welcome
In VBScript you cannot dim something as something.
Dim objNewPowerPoint
Dim MyPresentation
Dim pSlides
And dim is optional and serves no technical purpose in VBS (it merely catches spelling mistakes if Option Explicit is specified, else it does nothing at all as in your case except take time to the process the line). In compiled languages it allocates storage and checks data types when using it.
When you use Set = VBS knows it an object and makes it one (4 x 32 bit integers - One a reference count and another a memory address of the function table for the object - two are unused). If you use x=5555 vbs knows it's a integer.

Access/Excel: Method End of object Range failed?

I have an Access db that processes and imports Excel workbooks. It has historically worked well, but is suddenly giving me this error on all workbooks - even ones that previously worked:
-2147417851: Method 'End' of object 'Range' failed
The line causing the problem is:
iLastCBRow = XlBook.Worksheets("4_CensusBlocks").Range("B16001").End(xlUp).Row
If I step through this line in the Immediate window and enter
XlBook.Worksheets("4_CensusBlocks").Range("B16001").Value
it returns the value of that cell correctly.
I thought that the Access db might be corrupt, so I recreated it. Same problem. I also manually forced a repair on the Excel workbook. I even uninstalled and reinstalled Office.
Running Office 2016 64 bit now on Windows 7.
Does anyone have an idea what the problem might be? Thanks
it looks like it is because you have more than 16001 lines in the file. The first command
iLastCBRow = XlBook.Worksheets("4_CensusBlocks").Range("B16001").End(xlUp).Row)
sets iLastCBRow to the starting row.
Try using
iLastCBRow = ActiveSheet.UsedRange.SpecialCells(xlLastCell).Row
instead
I still don't understand WHY, but the problem seems to have been in using early binding of Excel object variables. Once I put in place
dim xl as object
dim xlbook as object
set xl = createobject("Excel.Application")
set xlbook = xl.workbooks.open(filename)
Instead of just
dim xlbook as excel.workbook
set xlbook = getobject(filename)
The error went away. I have only had Office 2016 installed this whole time, so perhaps an update made the OLE server think that I had multiple Offices installed or something?? No idea.

How do I fix Error 432 when loading a form in Word VBA?

I have a Word .dot file which works in older versions of Word but fails with error 432 when run in Word 2013.
When I debug the code I have the line:
Load customerForm
And VBA shows the error:
Run-time error '432': File name or class name not found during Automation operation
The project "pennyscode" includes "Module1" which contains the function being debugged, "ThisDocument" and a form called "customerForm".
I have tried changing the name to "pennyscode.customerForm" but this doesn't make any difference.
This code is being called from a Sub function which is called from Document_New().
Updates
I can place a breakpoint on the Load customerForm line and demonstrate that it is the line that is causing the problem. If at this point I mouse over the word "customerForm" VBA comes up with
customerForm = <Object variable or With block variable not set>
If I delete/skip the Load line then the next line is customerForm.Show and that produces the same error.
If I just open the .dotm file and then use Alt-F11 to open VBA, I can look at the code for selectCustomer, list properties/methods and customerForm appears in the list.
Additional Note
I believe that within the Load function it must be calling GetObject and it is this that is failing. It is as if VBA can't find the customerForm object even though it appears in the project.
I've posted the full code of the function being called from Document_New below.
Sub selectCustomer()
Dim Doc As Document
Set Doc = Application.ActiveDocument
If Doc.CustomDocumentProperties.Item("Customer") = "Nothing" Then
Load customerForm
customerForm.Show
Unload customerForm
Doc.Fields.Update
a$ = Doc.CustomDocumentProperties.Item("InvoiceNumber")
a$ = customerForm.pathBox.Value + "\" + a$
Doc.SaveAs (a$)
End If
End Sub
I've also posted the full .dotm (Excel 2013) and .dot (previous excel) and some sample data (.xls) here:
Dropbox/Public/Invoice 2015-16.dotm
Dropbox/Public/Invoice 2015-16.dot
Dropbox/Public/data.xls
Update
I've not had much luck making progress on this question. Can anyone suggest an approach to investigating this? Or how I might improve the information on the question?
I finally managed to fix this, and I have a few learnings.
Firstly the debugger shows the error as occurring on the Load customerForm line, but this is actually not the case.
The customerForm has an _Initialize function which loads data into it before it is displayed. This function was failing with but the debugger stops on the wrong place.
I was able to debug this more effectively by putting a breakpoint on the start of the _Initialize sub and then stepping through the code.
Once I had discovered this I realized that the code was failing to find the XLSX file due to a wrong path, thus causing the run-time error.
Once I'd fixed up all the paths, I then hit a second error: runtime error '9' which is a subscript problem. This also reported on the Load customerForm line and was also due to a problem with the _Initialize function.
This was the true source of the problem, and demonstrated a functional change between Office 2013 and previous versions of Office.
My code was opening an XLSX file and attempting to read data from it:
Dim myXL As Object
Dim myWS As Object
Set myXL = GetObject("C:\Test\data.xlsx")
myXL.Application.Visible = True
myXL.Parent.Windows(1).Visible = True
Set myWS = myXL.Application.Worksheets("Customers")
The run-time error 9 was due to the index of the Windows property, as their were no windows. In previous versions of Office, there was a single window, with 2013 the array is empty.
After much messing about I tried adding this line:
myXL.Activate
before accessing the Windows() array. Once that was executed Windows(1) existed and the code worked as before.
Hope this can help someone else struggling with similar problems.

Publish an excel worksheet as an HTML file using a command button

So I have tons of data in my workbook that I need to pass on to my users in a way that allows them to interact with the workbook..., but also limits what they can actually do. So I have made it so they can access certain pages to Add needed data, then I've given access to a menu page so they can run a report.
This report I have found is best if it's an html page.
To that end, I have tried several different ways, save as...and publish. I like the publish version, but I can not for the life of me get this working. All the samples I see, appear to be the same. Here is the line of code in question:
ActiveWorkbook.PublishObjects.Add(xlSourceSheet, ActiveWorkbook.Path & ".htm, "Sheet1", "", xlHtmlStatic, "", "Report Title").Publish True
Every time I get a run time error '1004':
Method 'Publish' of object 'PublishObject' failed
I have the above line of code in a sub, am I missing something? Do I need to set up the publish differently? Thanks for any ideas.
I have had a similar mysterious problem that sometimes it (.Publish) works and sometimes it doesn't, when I try publish.
However, I think the problem might be, in cases when it doesn't work right off the bat, to first save the relevant region as a webpage so that it exists already on the server. After that region has been saved at least once (manually or else maybe with .SaveAs .. see below), then the publish might work.
Here is an example of how I get this to work more consistently, something to convey the structure that works for me:
wkb=ActiveWorkbook.Name 'save wb for later access
url="http://a.com/b.htm" 'save to Internet
sheetname="c"
Sheets(sheetname).Range("d1:e2").Select 'activating sheet may be necessary
On Error Resume Next 'anticipate error to handle it
'Now comes the publish line the first time... which may work.. or not
ActiveWorkbook.PublishObjects.Add(xlSourceRange,url,sheetname,"d1:e2",xlHtmlStatic,"blah","moreblah").Publish (True) 'may fail to create page on website if page didn't already exist
theerr=Err.Number
On Error GoTo 0 'back to default error handling (none)
If theerr <> 0 Then 'if here perhaps because page nonexistent
'msgbox "maybe add warning here [FYI]"
Sheets("dummysheetwithlittleornodata").Copy 'will create workbook
On Error Resume Next
ActiveWorkbook.SaveAs url 'may fail to create webpage first time
ActiveWorkbook.saveAs url 'twice needed for some reason sometimes. [works for me]
On Error GoTo 0
'with fresh dummy html page created, now publish should hopefully work.. let's try again
ActiveWorkbook.Close savechanges:=False 'clean up and avoid popup
Workbooks(wkb).Activate 'get back to correct wkb
Sheets(sheetname).Range("d1:e2").Select
ActiveWorkbook.PublishObjects.Add(xlSourceRange,url,sheetname,"d1:e2",xlHtmlStatic,"blah","moreblah").Publish (True) 'hopefully if failed first time, now it succeeded ! good luck.
End If
The above code structure has allowed me to solve several publish problems I was having. All the techniques together have been enough so far to allow me to save a range from a sheet as a webpage (to server I have write access to) without having to do anything manually (like a manual save or even click on popup). Good Luck.
[The different non-obvious techniques include activating a range before trying a range publish, using the error handling approach and anticipating failure at certain points, the 2x saveas to compensate for mysterious inconsistent failures when using one saveas only, closing and getting back to original workbook cleanly, and using saveas to "guarantee" page exists in form that will make publish to succeed more consistently.]