Catia Sheet No. Title Blocks - vba

I would like to get some VBA code which would tell me the number of sheets in a Catia drawing. Each sheet would have a title block placed on it. A text field on each title block would communicates the number of sheets. So if you had three sheets in the drawing you would have 1 of 3 (in the title block sheet 1) 2 of 3 (in the title block shhet 2) and 3 of 3 (in the title block sheet 3). If the macro could update all title blocks on all sheets automatically.
Any help much appreciated.

The concept is to loop through all of the DrawingSheet objects in the Sheets collection of the DrawingDocument you should put all title block elements in the "Background View". Next we need to update or create existing title block text elements. These are DrawingText objects. We try to access the DrawingText by name(THIS MUST BE UNIQUE!). If it does not exist, we create it. If it does exist, we update the value.
Here's a start to making your title block:
Option Explicit
Sub UpdateSheetPage()
Dim DrawingDoc As DrawingDocument
Dim DSheet As DrawingSheet
Dim DView As DrawingView
Dim SheetCount As Integer
Dim currentSheet As Integer
'the drawing must be the active docuement window or this will fail. you can do more error checking if needed
On Error GoTo ExitSub
Set DrawingDoc = CATIA.ActiveDocument
SheetCount = DrawingDoc.Sheets.Count
currentSheet = 1 'initialize sheet number
'loop through all sheets and update or create a sheet number
For Each DSheet In DrawingDoc.Sheets
UpdatePageNumber DSheet, currentSheet, SheetCount
currentSheet = currentSheet + 1
Next
ExitSub:
End Sub
Sub UpdatePageNumber(currentDrawingSheet As DrawingSheet, currentSheetNumber As Integer, totalSheets As Integer)
Dim sheetNumber As String
Dim xPos, yPos As Long 'mm
'edit these if needed
xPos = 100 'edit this - only use for new creation
yPos = 100 'edit this
'display format
sheetNumber = "Page " & currentSheetNumber & "/" & totalSheets
Dim backgroundView As DrawingView
Dim dTexts As DrawingTexts
Dim currentText As DrawingText
Set backgroundView = currentDrawingSheet.Views.Item("Background View")
Set dTexts = backgroundView.Texts
On Error GoTo CreateNew
Set currentText = dTexts.GetItem("SheetNumber")
currentText.Text = sheetNumber
Exit Sub
CreateNew:
Set currentText = dTexts.Add(sheetNumber, xPos, yPos)
currentText.Name = "SheetNumber" 'so we can access it later for an update
End Sub

Related

Collection storing more than it's intended to causing problems for a Union statement

