VBA deleting a duplicate copy of chart object fails in Excel 2013 - vba

I have a VBA code that is intended to copy the contents of a range into a chart, to be able to export it to a PNG file (+some post-processing using an external command). Here is the relevant part:
Sub GenererImage() ' Entry point
getparams ' Collect parameters and define global variables
MiseEnPage.Range(ZoneImage).CopyPicture Appearance:=xlScreen,Format:=xlPicture
Application.DisplayAlerts = False
With ObjetGraphique.Duplicate
.Chart.Paste
.Chart.Export Filename:=CheminImage, Filtername:="PNG"
.Select
.Delete
End With
Application.DisplayAlerts = True
End Sub
The getparams procedure called in there is just collecting some parameters from another worksheet to define:
"MiseEnPage": reference to the worksheet object where the range I want to copy exists,
"ZoneImage" is set to the "B4:F11" string (refers to the range address),
"ObjetGraphique" is a reference to a ChartObject inside the "MiseEnPage" sheet. This ChartObject is an empty container (I am mainly using it to easily set the width and height).
"CheminImage" is a string containing the path to the picture filename on disk.
This code used to work perfectly in Excel 2010. Now my company has deployed Excel 2013 and my code now fails on the .Delete line, leaving the copy of the ChartObject (with the range picture pasted inside it) on the sheet and stopping macro execution.
I have tried activating the worksheet first, selecting the duplicate prior to deleting it and other things, to no avail. When tracing the execution in the debugger it chokes on the delete line with error 1004.
I am frustratingly stuck. Any clue?

If this works
With ObjetGraphique.Duplicate
.Chart.Paste
.Chart.Export Filename:=CheminImage, Filtername:="PNG"
.Select
End With
Selection.Delete
we have to assume that either the With is holding a reference and preventing the delete, or that the delete routine called by the selection object is not the same delete that's called by ObjetGraphique.Duplicate.delete, or that it's a subtle timing bug and that the extra time it takes to retrieve the selected object is enough to fix it.

OK after fiddling a lot with the object model, here is (the relevant part of) my final solution. Many thanks to HarassedDad for the clues.
Sub GenererImage() ' Point d'entrée
getparams
MiseEnPage.Range(ZoneImage).CopyPicture Appearance:=xlScreen, Format:=xlPicture
Application.DisplayAlerts = False
With ObjetGraphique
.Chart.Paste
.Chart.Export filename:=CheminImage, Filtername:="PNG"
.Chart.Shapes(1).Delete
End With
Application.DisplayAlerts = True
End Sub
What seems to happen is that the .Paste method of the Chart object creates a Shape in the .Shapes collection of this object. I can delete this Shape, but not the Chart itself or the ChartObject. Excel 2010 would allow that, but not Excel 2013.
I still do not understand the reasons, but at least I have something that works (until the next excel update probably...).

Related

Sheet inaccessible to macro: Error 1004: Application/Object Defined Error

