Powerpoint中VBA编程技巧

清华大佬耗费三个月吐血整理的几百G的资源,免费分享!....>>>

Sub PowerPointBasics_1() 
    ' PowerPoint 的对象模型 Ojbect Model (OM)模型导航 
    ' 每个东东在 PowerPoint 中都是某个类型的对象 
    ' 想操作好 PowerPoint,你就要和对象打交道 有些对象是另外一些对象的集合。 
    ' 对象具有属性 – 用来描述对象的东东 
    ' 对象具有方法 – 对象可以做或你可以对他做什么 
    ' 对象模型就是所有 PowerPoint 对象自成一个体系的集合 
    ' 就像一个倒置的树图 
     ' 按 F2 浏览查看对象 
     ' 数的最顶层是应用对象(Application) 
    ' 就是 PowerPoint 本身 
    ' 应用对象有他的属性 
    Debug.Print Application.Name 
     ' 用 Debug.Print 代替 MsgBox 能节省一点时间 
     ' 我们就不需要点击对话框的“确定”按钮 
     ' Debug.Print 的结果输出在 VB 编辑器环境中的立即窗口中 
     ' 如果它没有显示,通过点击菜单“视图”/“立即窗口”或者按 Ctrl+G 来显示 
     ' .Presentations 属性返回当前打开演示文档的一个集合 
     ' 我们通过“点”提示来调用它的功能 
     Debug.Print Application.Presentations.Count 
     ' 我们可以指定一个特定的对象 
 
    Debug.Print Application.Presentations(1).Name 
 
  
 
    ' 所以说 PowerPoint (即 application 对象) 包含 Presentations 对象 
 
    ' Presentations 包含 Slides 对象 
 
    ' Slides 包含 Shapes 对象,如 rectangles 和 circles。 
 
    ' 所以我们可以自然的这样写: 
 
    Debug.Print Application.ActivePresentation.Slides(2).Shapes.Count 
 
  
 
    ' 但是这么长的引用有些令人乏味 
 
    ' 另一种形式对我们来说更容易一些同时也会让 PowerPoint 处理的更快一些 
 
    ' 使用 With 关键字来引用你用的对象.. 
 
    With ActivePresentation.Slides(2).Shapes(2) 
 
        ' 这样你可以直接引用他的下级功能 
 
 
 
        Debug.Print .Name 
 
        Debug.Print .Height 
 
        Debug.Print .Width 
 
    ' 最后用 End With 关键字来表明引用完毕 
 
    End With 
 
  
 
    ' 我们也可以嵌套着使用 
 
    With ActivePresentation.Slides(2).Shapes(2) 
 
        Debug.Print .Name 
 
        With .TextFrame.TextRange 
 
            Debug.Print .Text 
 
            Debug.Print .Font.Name 
 
        End With 
 
    End With 
 
  
 
End Sub 
 
  
 
  
 
Sub PowerPointBasics_2() 
 
    ' 控制当前选中的对象 
 
  
 
    ' 显示对象的名字 
 
 
 
    With ActiveWindow.Selection.ShapeRange(1) 
 
        Debug.Print .Name 
 
    End With 
 
  
 
    ' 更改名字并移动他: 
 
    With ActiveWindow.Selection.ShapeRange(1) 
 
        ' 命名对象非常有用 
 
        .Name = "My favorite shape" 
 
        .Left = .Left + 72  ' 72 像素即 1 英寸 
 
    End With 
 
  
 
End Sub 
 
  
 
Sub PowerPointBasics_3() 
 
    ' 控制一个已命名的对象 
 
    ' 如果你知道一个对象的名字 
 
    ' 你就可以直接控制他 
 
    ' 不需要繁琐的调用了。 
 
  
 
    With ActivePresentation.Slides(2).Shapes("My favorite shape") 
 
        .Top = .Top - 72 
 
    End With 
 
 
 
  
 
    ' 每页幻灯片也可以有名字 
 
    With ActivePresentation.Slides(2) 
 
        .Name = "My favorite slide" 
 
    End With 
 
  
 
    ' 无论我们移动他到那个地方,名字不变 
 
    ' 这样我们就可以方便的操作啦 
 
    With ActivePresentation.Slides("My favorite slide").Shapes("My favorite shape") 
 
        .Height = .Height * 2 
 
    End With 
 
  
 
End Sub 
 
  
 