For some reason every column with data is being stored into columnsToCopy and unionVariable. At the top levels in Locals, I can see that it recognizes the column I actually want, but when I go deeper into say Cells -> WorkSheet -> UsedRange -> Value2 it will now show that all columns in my workbook are stored. This is the piece of code that I have assigning columnsToCopy, all the way to assigning unionVariable and then Copying it:
checkOne = iq_Array(0)
hasIQs = Left(checkOne, 3) = "iq_"
Dim columnsToCopy As Collection
Set columnsToCopy = New Collection
If hasIQs Then
' paste inital column into temporary worksheet
columnsToCopy.Add ShRef.Columns(1)
End If
' loop for each iq_ in the array
For arrayLoop = LBound(iq_Array) To UBound(iq_Array)
' Take copy of potential ref and adjust to standard if required
checkStr = iq_Array(arrayLoop)
If hasIQs And Left(checkStr, 3) <> "iq_" Then checkStr = "iq_" & checkStr
' Look for existence of corresponding column in local copy array
pCol = 0
For iCol = 2 To colNumb
If checkStr = IQRef(iCol) Then
pCol = iCol
Exit For
End If
Next iCol
If pCol > 0 Then
' Paste the corresponding column into the forming table
columnsToCopy.Add ShRef.Columns(pCol)
End If
Next arrayLoop
If columnsToCopy.Count > 1 Then 'data was added
' Copy table
Dim unionVariable As Range
Set unionVariable = columnsToCopy(1)
For k = 2 To columnsToCopy.Count
Set unionVariable = xlApp.Union(unionVariable, columnsToCopy(k))
Next k
unionVariable.Copy ' all the data added to ShWork
The reason I'm looking into this, is because when I Union(unionVariable, columnToCopy(k)) I'm not getting something that would be equivalent to Range("A:A","D:D","Z:Z") , instead I'm getting Range("A:Z").
Any help is appreciated
My full code:
Option Explicit
Private Sub averageScoreRelay()
' 1. Run from PPT and open an Excel file
' 2. Start at slide 1 and find a box that contains the words "iq_", if it has those words then it will have numbers after it like so "iq_43" or "iq_43, iq_56,iq_72".
' 3. find those words and numbers in the opened Excel file after splitting and re-formating string.
' 3. Copy column into a new sheets and repeat for all "iq_'s" until sheets 2 has a table.
' 4. Copy table from xl Paste Table into ppt
' 5. Do this for every slide
'Timer start
Dim StartTime As Double
Dim SecondsElapsed As Double
StartTime = Timer
'Create variables
Dim xlApp As Excel.Application
Dim xlWB As Excel.Workbook
Dim ShRef As Excel.Worksheet
Dim pptPres As Object
Dim colNumb As Long
Dim rowNumb As Long
' Create new excel instance and open relevant workbook
Set xlApp = New Excel.Application
'xlApp.Visible = True 'Make Excel visible
Set xlWB = xlApp.Workbooks.Open("C:\Users\Andre Kunz\Desktop\Gate\Macros\averageScores\pptxlpratice\dummy2.xlsx", True, False, , , , True, Notify:=False) 'Open relevant workbook
If xlWB Is Nothing Then ' may not need this if statement. check later.
MsgBox ("Error retrieving Average Score Report, Check file path")
Exit Sub
End If
xlApp.DisplayAlerts = False
'Find # of iq's in workbook
Set ShRef = xlWB.Worksheets("Sheet1")
colNumb = ShRef.Cells(1, ShRef.Columns.Count).End(xlToLeft).Column
rowNumb = ShRef.Cells(ShRef.Rows.Count, 1).End(xlUp).Row
Dim IQRef() As String
Dim iCol As Long
Dim IQRngRef() As Range
ReDim IQRef(colNumb)
ReDim IQRngRef(colNumb)
' capture IQ refs locally
For iCol = 2 To colNumb
Set IQRngRef(iCol) = ShRef.Range(ShRef.Cells(1, iCol), ShRef.Cells(rowNumb, iCol))
IQRef(iCol) = ShRef.Cells(1, iCol).Value
Next iCol
'Make pptPres the ppt active
Set pptPres = PowerPoint.ActivePresentation
'Create variables for the slide loop
Dim pptSlide As Slide
Dim Shpe As Shape
Dim pptText As String
Dim iq_Array As Variant
Dim arrayLoop As Long
Dim myShape As Object
Dim i As Long
Dim lRows As Long
Dim lCols As Long
Dim k As Long
'Loop through each pptSlide and check for IQ text box, grab avgScore values and create pptTable
For Each pptSlide In pptPres.Slides
i = 0
pptSlide.Select
'searches through shapes in the slide
For Each Shpe In pptSlide.Shapes
If Not Shpe.HasTextFrame Then GoTo nextShpe 'boom, one less nested If statement
If Not Shpe.TextFrame.HasText Then GoTo nextShpe ' boom, another nested If statement bites the dust
'Set pptText as the Text in the box, then make it lowercase and trim Spaces and Enters
pptText = Shpe.TextFrame.TextRange
pptText = LCase(Replace(pptText, " ", vbNullString))
pptText = Replace(Replace(Replace(pptText, vbCrLf, vbNullString), vbCr, vbNullString), vbLf, vbNullString)
'Identify if within text there is "iq_"
If InStr(1, pptText, "iq_") <= 0 Then GoTo nextShpe
'set iq_Array as an array of the split iq's
iq_Array = Split(pptText, ",")
Dim hasIQs As Boolean
Dim checkStr As String
Dim pCol As Long
Dim checkOne
checkOne = iq_Array(0)
hasIQs = Left(checkOne, 3) = "iq_"
Dim columnsToCopy As Collection
Set columnsToCopy = New Collection
If hasIQs Then
' paste inital column into temporary worksheet
columnsToCopy.Add ShRef.Columns(1)
End If
' loop for each iq_ in the array
For arrayLoop = LBound(iq_Array) To UBound(iq_Array)
' Take copy of potential ref and adjust to standard if required
checkStr = iq_Array(arrayLoop)
If hasIQs And Left(checkStr, 3) <> "iq_" Then checkStr = "iq_" & checkStr
' Look for existence of corresponding column in local copy array
pCol = 0
For iCol = 2 To colNumb
If checkStr = IQRef(iCol) Then
pCol = iCol
Exit For
End If
Next iCol
If pCol > 0 Then
' Paste the corresponding column into the forming table
columnsToCopy.Add ShRef.Columns(pCol)
End If
Next arrayLoop
If columnsToCopy.Count > 1 Then 'data was added
' Copy table
Dim unionVariable As Range
Set unionVariable = columnsToCopy(1)
For k = 2 To columnsToCopy.Count
Debug.Print k & " : " & unionVariable.Address & " + " & columnsToCopy(k).Address
Set unionVariable = xlApp.Union(unionVariable, columnsToCopy(k))
Debug.Print " --> " & unionVariable.Address
Next k
unionVariable.Copy ' all the data added to ShWork
tryAgain:
ActiveWindow.ViewType = ppViewNormal
ActiveWindow.Panes(2).Activate
Set myShape = pptSlide.Shapes.PasteSpecial(DataType:=ppPasteHTML, Link:=msoFalse)
On Error GoTo tryAgain
'Set position:
myShape.Left = -200
myShape.Top = 150 + i
i = i + 150
End If
nextShpe:
Next Shpe
nextSlide:
Next pptSlide
xlWB.Close
xlApp.Quit
xlApp.DisplayAlerts = True
'End Timer
SecondsElapsed = Round(Timer - StartTime, 2)
MsgBox "This code ran successfully in " & SecondsElapsed & " seconds", vbInformation
End Sub
Output from Debugger:
2 : $A:$A + $B:$B
--> $A:$B
3 : $A:$B + $AF:$AF
--> $A:$B,$AF:$AF
2 : $A:$A + $C:$C
--> $A:$A,$C:$C
2 : $A:$A + $D:$D
--> $A:$A,$D:$D
3 : $A:$A,$D:$D + $L:$L
--> $A:$A,$D:$D,$L:$L
Here is another option doesn't have the additional overhead of creating a temporary workbook/worksheet.
Note: It may not be perfect -- in my testing it does not preserve cell background color but it does preserve text/font formats, and this appears consistent with the PasteSpecial(ppPasteHtml) method.
Note also: this assumes you can use a Table in PowerPoint to store the pasted data, and that all columns in your union range have the same number of rows. If you're just dumping the data in to a textbox or whatever sort of shape, this won't work.
But the idea is that once we have our "union", we can iterate over the Areas, and the Columns in each area, performing the Copy and Paste operation against each individual column.
Here is my data in Excel, I will create a union of the highlighted cells:
Here is the output in PowerPoint where I removed the borders from the table, note the text formatting preserved as well as cell alignment:
Option Explicit
Sub foo()
Dim ppt As PowerPoint.Application
Dim pres As PowerPoint.Presentation
Dim sld As PowerPoint.Slide
Dim shp As PowerPoint.Shape
Dim tbl As PowerPoint.Shape
Dim unionRange As Range
Dim ar As Range, c As Long, i As Long
Set unionRange = Union([A1:B2], [D1:D2], [F1:F2])
Set ppt = CreateObject("PowerPoint.Application")
ppt.Visible = True
Set pres = ppt.ActivePresentation
Set sld = pres.Slides(1)
' Create initial table with only 1 column
With unionRange
Set tbl = sld.Shapes.AddTable(.Rows.Count, 1)
End With
For Each ar In unionRange.Areas()
For c = 1 To ar.Columns.Count
i = i + 1
With tbl.Table
' Add columns as you iterate the columns in your unionRange
If .Columns.Count < i Then .Columns.Add
.Columns(i).Cells.Borders(ppBorderBottom).Transparency = 1
.Columns(i).Cells.Borders(ppBorderTop).Transparency = 1
.Columns(i).Select
ar.Columns(c).Copy '// Copy the column from Excel
ppt.CommandBars.ExecuteMso ("Paste") '// Paste the values to PowerPoint
End With
Next
Next
End Sub
Maybe more efficient to handle the Areas like so:
For Each ar In unionRange.Areas()
c = ar.Columns.Count
Dim tCol
tCol = .Columns.Count
With tbl.Table
' Add columns as you iterate the columns in your unionRange
While .Columns.Count < (tCol + c)
.Columns.Add
Wend
.Columns(tCol).Cells.Borders(ppBorderBottom).Transparency = 1
.Columns(tCol).Cells.Borders(ppBorderTop).Transparency = 1
.Columns(tCol).Select
ar.Copy '// Copy the columns in THIS Area object from Excel
ppt.CommandBars.ExecuteMso ("Paste") '// Paste the values to PowerPoint
End With
Next
But I still think performance on large data set will suffer vs the other answer.
The issue seems to be caused by the pasting of the non-contiguous range into PowerPoint.
I don't know enough PowerPoint VBA to know whether it has some other paste method you could use, but a work-around would be to create a new Excel worksheet containing just the info you want to copy, and then to copy that worksheet to PowerPoint:
'...
Next k
unionVariable.Copy ' all the data added to ShWork
'Create a temporary sheet (the workbook is being closed without saving
'so the temporary worksheet will be "lost" after we finish)
xlWB.Worksheets.Add Before:=xlWB.Worksheets(1)
'Paste the data into the temporary sheet
xlWB.Worksheets(1).Range("A1").PasteSpecial xlPasteValues
'Copy the temporary sheet
xlWB.Worksheets(1).UsedRange.Copy
tryAgain:
ActiveWindow.ViewType = ppViewNormal
'...

