I am having a problem with a macro that copies named ranges and charts out of excel and into powerpoint. The macro functions as intended on my computer, however when when I run the macro on a coworker's computer I get Run-time error '-2147023170 (800706be)'. The problematic loop is below.
'Create an Instance of PowerPoint
On Error Resume Next
'Is PowerPoint already opened?
Set PowerPointApp = GetObject(class:="PowerPoint.Application")
'Clear the error between errors
Err.Clear
'If PowerPoint is not already open then open PowerPoint
If PowerPointApp Is Nothing Then
Set PowerPointApp = CreateObject(class:="PowerPoint.Application")
End If
'Handle if the PowerPoint Application is not found
If Err.Number = 429 Then
MsgBox "PowerPoint could not be found, aborting."
Exit Sub
End If
On Error GoTo 0
Application.ScreenUpdating = False
'Create a New Presentation
Set myPresentation = PowerPointApp.Presentations.Add
'Change aspect ratio
myPresentation.PageSetup.SlideSize = 2
cycle=1
For Each ch In ThisWorkbook.Sheets("Meeting Metrics").ChartObjects
'Add a slide to the Presentation
Set mySlide = myPresentation.Slides.Add(cycle, 11) '11 = ppLayoutTitleOnly
mySlide.Select
With mySlide.Shapes.Title.TextFrame.TextRange
.Text = slideTitles(cycle - 1)
With .Font
.Name = "Arial"
.Size = 32
.Color.RGB = RGB(237, 125, 49)
End With
End With
'Check if there is a table (Excel cell range) to copy for this slide
If Not IsMissing(copyRange(cycle - 1)) Then
'Copy Excel Range
ThisWorkbook.Sheets("Meeting Metrics").Range(copyRange(cycle - 1)).Copy
'Paste to PowerPoint
mySlide.Select
mySlide.Shapes.Paste
Set myShape = mySlide.Shapes(mySlide.Shapes.count)
Application.CutCopyMode = False
'Set position
myShape.Top = tableVertPos(cycle - 1) * 72
myShape.Left = tableHorPos(cycle - 1) * 72
End If
'Copy excel chart
ch.Select
ch.Chart.ChartArea.Copy
'Paste to PowerPoint
mySlide.Select
mySlide.Shapes.Paste
Set myShape = mySlide.Shapes(mySlide.Shapes.count)
Application.CutCopyMode = False
'Set position
myShape.Top = chartVertPos(cycle - 1) * 72
myShape.Left = chartHorPos(cycle - 1) * 72
cycle = cycle + 1
Next
When the error occurs, powerpoint will become unresponsive and ask to close. The error message will pop up, and debug will take me to one of lines containing mySlide (Not always the same line). If I try to hit the continue button, it results in Runtime error 462 since the powerpoint is closed. When I try to step through the program on the other computer to find the problematic line, it will step through a couple lines and then run like normal until it bugs out. However, if a throw a line break somewhere inside the loop and manually iterate it or put a message box inside the loop, the code will run fine.
I've tried inserting wait or sleep into the loop to see if this helps, but this just causes the code to halt for a few seconds before failing.
There appears to be a bug in the system described as a 'run ahead' in some places. I've had some success with the following ugly workaround...
Create the following UglyWait subprocedure
Sub UglyWait(Optional sec As Integer = 1)
Dim future As Date
future = DateAdd("s", sec, Now())
Do While Now() < future
DoEvents
Loop
End Sub
Place a call to UglyWait before and after any Powerpoint goto, paste, or save operations.
Application.Wait doesn't work, nor does a standard single DoEvents. This does seem to help though.
Related
I'm making an Add-in for PowerPoint 2013. My goal is to convert all equations that I find on slides to normal text, to change the font of those equations.
Because it won't let me change font while they are equations. I managed to find the equations, by iterating through text ranges and finding font name, they use "Cambria Math". So my question is how can programmatically change equations to normal text, Like the button in equation tools does? And it seems for some reason they removed "record macro" from PowerPoint, so I couldn't get help from that.
I tried recording macro in word and doing the same thing, and i got: Selection.OMaths(1).ConvertToMathText, but it doesn't seem to be OMaths in PowerPoint.
Dim Application As PowerPoint.Application = New PowerPoint.Application
Dim Presentation As PowerPoint.Presentation = Application.ActivePresentation
Dim Windows As PowerPoint.DocumentWindows = Application.Windows
For Each Slide As PowerPoint.Slide In Presentation.Slides
For Each Shape As PowerPoint.Shape In Slide.Shapes
For Each Paragraph As PowerPoint.TextRange In Shape.TextFrame.TextRange
For Each Line As PowerPoint.TextRange In Paragraph.Lines
If Line.Font.Name = "Cambria Math" Then
With Line.Font
.Name = "Calibri"
.Bold = True
End With
ElseIf Line.Font.Name = "Calibri" Then
With Line.Font
.Name = "Palatino"
End With
End If
Next Line
Next Paragraph
Next Shape
Next Slide
End Sub
Other text here is changed normally, but equations the ones with "Math Cambria" font, are unchanged.
I also tried to get selection, then something with OMaths, like in Word Vsto, but, it seems OMaths is not part of the PowerPoint. This next code is actually supposed to change it to equation, but i guess if it worked, could have find a way to reverse it.
For Each Window As PowerPoint.DocumentWindow In Windows
Selection.OMaths(1).ConvertToMathText
Next Window
I got it to work with PowerPoint 2016 in VBA. I didn't have "Calibri" in my list of fonts, so I changed it to "Calibri (Body)" and it works. It may be the same issue you're having with the .NET VSTO Addin. If I have time, I'll build a example of the VSTO Addin and post the results as well.
Video
VBA Code
Public Sub UpdateShapeFont()
On Error GoTo ErrTrap
Dim Application As PowerPoint.Application: Set Application = New PowerPoint.Application
Dim Presentation As PowerPoint.Presentation: Set Presentation = Application.ActivePresentation
Dim Windows As PowerPoint.DocumentWindows: Set Windows = Application.Windows
Dim Slide As PowerPoint.Slide
Dim Shape As PowerPoint.Shape
Dim Paragraph As PowerPoint.TextRange
Dim line As PowerPoint.TextRange
For Each Slide In Presentation.Slides
For Each Shape In Slide.Shapes
For Each Paragraph In Shape.TextFrame.TextRange
For Each line In Paragraph.Lines
Select Case line.Font.Name
Case "Cambria Math"
With line.Font
.Name = "Calibri (Body)" 'check if the font exists in your list of fonts; it did not work for "Calibri"
.Bold = True
End With
Case "Calibri"
With line.Font
.Name = "Palatino"
End With
End Select
Next line
Next Paragraph
Next Shape
Next Slide
ExitProcedure:
On Error Resume Next
Exit Sub
ErrTrap:
Select Case Err.number
Case Else
Debug.Print "Error #: " & Err.number & " |Error Description: " & Err.description
End Select
Resume ExitProcedure
Resume 'for debugging
End Sub
What I'm trying to do is to copy a bunch of cells as a picture from one sheet and paste it in a chart object in another sheet. The following is the code used and it is running fine when used in debug mode, but I do no see the image being pasted in the chart when I run it normally.
Sub copy_paste_KDT()
'
' copy_paste_KDT Macro
'
'
Worksheets("KDT").Range("J12:AB37").CopyPicture Appearance:=xlScreen, Format:=xlPicture
Dim wb_path As String
wb_path = Application.ThisWorkbook.Path
'Dim objCht As ChartObject
'Set objCht = ActiveSheet.ChartObjects("KDT Rectangle")
'If Not objCht Is Nothing Then
If ActiveSheet.ChartObjects.Count > 0 Then
ActiveSheet.ChartObjects("KDT Rectangle").Delete
End If
With Worksheets("profile")
'Creating the Chart
.ChartObjects.Add(690, 125, 550, 245).Name = "KDT Rectangle"
End With
If Range("B11").Value = 0 Then
With Worksheets("profile")
Application.ScreenUpdating = True
'Application.Wait (Now + TimeValue("00:00:01"))
With .ChartObjects("KDT Rectangle")
.Chart.Paste
End With
End With
End If
End Sub
I have also tried few thing like waiting for 1 to 10 seconds before the image is being pasted but of no use. Even tried putting a loop to count from 1 to a billion, no use again. Finally wanted to check if the image is getting pasted in a random cell of the sheet and that works, but not in the chart object.
I would appreciate if someone could help me figure out why the image is not getting paste.
TL,DR: Macro to copy paste a part of excel as a screenshot into a chart creates a chart successfully but not able to populate the image when run (F5), but works perfectly in debug mode (F8).
Although I am using Excel 2010 and your code works fine in testing for me.
You can try putting a Select in before the .Chart.Paste this might help with pasting inside the chart. See code below, just added the line into your original code, so you were almost there.
Option Explicit
Sub copy_paste_KDT()
'
' copy_paste_KDT Macro
'
'
Worksheets("KDT").Range("J12:AB37").CopyPicture Appearance:=xlScreen, Format:=xlPicture
Dim wb_path As String
wb_path = Application.ThisWorkbook.Path
'Dim objCht As ChartObject
'Set objCht = ActiveSheet.ChartObjects("KDT Rectangle")
'If Not objCht Is Nothing Then
If ActiveSheet.ChartObjects.Count > 0 Then
ActiveSheet.ChartObjects("KDT Rectangle").Delete
End If
With Worksheets("profile")
'Creating the Chart
.ChartObjects.Add(690, 125, 550, 245).Name = "KDT Rectangle"
End With
If Range("B11").Value = 0 Then
With Worksheets("profile")
Application.ScreenUpdating = True
'Application.Wait (Now + TimeValue("00:00:01"))
With .ChartObjects("KDT Rectangle")
.Select 'Just added this
.Chart.Paste
End With
End With
End If
End Sub
So this error seems to come up for a number of reasons, however none of the other solutions seem to address the issue I'm facing. I have a script running from excel that copies a table over to a powerpoint slide, but I keep getting "Shapes (unknown member): Invalid request".
What it's not caused from:
It's not a case of not grabbing focus of power point as I'm able to change text on a slide via the script and select different slides.
It's not a case of not copying table in time. I set it to wait and I've also put a message box in between and have pasted the table manually with what the vba code had copied.
The code:
Keep in mind I've omitted paths and unrelated segments of code...
Dim PPT As PowerPoint.Application
Set PPT = New PowerPoint.Application
PPT.Visible = True
PPT.Presentations.Open Filename:= "#######################"
Set curWS = Worksheets("###############")
curWS.Select
Set pt = curWS.PivotTables(1)
Set ptRg = pt.TableRange1
Set ptRg = Range(curWS.Cells(ptRg.Row - 1, ptRg.Column), _
curWS.Cells(ptRg.Row + ptRg.Rows.Count - 1, ptRg.Columns.Count + ptRg.Column - 1))
ptRg.Select
Selection.Copy
DoEvents
PPT.ActivePresentation.Application.ActiveWindow.Panes(2).Activate
PPT.ActivePresentation.Application.ActivePresentation.Slides(2).Select
PPT.ActivePresentation.Application.ActivePresentation.Slides(2).Shapes.PasteSpecial ppPastePNG, msoFalse
Try change your ppPastePNG to ppPasteEnhancedMetafile.
e.g.
PPT.ActivePresentation.Slides(2).Shapes.PasteSpecial ppPasteEnhancedMetafile, msoFalse
Modify the last lines in your code with the piece of code below (using the myShape object, will allow you later to modify the picture parameters easily)
Dim myShape As Object
PPT.ActivePresentation.Application.ActiveWindow.Panes(2).Activate
ptRg.Select
Selection.Copy
Set myShape = PPT.ActivePresentation.Slides(2).Shapes.PasteSpecial(ppPastePNG, msoFalse)
Apparently it sometimes is not copying correctly, then it goes to the pasting part and it has nothing...
I managed to solve this problem by placing Application.CutCopyMode = False before the selection and copy command
Example:
Application.CutCopyMode = False
'Selecting and copying
Range("ExportTable").Copy
' Pasting and giving format
With PPSlide.Shapes.PasteSpecial(DataType:=2)
.Align msoAlignLefts, msoTrue
.Align msoAlignCenters, True
.Align msoAlignMiddles, True
.IncrementTop (dist_top)
.Top = 70
.Left = 15
.LockAspectRatio = msoFalse
.Height = 90
.Width = 690
End With
I am building a macro that takes excel data and puts in PowerPoint presentation, however the presentation that is created from scratch by my macro contains default Office SlideMaster in opposition to a new presentation created by opening PowerPoint manually which contains SlideMaster loaded from
C:\Users\xxxx\AppData\Roaming\Microsoft\Windows\Templates\blank.potx which is a company slidemaster. I want the macro to create a presentation with company slidemaster, the problem is that the macro will be ran on different computers therefore I can not use the path to blank.potx (username changes).
Is it possible to make it work that way?
Here is the beggining of my code:
Sub mainsub()
Dim PowerPointApp As Object
Dim myPresentation As Object
Dim mySlide As Object
Dim mySlide2 As Object
Dim myShape As Object
Dim myShape1 As Object
Dim myShape2 As Object
Dim ws As Worksheet
Set formularz = ThisWorkbook.Sheets("formularz")
On Error Resume Next
Set PowerPointApp = GetObject(class:="PowerPoint.Application")
Err.Clear
If PowerPointApp Is Nothing Then Set PowerPointApp = CreateObject(class:="PowerPoint.Application")
If Err.Number = 429 Then
MsgBox "PowerPoint could not be found, aborting."
Exit Sub
End If
On Error GoTo 0
Application.ScreenUpdating = False
Set myPresentation = PowerPointApp.Presentations.Add
Set mySlide = myPresentation.Slides.Add(1, 12)
With myPresentation.PageSetup
.SlideWidth = 800
.SlideHeight = 450
End With
ThisWorkbook.Sheets("formularz").Activate
PowerPointApp.Visible = True
PowerPointApp.Activate
PowerPointApp.WindowState = 2
mySlide.Select
Set myShape1 = mySlide.Shapes.addTextbox(msoTextOrientationHorizontal, 100, 100, 100, 100)
text1 = formularz.Range("B2").text
myShape1.TextFrame.TextRange.text = text1
myShape1.top = 0
myShape1.TextFrame.TextRange.Font.Name = "Helvetica 75"
myShape1.TextFrame.TextRange.Font.Color.RGB = RGB(255, 102, 0)
myShape1.TextFrame.WordWrap = 0
myShape1.left = 400 - myShape1.width / 2
PowerPointApp.ActiveWindow.Selection.Unselect
.
.
.
and so on, mainly creating great number of another slides and shapes.
Probably the answer to my question is (to be put) somewhere in above code.
Thanks for any piece of advice
I have an Excel Picture as Shape and i want to paste it to mny PowerPoint app which has a Special layout which i have already specified.
Sub ExcelShapePowerpoint()
Dim PowerPointApp As Object
Dim myPresentation As Object
Dim mySlide As Object
Dim myShape As Object
Dim pastedPic1 As Shape
Set DestinationSheet1 = Workbooks("myExcelFile.xlsm").Sheets("myExcelSheet")
Set pastedPic1 = DestinationSheet1.Shapes(10)
On Error Resume Next
Set PowerPointApp = GetObject(class:="PowerPoint.Application")
If PowerPointApp Is Nothing Then Set PowerPointApp = CreateObject(class:="PowerPoint.Application")
'Handle if the PowerPoint Application is not found
If Err.Number = 429 Then
MsgBox "PowerPoint could not be found, aborting."
Exit Sub
End If
On Error GoTo 0
Application.ScreenUpdating = False
Set myPresentation = PowerPointApp.Presentations.Add
Set mySlide = myPresentation.Slides.Add(1, 11) '11 = ppLayoutTitleOnly
With myPresentation.PageSetup
.SlideWidth = 961
.SlideHeight = 540
End With
pastedPic1.Copy
mySlide.Shapes.PasteSpecial DataType:=2 '2 = ppPasteEnhancedMetafile
Set myShape = mySlide.Shapes(mySlide.Shapes.Count)
'Set position:
myShape.Left = -15
myShape.Top = 11
PowerPointApp.Visible = True
PowerPointApp.Activate
Application.CutCopyMode = False
End Sub
As its obvious from the code the layout is already set. Now i want the pastedpic1 to fit completely to the layout of the PowerPoint.
What should i do ?
To scale the shape myShape to the size of the slide, use this:
With myShape
.Top = 0
.Left = 0
.Width = ActivePresentation.PageSetup.SlideWidth
.Height = ActivePresentation.PageSetup.SlideHeight
End With
Note that depending on the aspect ratio of your shape and slide, stretching may occur. This can be dealt with using the cropping methods.
I had a similar problem but took another approach:
I created a PowerPoint template where I added Picture placeholders to the destinations where the pictures have to be inserted. This approach has the advantage, that you can edit the layout in PowerPoint and do not have to fiddle with pixel sizes in the basic code.
The following example is in VBScript but can be transfered to VBA easily:
Open the PowerPoint template:
Dim powerPoint, presentation
Set powerPoint = CreateObject("PowerPoint.Application")
Set presentation = powerPoint.Presentations.open("C:\template.pptx")
Select the Placeholder, and paste the picture:
Dim slide, view, image, placeholder
Set view = m_presentation.Windows(1).View
Set slide = m_presentation.Slides(slideId)
view.GotoSlide(slide.SlideIndex)
Set placeholder = slide.Shapes(shapeName)
placeholder.Select()
view.Paste()
slide.Application.CommandBars.ExecuteMso("PictureFitCrop")
Scale the picture to fit the size of the placeholder:
slide.Application.CommandBars.ExecuteMso("PictureFitCrop")