Unable to iterate the CustomerData collection (Invalid Procedure Call error) - vba

I am attempting to store xml metadata within chart shapes in a PowerPoint presentation.
I need to ensure that the shape only contains the current xml data, so I have a function to delete existing data (if any) and add the current data.
Sub Test()
Dim cht as Chart
Dim xml as String
Set cht = ActivePresentation.Slides(1).Shapes(1)
xml = "<Chart property1='true' property2='false'>blah blah blah</Chart>"
EmbedChartXML xml, cht
End Sub
Sub EmbedChartXML(xml As String, cht As Shape)
Dim x As Variant
'Get rid of any previous data
For Each x In cht.CustomerData
x.Delete
Next
Set xmlPart = cht.CustomerData.Add
xmlPart.LoadXML xml
End Sub
The For Each loop is failing with the indicated error message. I can see that the cht.CustomerData.Count = 2 (for example), but if I try to view this in the Locals window, I get the same error.
UPDATE
Here is another test routine that is failing, even though there is nothing inside the For/Next loop.
Sub TestIteration()
Dim sld As Slide
Dim pres As Presentation
Dim shp As Shape
Dim x As CustomXMLPart
Set pres = ActivePresentation
Set sld = pres.Slides(2)
For Each shp In sld.Shapes
Set pptCustomerData = shp.CustomerData
For Each x In shp.CustomerData
' For Each pptCustomXMLPart In pptCustomerData
' Debug.Print pptCustomXMLPart.Id
' Next
Next
Next
End Sub

Others here cannot replicate this error in Excel 2013 (I am using Excel 2010) where the collection object itself becomes inaccessible. Perhaps there is a bug or something, but I could not find much on Google about similar errors...
I ultimately arrive at this solution. I am not sure why the CustomXMLPart's .Delete method doesn't actually delete the item from the collection (instead it makes it to Nothing, and then failure on successive iteration attempts).
Instead, I use the CustomerData.Delete method. This seems to be working as expected.
Sub EmbedChartXML(xml As String, cht As Shape)
Dim x As Variant
Dim cData As CustomerData
Dim xID As String
Set cData = cht.CustomerData
Debug.Print cht.CustomerData.Count
'Get rid of any previous data
For Each x In cData
xID = x.Id
cData.Delete xID
Next
With cData.Add
.LoadXML xml
End With
Debug.Print cht.CustomerData.Count
End Sub

Related

Unlock with macro when read-only in PowerPoint

I want to remove read-only using a PowerPoint macro.
I'm writing a macro that fires when a file is opened.
In that macro, there is a process to delete a specific shape.
The PowerPoint file has a write lock.
Given the above assumptions, when you open the file read-only
The macro will be executed, but an error will occur because it is read-only and the shape cannot be deleted.
So I unlock the read-only lock when the macro is executed
When I'm done deleting a particular shape, I want to lock it again for read-only.
Is there such a way?
I know the write lock password.
Public Sub Ribbon_onLoad(ribbon As IRibbonUI)
Const EXP_DATE As Date = "2021/09/30"
Dim NOW_DATE As Date: NOW_DATE = Format(Date, "yyyy/mm/dd")
Dim pp As PowerPoint.Presentation: Set pp = ActivePresentation
If NOW_DATE <= EXP_DATE Then
MsgBox "OK!"
Call DeleteShapesWithName("expShape")
Else
MsgBox "No!Exp!:" + Format(EXP_DATE, "yyyy/mm/dd")
'ActivePresentation.Close
End If
End Sub
Sub DeleteShapesWithName(ByVal targetName As String)
Dim sld As Slide
Dim shp As Shape
Dim i As Long
i = 1
For Each sld In Application.ActivePresentation.Slides
Do Until i > sld.Shapes.Count
If sld.Shapes(i).Name = targetName Then
sld.Shapes(i).Delete
Else
i = i + 1
End If
Loop
Next
End Sub
------add
I added the modified source after receiving the reply.
Public Sub Ribbon_onLoad(ribbon As IRibbonUI)
Call UnlockPresentation
End Sub
Sub UnlockPresentation()
Dim oPVW As ProtectedViewWindow
Dim oPres As Presentation
Set oPVW = ProtectedViewWindows.Open("C:\test\example_exp.pptm")
oPVW.Edit ModifyPassword:="test"
Call DeleteShapesWithName("expShape")
'Do stuff here
End Sub
Sub DeleteShapesWithName(ByVal targetName As String)
Dim sld As Slide
Dim shp As Shape
Dim i As Long
i = 1
For Each sld In Application.ActivePresentation.Slides
Do Until i > sld.Shapes.Count
If sld.Shapes(i).Name = targetName Then
sld.Shapes(i).Delete
Else
i = i + 1
End If
Loop
Next
End Sub
Here's code to open a read-only presentation so you can modify it. No need to reset the password, just replace "Test" with the actual password. Where the Do stuff here comment is, you can use the ActivePresentation keyword to modify the file:
Sub UnlockPresentation()
Dim oPVW As ProtectedViewWindow
Dim oPres As Presentation
Set oPVW = ProtectedViewWindows.Open("C:\HasModPW.pptx")
oPVW.Edit ModifyPassword:="ExistingModificationPassword"
'Do stuff here
End Sub
Please note: Microsoft's help page on ProtectViewWindow.Edit is wrong. The page currently states this method changes the password, but it actually provides the PW to make editing possible,