Using a loop to insert pictures to Word using Excel VBA

I'm trying to use a loop to shorten the last part of my VBA code.
The current code I have is:
Sub InsertPics()
Dim WordApp as Object
Dim WordDoc as Object
Set WordApp = CreateObject("Word.Application")
Set WordDoc = WordApp.Documents.Open("Testing.docx"
WordApp.Visible = True
Dim path() as Variant
Dim i as Long
Dim Pic as Variant
path = Application.Transpose(Sheets("Selection").Range("N10:N24").Value)
For i = LBound(ppath) To UBound(ppath)
path(i) = Sheets("Output").Range("Directory").Value & "\" & path(i) & ".jpg"
Next i
Set Pic1 = WordDoc.InlineShapes.AddPicture(path(1), False, True).ConvertToShape
Set Pic2 = WordDoc.InlineShapes.AddPicture(path(2), False, True).ConvertToShape
Set Pic3 = WordDoc.InlineShapes.AddPicture(path(3), False, True).ConvertToShape
End Sub
The Set Pic() part goes on for quite awhile so I'm looking for a way to do the same sub with a shorter code. Is there a way to loop this part?
Note: WordDoc refers to a specific word document, path() refers to a list of directory addresses that I've already defined.
You could use an array or a collection :
Sub test_volvader()
Dim i As Integer
Dim myCol As Collection
Set myCol = New Collection
For i = 1 To 3
myCol.Add WordDoc.InlineShapes.AddPicture(Path(1), False, True).ConvertToShape, i
Next i
For i = 1 To myCol.Count
YourOperationOnAPicture myCol.Item(i)
Next i
End Sub
You should put your pictures in a list too. See R3uK's collection proposal.
But if you don't need to keep a reference on your pictures, you can make it even simpler:
For i = 1 To 3
WordDoc.InlineShapes.AddPicture(path(i), False, True).ConvertToShape
Next

VBA fetch picture from a folder based on a string name. Contains wildcard

I have an excel file with 160 rows and 2 columns of data - article name, price.
I also have a folder which contains photos for those articles.
The problem is that that picture names are not EXACTLY the same as the article names in my excel sheet.
For example in my sheet I have article name: "3714-012-P140" but in the folder it would be "3714-012-P140---****".
However, after the initial 3 blocks of code (3714; 012; P140 in the example) there will always show up only 1 picture in the search.
How would one go about selecting the picture with a wildcard in it?
Additionally, how would I go about locking the picture into a specific cell in excel? What I mean to say is that when I resize or delete some rows/columns, the pictures move along the cells they are assigned to.
Dim ws As Worksheet
Dim articleCode As String, _
findStr As String
Set ws = Workbooks(1).Worksheets(1)
For i = 1 to ws.UsedRange.Rows.Count
articleCode = ws.Cells(i,1)
findStr = 'some code
ActiveSheet.Pictures.Insert( _
"C:\...path...\" & findStr & ".jpg").Select
Next i
Edit: I need to insert the photo into a third column in each row of data.
Regarding "locking" a picture into a specific cell.
See here for info about how to link a shape to a cell.
Essentially you need to:
Position the picture over a cell. This can be done by setting the pictures (ie shape) .Top and .Left properties to be the same the cell you are linking the picture to.
Set the formula of the shape to equal the cell reference (this will also resize the shape to be the same size as the cell, and cause it to resize if the cell size is changed). See here
The code below taken from here will help you find a file in a folder that matches a "findstring". (It will need to be adapted!)
Sub FindPatternMatchedFiles()
Dim objFSO As Object
Set objFSO = CreateObject("Scripting.FileSystemObject")
Dim objRegExp As Object
Set objRegExp = CreateObject("VBScript.RegExp")
objRegExp.pattern = ".*xlsx"
objRegExp.IgnoreCase = True
Dim colFiles As Collection
Set colFiles = New Collection
RecursiveFileSearch "C:\Path\To\Your\Directory", objRegExp, colFiles, objFSO
For Each f In colFiles
Debug.Print (f)
'Insert code here to do something with the matched files
Next
'Garbage Collection
Set objFSO = Nothing
Set objRegExp = Nothing
End Sub
Have your existing code call a function that accepts the name of the article (articleCode) and returns the path of the image file:
strImage = FindImage(articleCode)
If Len(strImage) > 0 Then ActiveSheet.Pictures.Insert strImage
Then you can write your function like so:
Function FindImage(strArticle As String) As String
Dim objFile As Object
With CreateObject("Scripting.FileSystemObject")
For Each objFile In .GetFolder("c:\path\to\images").Files
If StrComp(Left$(objFile.Name, Len(strArticle)), strArticle, vbTextCompare) = 0 Then
' Found an image file that begins with the article code.
FindImage = objFile.Path
Exit Function
End If
Next
End With
End Function
The function below takes articleCode which is the name of the picture, row and column into which the picture should be input.
Function picInsert(articleCode As String, row As Integer, column As Integer)
Dim objFSO As Object
Dim objFolder As Object
Dim objFile As Object
Dim i As Integer
Dim ws As Worksheet
Set ws = Workbooks(1).Worksheets(2) 'your worksheet where the pictures will be put
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder("...path...")
i = 1
For Each objFile In objFolder.Files
If objFile.name Like (articleCode & "*") Then 'finds a picture with similar name to the one searched
With ActiveSheet.Pictures.Insert(objFile.Path)
With .ShapeRange
.LockAspectRatio = msoTrue
.Width = 5
.Height = 15
End With
.Left = ActiveSheet.Cells(row, column).Left
.Top = ActiveSheet.Cells(row, column).Top
.Placement = 1 'locks the picture to a cell
End With
End If
i = i + 1
Next objFile
End Function
This is a test sub with which I tried the function above. Basically a simple loop which goes over the rows, takes the articleCode from first column and inputs a picture into third column using the function above.
Public Sub test()
Dim ws As Worksheet
Dim i As Integer
Dim articleCode As String
Set ws = Workbooks(1).Worksheets(2)
For i = 1 To ws.UsedRange.Rows.Count
articleCode = ws.Cells(i, 1)
Call picInsert(articleCode, i, 3)
Next i
End Sub

Selection.Range Type Mismatch

I have code that gets the range of each heading in a word document. The headings' ranges are saved in HeadingRange(). I am getting Run-Type Error 13: type mismatch when I set HeadingRange(HeadingCount) in my For loop. I don't know why this is happening. Both HeadingRange() and wrdApp.Selection.Range are clearly instances of the Range class.
Private Sub WordTab()
Dim wrdDoc As Word.Document
Dim wrdApp As Word.Application
Set wrdApp = CreateObject("Word.Application")
wrdApp.Visible = True
Set wrdDoc = wrdApp.Documents.Open("C:/Test.docx")
Dim i As Integer
Dim myHeadings As Variant
Dim count As Integer
Dim HeadingRange() As Range
Dim HeadingCount as Integer
TableCount = wrdDoc.Tables.count
wrdApp.Selection.HomeKey Unit:=wdStory 'moves selection to beginning of doc. assuming document's first line is not a heading.
myHeadings = wrdDoc.GetCrossReferenceItems(wdRefTypeHeading)
HeadingCount = 1
For i = LBound(myHeadings) To UBound(myHeadings) 'iterate through all headings
wrdApp.Selection.GoTo What:=wdGoToHeading, Which:=wdGoToNext 'move selection to next heading.
wrdApp.Selection.Expand wdLine 'expand selection range to entire line
ReDim Preserve HeadingRange(1 To HeadingCount)
Set HeadingRange(HeadingCount) = wrdApp.Selection.Range 'This is where the type mismatch happens
HeadingCount = HeadingCount + 1
Next i
wrdDoc.Close (Word.WdSaveOptions.wdDoNotSaveChanges)
Debug.Print "Done"
End Sub
Redimension the Array to some dummy size first. You are trying to Preserve a non-existent array.
So you could add a
Redim HeadingRange(1 To 1)
code at the start, before your loop begins.

Read Cell properties in Visio using vb

I am trying to create a VB macro in Visio that can read the data and properties of the shape. So say I have a Rectangle Shpae in Visio with Cells Name, Description, Type, Size.... and so on.
When I try to read the cells and their values I am only getting the first cell and its value.
Here is my code . I would appreciate some help here.
Sub Testing()
Dim excelObj As Object
Dim excelFile As String
Dim sheetName As String
' Dim excelBook As Excel.Workbook
' Set excelFile = "C:\Users\hbhasin\Documents\test.xls"
'Set sheetName = "New Sheet name"
Set excelObj = CreateObject("Excel.Application")
excelObj.Workbooks.Add
Dim pagObj As Visio.Page
Dim shpsObj As Visio.shapes
Dim shapes As Visio.shapes
Dim shpObj As Visio.Shape
Dim CellObj As Visio.Cell
Dim Storage() As String
Dim iShapeCount As Integer
Dim i As Integer
Dim j As Integer
Set pagObj = ActivePage
Set shpsObj = pagObj.shapes
iShapeCount = shpsObj.Count
Debug.Print iShapeCount
ReDim Storage(8, iShapeCount - 1)
For i = 1 To iShapeCount - 1
Set shpObj = shpsObj(i)
Storage(1, i - 1) = shpObj.Name
If shpObj.CellExists("Prop.Name", visExistsLocally) Then
Set CellObj = shpObj.CellsU("Prop.Name")
Storage(2, i - 1) = CellObj.ResultStr("")
End If
If shpObj.CellExists("Prop.Description", visExistsLocally) Then
Debug.Print "Test the IF statement"
Set CellObj = shpObj.CellsU("Prop.Description")
Storage(3, i - 1) = CellObj.ResultStr("")
End If
Next
For i = 0 To iShapeCount - 1
Debug.Print "Name- " & Storage(0, i)
Debug.Print "Description-" & Storage(1, i)
Next
End Sub
In fact, I have put a debug statement within the second if clause and that does not execute which tells me the compiler is not even seeing the second cell or any cell after.
If you're not getting the Description Shape Data it maybe that it's not local, but inherited from its master. Here's a slight modification of your code (with the Excel part removed as I don't think it's relevant here):
Sub Testing()
Dim shpsObj As Visio.shapes
Set shpsObj = ActivePage.shapes
Dim iShapeCount As Integer
iShapeCount = shpsObj.Count
'Assumes you want an array of shape data
Dim Storage() As String
ReDim Storage(iShapeCount - 1, 2)
'Visio shapes are 1 based so use full count
Dim i As Integer
Dim shpObj As Visio.Shape
For i = 1 To iShapeCount
Set shpObj = shpsObj(i)
Storage(i - 1, 0) = shpObj.Name 'Do you want NameU?
'Assumes you don't care whether the cell is local or inherited
If shpObj.CellExistsU("Prop.Name", visExistsAnywhere) Then
Storage(i - 1, 1) = shpObj.CellsU("Prop.Name").ResultStr("")
End If
If shpObj.CellExistsU("Prop.Description", visExistsAnywhere) Then
Storage(i - 1, 2) = shpObj.CellsU("Prop.Description").ResultStr("")
End If
Next
Dim j As Long
For j = LBound(Storage, 1) To UBound(Storage, 1)
Debug.Print "Shape Name- " & Storage(j, 0)
Debug.Print " Prop.Name- " & Storage(j, 1)
Debug.Print " Prop.Description- " & Storage(j, 2)
Next j
End Sub
If you're just running through all the shapes on the page, then you might want to look at For Each shp In shapes as an alternative. Check out this page for more details:
http://visualsignals.typepad.co.uk/vislog/2007/11/looping-through.html
Also, you might want to try look at the CreateSelection page method to narrow down your target shapes if you're dealing with a large number