Sub PowerPointBasics_4() 
 
    ' 对象的引用 
 
  
 
    ' 可以通过变量来保持对对象的引用 
 
    ' 可能会有些难于理解,不过不用担心 
 
    ' 参照实例很容易理解的。 
 
  
 
    ' 先看下面的例子: 
 
 
 
  
 
    ' 定义一个变量为某个类型 
 
    Dim oShape As Shape 
 
  
 
    ' 让他指向某个特定的对象 
 
    Set oShape = ActivePresentation.Slides("My favorite slide").Shapes("My favorite shape") 
 
    ' 注意我们使用已命名的对象。 
 
  
 
    ' 从现在开始,我们就可以把 oShape 认作为我们命名的那个对象。 
 
    Debug.Print oShape.TextFrame.TextRange.Text 
 
    oShape.TextFrame.TextRange.Font.Color.RGB = RGB(255, 0, 0) 
 
    ' 直到我们删除这个变量,都可以认为他就是我们命名的那个对象。 
 
  
 
    Set oShape = Nothing 
 
  
 
End Sub 
 
  
 
Sub PowerPointBasics_5() 
 
    ' 遍历所有的幻灯片 
 
    ' 便利所有的对象 
 
  
 
    ' So far, we haven't done anything you couldn't do 
 
 
 
    ' with your mouse, and do it more easily at that. 
 
    ' One more little lesson, then the real fun starts. 
 
  
 
    Dim x As Long   ' we'll use X as a counter 
 
    ' OK, I said always to give variables meaningful names 
 
    ' But for little "throwaway" jobs like this, programmers often 
 
    ' use x, y, and the like 
 
  
 
    ' Let's do something with every slide in the presentation 
 
    For x = 1 To ActivePresentation.Slides.Count 
 
        Debug.Print ActivePresentation.Slides(x).Name 
 
    Next x 
 
  
 
    ' Or with every shape on one of the slides 
 
    ' Since x is a "junk" variable, we'll just re-use it here 
 
    ' And we'll use the With syntax to save some typing 
 
    With ActivePresentation.Slides(3) 
 
        For x = 1 To .Shapes.Count 
 
            Debug.Print .Shapes(x).Name 
 
        Next x 
 
    End With  ' ActivePresentation.Slides(3) 
 
  
 
 
 
End Sub 
 
  
 
Sub PowerPointBasics_6() 
 
    ' 处理异常错误 
 
  
 
    ' You can trust computer users to do one thing and one thing only: 
 
    '           The Unexpected 
 
    ' You can trust computers to do pretty much the same 
 
  
 
    ' That's where error handling comes in 
 
  
 
    ' What do you think will happen when I run this code? 
 
    With ActivePresentation.Slides(42) 
 
        MsgBox ("Steve, you moron, there IS no slide 42!") 
 
    End With 
 
  
 
End Sub 
 
  
 
Sub PowerPointBasics_6a() 
 
    ' Error Handling Continued 
 
  
 
    ' Let's protect our code against boneheaded Steves 
 
 
 
    ' If he does something that provokes an error, deal with it gracefully 
 
    On Error GoTo ErrorHandler 
 
  
 
    With ActivePresentation.Slides(42) 
 
        MsgBox ("Steve, you moron, there IS no slide 42!") 
 
    End With 
 
  
 
' Words with a : at the end are "labels" 
 
' and can be the destination of a "GoTo" command 
 
' Using GoTo is considered Very Bad Form except in error handlers 
 
  
 
' If we got here without error we need to quit before we hit the error 
 
' handling code so ... 
 
NormalExit: 
 
    Exit Sub 
 
  
 
ErrorHandler: 
 
    MsgBox ("Error: " & Err.Number & vbCrLf & Err.Description) 
 
    ' resume next 
 
    ' exit sub 
 
    Resume NormalExit 
 
  
 
 
 
End Sub 
 
  
 
Option Explicit  
 
Public strText As String  
 
Public strOption As String  
 
  
 
Sub Forms_1()  
 
    ' Creating/Showing/Unloading a form  
 
  
 
    ' Forms are a more sophisticated way of getting user input than  
 
    ' simple InputBox commands  
 
  
 
    ' For example:  
 
    frmMyForm1.Show  
 
  
 
    ' now the user has dismissed the form  
 
    ' let's see what they entered  
 
  
 
    Debug.Print frmMyForm1.TextBox1.Text  
 
  
 
    If frmMyForm1.OptionButton1.Value = True Then  
 
        Debug.Print "Yes"  
 
 
 
    End If  
 
    If frmMyForm1.OptionButton2.Value = True Then  
 
        Debug.Print "Chocolate"  
 
    End If  
 
    If frmMyForm1.OptionButton3.Value = True Then  
 
        Debug.Print "Teal"  
 
    End If  
 
  
 
    ' we're done with the form so unload it  
 
    Unload frmMyForm1  
 
  
 
    ' But what if we want to make the form data available until much later?  
 
    ' And wouldn't it make more sense to keep all the form's logic  
 
    ' in the form itself?  
 
  
 