MS Visio Drop a custom shape using VBA

I can't seem to figure out how to drop a shape using VBA.
What I want to do is: The user opens a UserForm and enters something in the TextBoxes. When clicking on the commandbutton I want to load a Shape (i.e. ressource) from a custom stencil (i.e. shapes.vssx) write the User-Entries into the ShapeData (i.e. write a Name string in Props.Name) and then Drop it somewhere on the sheet. I know I have to use the Shape.Drop method but how do I reference the specific Master-Shape I want to use for creating the new shape?
So far I am trying with this
Private Sub CommandButton1_Click()
Dim shp As Visio.Shape
Dim page As Visio.page
Set page = Application.ActiveWindow.page
Set shp = Application.Documents.Item("shapes.vssx").Masters.ItemU("ressource")
page.Drop shp, 1, 1
End Sub
Which returns a type mismatch. What am I missing?
You're looking to drop a Master rather than a Shape so try this modification of your code (untested):
Private Sub CommandButton1_Click()
Dim mst as Visio.Master
Dim shp As Visio.Shape
Dim pag As Visio.page
Set pag = Application.ActiveWindow.Page
Set mst = Application.Documents.Item("shapes.vssx").Masters.ItemU("ressource")
'You might also want to add some checks that the target document and then master exist
Set shp = pag.Drop(mst, 1, 1)
End Sub

Error while copy-pasting data from another ppt

I'm trying to copy slide 1 from external ppt to current ppt into notes page. However, I'm getting this error msg:
Slides (unknown member) : Invalid request. Clipboard is empty or
contains data which may not be pasted here.
The external ppt from where I'm copying does contains the data.
VBA script:
Sub copySlide()
Dim objPresentation As Presentation
Set objPresentation = Presentations.Open("/path/slides.ppt")
objPresentation.Slides.Item(1).Copy
Presentations.Item(1).Slides.Paste
objPresentation.Close
End Sub
Try the code below, I hope your presentation at ("/path/slides.ppt") doesn't throw an error.
I added 2 options, either place it at the end, or as the second slide - you can modify the Paste line easily
Code
Sub copySlide()
Dim MyPres As Presentation
Dim objPresentation As Presentation
Set MyPres = ActivePresentation
Set objPresentation = Presentations.Open("/path/slides.ppt")
objPresentation.Slides(1).Copy
'MyPres.Slides.Paste MyPres.Slides.Count + 1 ' <-- place it at the end
MyPres.Slides.Paste 2 ' <-- place it as the second slide
objPresentation.Close
Set objPresentation = Nothing ' clear object
End Sub

Block Reference Hyperlink property in AutoCAD 2014 with VBA?