This is happening in several of my macros, but this is the one in from of me:
Private Sub resettool()
'''resets step 2 input and user input on MPP tabs
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Call showsheets 'makes all of these sheets .Visible = True
'clear data from lookups and data corrals
Sheets("Media by Copy Lookup").Range("b1",Range("b1").End(xlToRight).End(xlDown)).ClearContents
Sheets("Total Media Lookup").Range("d1",Range("d1").End(xlToRight).End(xlDown)).ClearContents
Sheets("Total Media Lookup").Range("b2:c100").ClearContents
Sheets("Media by Copy Data").Range("a1",Range("a1").End(xlToRight).End(xlDown)).ClearContents
'etc etc
End Sub
It continues with similar data-clearing lines for a while. This started happening when I took someone else's code and cleaned it by removing the .Select usages as people on here have suggested. It seems that the macro isn't able to access the sheets I'm referencing, because a line runs successfully if I step into the code, manually select the referenced sheet, and then hit go (but then of course I get the same error when I try to edit another sheet).
Any ideas why the macro wouldn't be able to access these sheets unless I explicitly activate/select them? The sheets are all visible, so that shouldn't be the problem.
P.S. I've seen the guide on using .Rows.Count).End(xlUp) instead of End(xlDown) to find the bottom of my data and will implement that soon, but this issue is occurring no matter how I define the range; it's about the sheet.

Excel Crashes after but not while running macro to copy formatting of chart to another chart

I wrote a macro that copies the format of one chart object and pastes it into other chart objects. The macro SUCCESSFULLY completes and the newly made chart objects are correctly made. It does what it's supposed to! However, Excel crashes immediately upon saving or after fiddling with the new chart object. It crashes in both Excel 2010 and Excel 2016.
I have isolated the code snippet that causes the Excel crash. In the following snippet of code, if Lines 8-9 are commented out, Excel does not crash:
For Each cht In sh_plots.ChartObjects
With cht.Chart
'copies master chart format
master_plot.Chart.ChartArea.Copy
'applies formats
.ChartArea.Select
ActiveSheet.PasteSpecial Format:=2
Application.CutCopyMode = False
So these 2 lines (8-9) are the ones at fault:
.ChartArea.Select
ActiveSheet.PasteSpecial Format:=2
Does anyone know why these 2 lines are acting as the bane of my existence right now? I have tested these 2 lines multiple times, and the crash is reproducible. My excel file is not corrupt because I tried to copy the code as text to a new Excel file and used safe mode etc etc, still crashing.
I do not want to have to copy the master chart property by property to accomplish the same thing as this simple format paster - unless someone has a better idea, that would require so much more extra code!
I have the Event Viewer error log if that would shed any light. Thanks!
Untested, as am on mobile. But I don't think you need to activate/select to copy-paste.
Code below toggles events and screen updating.
' Ensure you have Option Explicit and have declared cht as a ChartObject '
With application
.screenupdating = false
.enableevents = false
End with
'copies master chart format
master_plot.Chart.ChartArea.Copy
For Each cht In sh_plots.ChartObjects
'applies formats
Cht.chart.paste type:=xlformats
Next cht
'reset property outside of loop - once all done. '
Application.CutCopyMode = False
With application
.screenupdating = true
.enableevents = true
End with
Oh I solved the problem by messing around with more stuff!
For some reason Excel crashes if you specify error bars before pasting the chart format. So I did not specify error bars until after I pasted the format. Really weird that it does this.

Error in script which copies charts from Excel to PowerPoint

I am attempting to call the below Sub in order to copy given chart to a specified PowerPoint presentation. However, when I run the macro which calls this Sub, the line indicated below returns the following error: "Object doesn't support this property or method." What's odd is that both Shapes and Slide do contain the methods which are called. As well, the bitmap is correctly copied to my clipboard and pastes into the slide before the error is called. You will find the Sub() below.
Sub copyChart(chrt As Chart, pres As PowerPoint.Presentation)
Dim curSlide As Slide, dummySlide As Slide
Set dummySlide= pres.Slides(2) 'Second slide is dummy slide.
Set curSlide = dummySlide.Duplicate(1) 'Duplicate dummy, set as current slide.
chrt.CopyPicture Appearance:=xlScreen, Format:=xlBitmap 'Copy the chart as a picture.
curSlide.Shapes.Paste '<-----------Error here.
End Sub
As well, I was hoping to provide a .txt file of my entire script, but was unsure how (it is a little lengthy to paste here). Thanks for your help.
(Note that this implementation is very similar to that at Paste Excel Chart into Powerpoint using VBA, further confusing me.)
I have had a lot of trouble in recent versions of Office. 2003 and earlier didn't have this problem, 2007 and 2010 had it a bit, and 2013 and 2016 have it in spades.
When you step through the code it works fine, but when you run it at full speed, it errors on the paste.
It's as if the copy doesn't have time to finish finish, so when you paste the clipboard doesn't have anything in it yet to paste.
Sometimes this helps:
chrt.CopyPicture Appearance:=xlScreen, Format:=xlBitmap
DoEvents
curSlide.Shapes.Paste
DoEvents tells VBA to wait while background operations have a chance to finish up.
It looks like the error can be attributed to how VBA handles variables across different references. (In particular, how PPT VBA handles them.) I was able to get the macro to work by actively selecting/copying the charts. I will need to do a little more research to get why variables cause problems, but at least I know how tackle the problem.
Sub copyChart(curSlide As Slide)
Dim chr as ChartObject
Set chr = Sheets("CHARTSHEET").ChartObjects(1)
Sheets("CHARTSHEET").Select
ActiveChart.CopyPicture
curSlide.Shapes.PasteSpecial
End Sub
I like to use another method, I like to define an Object, then set it to the pasted Chart. Afterwards, it's much easier modifying the pasted Chart object's parameters inside PowerPoint (from Excel).
See code below:
Sub copyChart(curSlide As Slide)
Dim chr As ChartObject
Dim myChart As Object
Set chr = Sheets("CHARTSHEET").ChartObjects(1)
chr.Copy
' setting myChart object to the pasted chart (let's me later an easy way to modify it's parameters)
Set myChart = curSlide.Shapes.PasteSpecial(ppPasteBitmap, msoFalse) ' can change first parameter to other avaialabe formats : ppPasteGIF, ppPasteEnhancedMetafile, ppPasteOLEObject, etc.
' set different parameters for the pasted chart in PowerPoint slide
With myChart
.Left = 200
.Top = 200
End With
End Sub
In the code line:
Set myChart = curSlide.Shapes.PasteSpecial(ppPasteBitmap, msoFalse)
You can change the first parameter in brackets: ppPasteBitmap to many other avaialble formats (test them and see which one gives you the best result), such as: ppPasteGIF, ppPasteEnhancedMetafile, ppPasteOLEObject, etc.

Excel VBA - Formatting script for automation

So here's what I'm trying to do:
Open file: Pc_Profile
Create new sheet: Sheet1
Copy desired cells from Pc_Profile to Sheet1 (see script below)
Copy entire Sheet1 to new excel file: db.xls
Rename sheet to content of cell A5
Create new sheet for next script run
Basically I'm trying to automate an extraction of a TON of excel files into a single organized file. Each script call should extract to its own sheet so there's no overwritten information.
Here is what I have working so far. It just copies the desired cells to a new sheet within the same file.
' Create Excel object
Set objExcel = CreateObject("Excel.Application")
' Open the workbook
Set objWorkbook = objExcel.Workbooks.Open _
("\\[directory]\Pc_Profile.xls")
' Set to True or False, whatever you like
objExcel.Visible = True
objWorkbook.Worksheets("Pc_Profile").Range("A5:D5").Copy
objWorkbook.Worksheets("Sheet1").Range("A1").PasteSpecial
objWorkbook.Worksheets("Pc_Profile").Range("A8:B8").Copy
objWorkbook.Worksheets("Sheet1").Range("A2").PasteSpecial
objWorkbook.Worksheets("Pc_Profile").Range("A13:B13").Copy
objWorkbook.Worksheets("Sheet1").Range("A3").PasteSpecial
objWorkbook.Worksheets("Pc_Profile").Range("A15:D17").Copy
objWorkbook.Worksheets("Sheet1").Range("A4").PasteSpecial
objWorkbook.Worksheets("Pc_Profile").Range("A24:E26").Copy
objWorkbook.Worksheets("Sheet1").Range("A7").PasteSpecial
objWorkbook.Worksheets("Pc_Profile").Range("A28:B30").Copy
objWorkbook.Worksheets("Sheet1").Range("A10").PasteSpecial
objWorkbook.Worksheets("Pc_Profile").Range("A43:B43").Copy
objWorkbook.Worksheets("Sheet1").Range("A13").PasteSpecial
objWorkbook.Worksheets("Pc_Profile").Range("A45:B45").Copy
objWorkbook.Worksheets("Sheet1").Range("A14").PasteSpecial
' Activate Sheet2 so you can see it actually pasted the data
objWorkbook.Worksheets("Sheet2").Activate
I would really appreciate the extra push. I'm automating this for a work project and have no experience with VB - I just learned that on the go.
A couple things that are good practice to get into before I get to your actual question:
1) Any macro that you expect to run a long time should have Application.ScreenUpdating = False before any actual work is done in the code, this tells Excel not to bother with changing what's displayed on the screen (big performance booster). Be sure to include an Application.ScreenUpdating = True near the end of your code
2) Similar to #1, you generally want to include Application.Calculation = xlManual to boost performance. If you have large ranges of cells that your macro needs accurate up-to-date values from, it may be easier to leave the calculation automatic, but that doesn't appear to be the case in this instance.
3) You don't need to create a new Excel instance (which is what your first line of code does). You're already in a perfectly good instance of Excel. This also saves you having to close the other instance at the end of the macro (or worse from forgetting to do so and having memory get hogged by Excel processes that aren't really in use)
As to your specific problem, it sounds like you have more workbooks that Pc_profile to copy from, and that you're wanting to create a new "db.xls" with each run of the macro. Based on those assumptions all you need to do is nest your code starting with 'Open the workbook and objWorkbook.Worksheets("Sheet1").Range("A14").PasteSpecial inside a Do While loop. The thing I'm not sure about is how to control the loop. If the list of files is always the same, you should just include a list on a sheet in the workbook that holds the macro and just iterate through that.
The other thing you should do for ease of coding, and to make the loop more effective is declare and use a Worksheet variable and set if for each workbook to the appropriate sheet to pull data from. Ex.
Dim ws as Worksheet
'The Dim is outside your loop, but this would be inside it
Set ws = objWorkbook.Worksheets("whatever_the_sheet's_name_is")
This way you can replace each occurrence of objWorkbook.Worksheets("Pc_Profile"). with ws., easier to type, easier to read, easier to update, and less error prone.
Next, you don't actually have code for moving Sheet1 to a new workbook, or renaming it. To move it (as well as the other Sheet1's yet to be created), you should, before getting to the Do While loop, have the following
Dim target as Workbook
Set target = Application.Workbooks.Add
Then at almost the end of the loop, you need objWorkbook.Worksheets("Sheet1").Move Before:=Target.Sheets(1)
Last, you need to include objWorkbook.Close SaveChanges:=False after you've moved Sheet1 out of the Pc_Profile and renamed it.

Copy method fail due to memory

In my workbook, I copy the current sheet to keep as a record of a sale. Eventually, the workbook fills up with sales and at some point throws an error when I try to copy another sheet. After saving, then completely exiting Excel, then reloading the file, I can continue without problems. I'm guessing it's a memory issue, but I'm not quite sure how to solve it without restarting Excel. I can't remember the wording of the error exactly, but it went along the lines of "Copy method of worksheet failed". FWIW I use "Application.CutCopyMode = False" at the end of the macro that copies the sheet.
1st edit:
I'd like to post all of the code, but there's just so much of it (mostly not related to updating values, input verification, etc. etc.); if I post everything, I'd have to post all of the other functions for it to make sense. Suffice it to say, here's what I think is applicable:
ActiveSheet.Copy After:=Sheets(3)
...(more code)...
Call resetInterface(True, True, (wasScreenUpdating), (wasProtected))
and for the "resetInterface" function:
' Final operations for a typical function/sub '
Function resetInterface(Optional calc As Boolean = False, Optional ccmode As Boolean = False, Optional scrUpdate As Boolean = True, Optional protectWS As Boolean = False)
With Application
If calc Then
.Calculation = xlCalculationAutomatic
.Calculate
End If
If ccmode Then .CutCopyMode = False
.ScreenUpdating = scrUpdate
End With
If protectWS Then ActiveSheet.Protect
End Function
There used to be a problem when copying sheets in Excel that the CodeName property of the Worksheet object would be appended with a 1 and get to be too long. I think it's been fixed, but it would depend on what version you're using.
Open the VBA (Alt+F11) and show the Project Explorer (Ctl+R). Look at the CodeNames of your copied sheets. Are they Sheet1, Sheet2, etc..? Or are they Sheet1, Sheet11, Sheet111, etc...? If the latter, this may be causing the problem. See http://support.microsoft.com/kb/177634
Or it could be that you have a workbook level name, see http://support.microsoft.com/?kbid=210684
The error you're referring to is:
Excel VB run-time error 1004: "Copy method of Worksheet class Failed"
Can you post the macro you've written?