End Sub  
 
  
 
Sub Forms_2()  
 
    ' This uses a form with the logic built in  
 
    ' Note that we had to declare a few PUBLIC variables  
 
    ' so the form could get at them  
 
  
 
 
 
    frmMyForm2.Show  
 
  
 
    ' we're done with the form so unload it  
 
    Unload frmMyForm2  
 
  
 
    ' let's see what they entered - our variables still have the values  
 
    ' the form code assigned them:  
 
    Debug.Print strText  
 
    Debug.Print strOption  
 
  
 
    ' CODE RE-USE  
 
    ' We can export the form to a file and import it into other projects  
 
  
 
End Sub 
 
  
 
This is the code from the Animation Tricks section of the seminar (modAnimationTricks)  
 
  
 
  
 
Option Explicit  
 
  
 
' This tells VBA how to call on the Windows API Sleep function  
 
' This function puts our VBA code to sleep for X milliseconds  
 
 
 
' (thousandths of a second) then lets it wake up after that  
 
' Unlike other ways of killing time, this doesn't hog computer cycles  
 
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)  
 
  
 
Sub xYouClicked(oSh As Shape)  
 
    Dim oShThought As Shape  
 
    Set oShThought = oSh.Parent.Shapes("Thought")  
 
  
 
    ' Make the thought balloon visible  
 
    oShThought.Visible = True  
 
    ' Move it to just to the right of the clicked shape  
 
    oShThought.Left = oSh.Left + oSh.Width  
 
    ' Position it vertically just above the clicked shape  
 
    oShThought.Top = oSh.Top - oShThought.Height  
 
  
 
    Select Case UCase(oSh.Name)  
 
        Case Is = "EENIE"  
 
            oShThought.TextFrame.TextRange.Text = "Pest!"  
 
        Case Is = "MEENIE"  
 
            oShThought.TextFrame.TextRange.Text = "This is annoying!"  
 
        Case Is = "MINIE"  
 
            oShThought.TextFrame.TextRange.Text = "This is REALLY annoying!!"  
 
 
 
        Case Is = "MOE"  
 
            oShThought.Visible = False  
 
            oSh.Parent.Shapes("STOP").Visible = True  
 
    End Select  
 
  
 
End Sub  
 
  
 
Sub yYouClicked(oSh As Shape)  
 
    ' This time we'll use tags to make it easier to maintain  
 
  
 
    Dim oShThought As Shape  
 
    Set oShThought = oSh.Parent.Shapes("Thought")  
 
  
 
    ' Make the thought balloon visible and move it next to the  
 
    ' shape the user just clicked  
 
    oShThought.Visible = True  
 
    oShThought.Left = oSh.Left + oSh.Width  
 
    oShThought.Top = oSh.Top - oShThought.Height  
 
  
 
    ' Use tags to pick up the text  
 
    oShThought.TextFrame.TextRange.Text = oSh.Tags("Thought")  
 
  
 
 
 
End Sub  
 
  
 
Sub AddATag()  
 
    ' A little macro to add a tag to the selected shape  
 
    Dim strTag As String  
 
  
 
    ' Our old buddy InputBox gets the tag text ...  
 
    strTag = InputBox("Type the text for the thought balloon", "What is the shape thinking?")  
 
  
 
    ' Instead of forcing user to enter something, we'll just quit  
 
    ' if not  
 
    If strTag = "" Then  
 
        Exit Sub  
 
    End If  
 
  
 
    ' Must have entered something, so tag the shape with it  
 
    With ActiveWindow.Selection.ShapeRange(1)  
 
        .Tags.Add "Thought", strTag  
 
    End With  
 
End Sub  
 
  
 