I have this .dwg file that has hundreds of block references.
I am trying to create hyperlink to a pdf file from all of the block references. The pdf are on my D drive.
For example, names of the block refernece are: '2:test', '26:test', '234:test'. Essentially hyperlink for
each point would be: '2:test' would hyperlink to D:\Reports\File-002.pdf;
'26:test' would hyperlink to D:\Reports\File-026.pdf; '234:test' would hyperlink to D:\Reports\File-234.pdf.
From block
references i get the number before the ':', and its matching pdf would be 'File-' followed by the number before ':' in 3 digits.
There are lot of these to do by hands, and i think i can program for this.
I have enough basic programming knowledge to manipulate the string to get my number and convert it in 3 digits. The question i have
and/or need help is with how to cycle through each block reference(for loop) on the file and be able to write to its hyperlink property? Is this even possible?
Before coming here i kind of looked at these links but they did not prove helpful:
Link1; Link2; Link3
Thanks for the hints
UPDATE
Private Sub CommandButton1_Click()
Dim ReadData As String
Open "C:\Desktop\Files\DesignFile.DWG" For Input As #1
Do Until EOF(1)
Line Input #1, ReadData
MsgBox ReadData 'Adding Line to read the whole line, not only first 128 positions
Loop
Close #1
End Sub
You can try this:
Dim stringInput
stringInput = "2:test', '26:test', '234:test"
stringSplit = Split(stringInput, ",")
For i = 0 To UBound(stringSplit)
Debug.Print (stringSplit(i))
Next i
Outputs:
2:test'
'26:test'
'234:test
you can try this
Option Explicit
Sub test()
Dim acBlockRef As AcadBlockReference
Dim baseStrng As String
baseStrng = "D:\Reports\File-"
For Each acBlockRef In BlockRefsSSet("BlockRefs")
acBlockRef.Hyperlinks.Add("PDF").URL = baseStrng & Format(Left(acBlockRef.Name, InStr(acBlockRef.Name, "-") - 1), "000") & ".pdf"
Next acBlockRef
ThisDrawing.SelectionSets("BlockRefs").Delete
End Sub
'-----------------------------------------------------------------
'helper functions
'------------------
Function BlockRefsSSet(ssetName As String, Optional acDoc As Variant) As AcadSelectionSet
'returns a selection set of all block references in the passed drawing
Dim acSelSet As AcadSelectionSet
Dim Filtertype(0) As Integer
Dim Filterdata(0) As Variant
Set BlockRefsSSet = CreateSelectionSet(ssetName, acDoc)
Filtertype(0) = 0: Filterdata(0) = "INSERT"
BlockRefsSSet.Select acSelectionSetAll, , , Filtertype, Filterdata
End Function
Function CreateSelectionSet(selsetName As String, Optional acDoc As Variant) As AcadSelectionSet
'returns a selection set with the given name
'if a selectionset with the given name already exists, it'll be cleared
'if a selectionset with the given name doesn't exist, it'll be created
Dim acSelSet As AcadSelectionSet
If IsMissing(acDoc) Then Set acDoc = ThisDrawing
On Error Resume Next
Set acSelSet = acDoc.SelectionSets.Item(selsetName) 'try to get an exisisting selection set
On Error GoTo 0
If acSelSet Is Nothing Then Set acSelSet = acDoc.SelectionSets.Add(selsetName) 'if unsuccsessful, then create it
acSelSet.Clear 'cleare the selection set
Set CreateSelectionSet = acSelSet
End Function
'-----------------------------------------------------------------
with following notes:
you can't have a colon (":") in a block name
so I used a hypen ("-") as its substitute
every block reference object will be attached the URL ("D:\Reports\File-nnn.pdf") associated with the block name it's a reference of

VISIO count shapes in container

I'm pretty rusty with VBA and I was hoping someone could point me in the right direction, or help me out. What I'm trying to do is run a macro that will cycle through each active container on my sheet, and then count the number of shapes within that container. Then I'd like to update a field in the shape data for the container with the number of shapes.
This is what I have so far:
Public Sub countContainers()
Dim vsoPage As Visio.Page
Dim vsoDocument As Visio.Document
Dim vsoDocuments As Visio.Documents
Dim vsoPages As Visio.Pages
Dim vsoContainerShape As Visio.Shape
Dim containerId As Variant
For Each containerId In vsoPage.GetContainers(visContainerIncludeNested)
Set vsoContainerShape = vsoPage.Shapes.ItemFromID(containerId)
Debug.Print vsoContainerShape.NameU
Next
End Sub
The error I get is Object Variable or With Block variable not set
Any ideas?
The error is because you have declared the vsoPage but you never assigned it to any page in your document.
Add a line such as this to initialize it and the error goes away:
Set vsoPage = ActivePage