Sub YouClicked(oSh As Shape)  
 
 
 
    ' And now we'll add a WinAPI Sleep call to make it even smoother  
 
  
 
    Dim oShThought As Shape  
 
    Set oShThought = oSh.Parent.Shapes("Thought")  
 
  
 
    ' Use tags to pick up the text  
 
    oShThought.TextFrame.TextRange.Text = oSh.Tags("Thought")  
 
  
 
    ' Make the thought balloon visible and move it next to the  
 
    ' shape the user just clicked  
 
    oShThought.Left = oSh.Left + oSh.Width  
 
    oShThought.Top = oSh.Top - oShThought.Height  
 
    oShThought.Visible = True  
 
  
 
    ' give the system a little time to redraw  
 
    DoEvents  
 
  
 
    ' Now wait a second (1000 milliseconds to be precise) ...  
 
    Sleep 1000  
 
    ' and make it invisible again  
 
    oShThought.Visible = False  
 
  
 
 
 
End Sub  
 
  
 
  
 
Sub Reset()  
 
    ' Re-bait our little trap so it's ready for the next  
 
    ' unwary user  
 
    ActivePresentation.Slides("AnimationTricks").Shapes("STOP").Visible = False  
 
    ActivePresentation.Slides("AnimationTricks").Shapes("Thought").Visible = False  
 
End Sub 
 
  
 
  
 
This is the code from the Mass Quantities section of the seminar (modMassQuantities) that deals 
with automating actions across many slides or many presentations.  
 
  
 
  
 
Option Explicit  
 
  
 
Sub GreenToRed()  
 
    ' Object variables for Slides and Shapes  
 
    Dim oSh As Shape  
 
    Dim oSl As Slide  
 
  
 
    For Each oSl In ActivePresentation.Slides  
 
 
 
        For Each oSh In oSl.Shapes  
 
            If oSh.Fill.ForeColor.RGB = RGB(0, 255, 0) Then  
 
                oSh.Fill.ForeColor.RGB = RGB(255, 0, 0)  
 
            End If  
 
        Next oSh  
 
    Next oSl  
 
  
 
End Sub  
 
  
 
Sub FolderFull()  
 
    ' For each presentation in a folder that matches our specifications  
 
    '   - open the file  
 
    '   - call another subroutine that does something to it  
 
    '   - save the file  
 
    '   - close the file  
 
  
 
    Dim strCurrentFile As String    ' variable to hold a single file name  
 
    Dim strFileSpec As String       ' variable to hold our file spec  
 
    ' give it a value that works for my computer:  
 
    strFileSpec 
= 
"C:\Documents 
and 
Settings\Stephen 
Rindsberg\Desktop\PPTLive\Automation\LotsOfFiles\*.ppt"  
 
  
 
 
 
    ' get the first file that matches our specification  
 
    strCurrentFile = Dir$(strFileSpec)  
 
  
 
    ' don't do anything if we didn't find any matching files  
 
    ' but if we did, keep processing files until we don't find any more  
 
    While Len(strCurrentFile) > 0  
 
        ' open the presentation  
 
        Presentations.Open (strCurrentFile)  
 
  
 
        ' by changing this next line to call a different subroutine  
 
        ' you can have this same code do other tasks  
 
        Debug.Print ActivePresentation.Name  
 
  
 
        ' call the Green to Red macro to process the file  
 
        Call GreenToRed  
 
  
 
        ' save the file under a new name with FIXED_ at the beginning  
 
        ActivePresentation.SaveAs (ActivePresentation.Path & "\" _  
 
            & "Fixed_" _  
 
            & ActivePresentation.Name)  
 
  
 
        ' close it  
 
 
 
        ActivePresentation.Close  
 
        ' and get the next file that matches our specification  
 
        ' if you don't supply a new file spec, Dir$ returns the next  
 
        ' file that matches the previously supplied specification  
 
        strCurrentFile = Dir$  
 
    Wend  
 
  
 
    ' Note: Don't use Dir in code that's called from within a loop  
 
    ' that uses Dir - only one "Dir" can be "active" at a time.  
 
    ' In production code, it's best to keep it in a very short loop or  
 
    ' to collect file names in a short loop then process them after  
 
    ' Arrays are useful for this  
 
  
 
End Sub 
 
  
 
Misc. Example code from the seminar (modMiscExamples)  
 
  
 
  
 
  
 
Option Explicit  
 
  
 
Sub FolderFullFromArray()  
 
 
 
    ' Uses array to collect filenames for processing  
 
    ' This is more reliable than processing the files within a loop  
 
    ' that includes DIR  
 
  
 
    Dim rayFileNames() As String  
 
    Dim strCurrentFile As String    ' variable to hold a single file name  
 
    Dim strFileSpec As String       ' variable to hold our file spec  
 
    ' give it a value that works for my computer:  
 
    strFileSpec 
= 
"C:\Documents 
and 
Settings\Stephen 
Rindsberg\Desktop\PPTLive\Automation\LotsOfFiles\*.ppt"  
 
  
 
    ' Redimension the array to 1 element  
 
    ReDim rayFileNames(1 To 1) As String  
 
  
 
    ' get the first file that matches our specification  
 
    strCurrentFile = Dir$(strFileSpec)  
 
  
 
    ' don't do anything if we didn't find any matching files  
 
    ' but if we did, keep processing files until we don't find any more  
 
    While Len(strCurrentFile) > 0  
 
        ' Add it to the array  
 
        rayFileNames(UBound(rayFileNames)) = strCurrentFile  
 
        strCurrentFile = Dir  
 
 
 
        ' redimension the array  
 
        ReDim Preserve rayFileNames(1 To UBound(rayFileNames) + 1) As String  
 
    Wend  
 
  
 
    ' If there were no files, the array has one element  
 
    ' If it has more than one element, the last element is blank  
 
    If UBound(rayFileNames) > 1 Then  
 
        ' lop off the last, empty element  
 
        ReDim Preserve rayFileNames(1 To UBound(rayFileNames) - 1) As String  
 
    Else  
 
        ' no files found  
 
        Exit Sub  
 
    End If  
 
  
 
    ' If we got this far, we have files to process in the array so  
 
    Dim x As Long  
 
  
 
    For x = 1 To UBound(rayFileNames)  
 
  
 
        ' open the presentation  
 
        Presentations.Open (rayFileNames(x))  
 
        Debug.Print ActivePresentation.Name  
 
 
 
  
 
        ' call the Green to Red macro to process the file  
 
        Call GreenToRed  
 
  
 
        ' save the file under a new name with FIXED_ at the beginning  
 
        ActivePresentation.SaveAs (ActivePresentation.Path & "\" _  
 
            & "Fixed_" _  
 
            & ActivePresentation.Name)  
 
  
 
        ' close it  
 
        ActivePresentation.Close  
 
    Next x  
 
  
 
End Sub 
 
  
 
This is the code from the Macro Recorder demonstration  
 
  
 
  
 
The Macro Recorder is handy for little quickie macros and especially for learning how 
PowerPoint's object model works, but it doesn't produce code that's very useful as is.  
 
  
 
  
 
 
 
This demonstrates how you can make the recorder produce more useful code and how you can 
take what you've learned from it and tweak it into something more generally useful.  
 
  
 
  
 
Suppose the corporate colors have just changed from green to red. You've got dozens or hundreds 
of presentations with the fills set to the old green and need to change them all. Fast.  
 
  
 
  
 
You open one in PPT and record a macro while you select a shape and change its color from green 
to red.  
 
Here's what you end up with:  
 
  
 
  
 
Sub Macro1()  
 
  
 
    ActiveWindow.Selection.SlideRange.Shapes("Rectangle 5").Select  
 
    With ActiveWindow.Selection.ShapeRange  
 
        .Fill.Visible = msoTrue  
 
        .Fill.ForeColor.RGB = RGB(255, 0, 102)  
 
        .Fill.Solid  
 
    End With  
 
    ActivePresentation.ExtraColors.Add RGB(Red:=255, Green:=0, Blue:=102)  
 
  
 
End Sub  
 
 
 
  
 
This has a few problems:  
 
  
 
It only works IF there's a shape named "Rectangle 5" on the current slide   
 
It will only change a shape by that name, no other   
 
It changes things we may not WANT changed (.Fill.Solid, .Fill.Visible)   
 
It adds extra colors to the PPT palette (.ExtraColors)   
 
  
 
In short, it solves the problem of changing ONE shape on ONE slide from green to red. And that's 
it. And it creates other potential problems in the process.  
 
  
 
  
 
But it did show us how to change a shape's color in PowerPoint VBA, so it's not totally useless.  
 
  
 
  
 
Let's see if we can get it to do something more general.  
 
Select the green rectangle first, THEN record a macro while changing it to red:  
 
  
 
  
 
Sub Macro2()  
 
  
 
    With ActiveWindow.Selection.ShapeRange  
 
 
 
        .Fill.ForeColor.RGB = RGB(255, 0, 102)  
 
        .Fill.Visible = msoTrue  
 
        .Fill.Solid  
 
    End With  
 
  
 
End Sub  
 
  
 
That's better. A lot better. It works on any selected shape and in fact it works on multiple selected 
shapes.  
 
It still sets a few extra properties but we can comment those out.  
 
Now you can select all the shapes on each slide, run this macro and ...  
 
  
 
  
 
No. Don't do that. It'll change all the green selected shapes to red, true. Also all the blue ones and 
purple ones and so on. ALL the selected shapes.  
 
  
 
  
 
So you still have to go from slide to slide selecting all (and ONLY) the green shapes, then running 
the macro again and again.  
 
  
 
  
 
Enough of this. Here's how you and the other VBA Pros really do this kind of stuff:  
 
  
 
  
 
 
 
Sub GreenToRed()  
 
  
 
    Dim oSh As Shape  
 
    Dim oSl As Slide  
 
  
 
    ' Look at each slide in the current presentation:  
 
    For Each oSl In ActivePresentation.Slides  
 
  
 
        ' Look at each shape on each slide:  
 
        For Each oSh In oSl.Shapes  
 
  
 
            ' IF the shape's .Fill.ForeColor.RGB = pure green:  
 
            If oSh.Fill.ForeColor.RGB = RGB(0, 255, 0) Then  
 
  
 
                ' Change it to red  
 
                oSh.Fill.ForeColor.RGB = RGB(255, 0, 0)  
 
  
 
            End If  
 
  
 
        Next oSh  
 
  
 
    Next oSl  
 
 
 
  
 
End Sub  
 
  
 
In less time than it takes you to get your finger off the mouse button, that will change thousands of 
shapes on hundreds of slides from green to red. And it only touches the shapes that are the exact 
shade of green we've targeted, no other colors.  
 
Is it safe to touch the text? 
Not all shapes can have text. If you try to access a text property of one of these, PowerPoint errors 
out. 
In addition, some shapes created by PowerPoint 97 can be corrupted to the point where, though 
they have the ability to hold text, they cause errors if you try to check for the text. 
 
 
This is kind of a safety check function. It tests the various things that might cause errors and 
returns True if none of them actually cause errors. 
 
 
Public Function IsSafeToTouchText(pShape As Shape) As Boolean 
 
 On Error GoTo Errorhandler 
 
 If pShape.HasTextFrame Then 
  If pShape.TextFrame.HasText Then 
   ' Errors here if it's a bogus shape:  
   If Len(pShape.TextFrame.TextRange.text) > 0 Then 
    ' it's safe to touch it 
    IsSafeToTouchText = True 
    Exit Function 
   End If ' Length > 0 
  End If ' HasText 
 End If ' HasTextFrame 
 
Normal_Exit: 
 IsSafeToTouchText = False 
 Exit Function 
 
Errorhandler: 
 IsSafeToTouchText = False 
 Exit Function 
 
 
 
End Function 
 
 
What's the path to the PPA (add-in) file?  
 
If your add-in requires additional files, you'll probably keep them in the same folder as the add-in 
itself.  
 
  
 
  
 
Ah, but where's that? A user might install an add-in from anywhere on the local hard drive or even 
from a network drive, so you can't be certain where the add-in and its associated files are. At least 
not without this:  
 
  
 
  
 
Public Function PPAPath(AddinName as String) As String  
 
' Returns the path to the named add-in if found, null if not  
 
' Dependencies:  SlashTerminate (listed below, explained later)  
 
  
 
       Dim x As Integer  
 
       PPAPath = ""  
 
  
 
       For x = 1 To Application.AddIns.count  
 
              If UCase(Application.AddIns(x).Name) = UCase(AddinName) Then  
 
                     ' we found it, so  
 
                     PPAPath = Application.AddIns(x).path & GetPathSeparator  
 
                     ' no need to check any other addins  
 
 
 
                     Exit Function  
 
              End If  
 
       Next x  
 
  
 
       ' So we can run it from a PPT in the IDE instead of a PPA:  
 
       If PPAPath = "" Then  
 
              PPAPath = SlashTerminate(ActivePresentation.path)  
 
       End If  
 
  
 
End Function  
 
  
 
Function SlashTerminate(sPath as String) as String  
 
' Returns a string terminated with a path separator character  
 
' Works on PC or Mac  
 
  
 
       Dim PathSep As String  
 
       #If Mac Then  
 
              PathSep = ":"  
 
       #Else  
 
              PathSep = "\"  
 
       #End If  
 
  
 
 
 
       ' Is the rightmost character a backslash?  
 
       If Right$(sPath,1) <> PathSep Then  
 
              ' No; add a backslash  
 
              SlashTerminate = sPath & PathSep  
 
       Else  
 
              SlashTerminate = sPath  
 
       End If  
 
  
 
End Function