如何编写适用于多个Office应用程序的VBA代码

时间:2013-10-02 10:28:12

标签: vba excel-vba ms-word ms-office powerpoint-vba

我想编写一个适用于三个主要Office应用程序(Excel,PowerPoint,Word)的VBA代码模块。

由于每个应用程序中的对象模型不同,如果我在Excel VBE中编写特定于PowerPoint的代码,则项目将无法编译。首先出现的方法似乎是使用条件编译器常量。但这仍然会导致VBE吐出错误,具体取决于VBE当前所在的MSO应用程序。

在下面的简化示例中,我想将图片添加到工作表,幻灯片或文档中,具体取决于运行VBA代码的应用程序。如果我尝试在Excel中编译它,PowerPoint代码不会编译(即使它在条件编译器If ... Then语句中!),反之亦然。如何在不添加对其他MSO应用程序的引用的情况下解决这个问题(因为这会在分发到不同的MSO版本时导致兼容性问题)?

编译器继续查看应该被条件编译器常量“有效地”注释掉的代码的方式是非常奇怪/恼人的行为!

' Set the compiler constant depending on which MSO app is hosting the VBE
' before saving as the respective .ppam/.xlam/.dotm add-in
#Const APP = "EXL"

Option Explicit

Dim curSlide As Integer
Dim curSheet As Integer

Public Sub InsertPicture()
    Dim oShp as Shape
    #If APP = "PPT" Then
        ' Do PowerPoint stuff
        ' The next 2 lines will throw "Invalid qualifier" and
        ' "Variable not defined" errors respectively when compiling in Excel.
        curSlide = ActiveWindow.View.Slide.SlideIndex
        Set oShp = ActivePresentation.Slides(curSlide).Shapes.AddPicture & _
            (filename, msoFalse, msoTrue, 0, 0)
    #ElseIf APP = "EXL" Then
        ' Do Excel stuff
        curSheet = ActiveWindow.ActiveSheet
        Set oShp = ActiveSheet.AddPicture(filename, msoFalse, msoTrue, 0, 0)
    #ElseIf APP = "WRD" Then
        ' Do Word stuff
    #End If
End Sub

因为我无法回答我自己的问题:

扩展你的想法KazJaw,我认为这样的事情可能有效,用GetObject替换CreateObject函数(因为实例将在从加载项中调用过程后已经存在):

' CONDITIONAL COMPILER CONSTANTS
' Set this value before saving to .ppam, .xlam or .dotm
#Const APP = "EXL" ' Allowed Values : PPT, EXL or WRD

Sub One_Sub_For_Word_Excel_PP(filename As String, Optional SlideIndex as Integer)
    #If APP = "PPT" Then
        Dim appPPP As Object
        Set appPPT = GetObject(, "PowerPoint.Application")
        appPPT.ActivePresentation.Slides(SlideIndex).Shapes.AddPicture & _
            (filename,msoFalse,msoTrue,0,0)
    #ElseIf APP = "EXL" Then
        Dim appEXL As Object
        Set appEXL = GetObject(, "Excel.Application")
        appEXL.ActiveSheet.AddPicture(filename, msoFalse, msoTrue, 0, 0)
    #ElseIf APP = "WRD" Then
        Dim appWRD As Object
        Set appWRD = GetObject(, "Word.Application")
        appWRD.ActiveDocument.AddPicture(filename, msoFalse, msoTrue, 0, 0)
    #End If
End Sub

4 个答案:

答案 0 :(得分:1)

你可以尝试:

Public AppName as String
Public App as Object
Sub One_Sub_For_Word_Excel_PP(filename As String, Optional SlideIndex as Integer)
    AppName = Application.Name
    Set App = Application
    Select Case AppName
        Case "Microsoft PowerPoint"
            App.ActivePresentation.Slides(SlideIndex).Shapes.AddPicture & _
                (filename,msoFalse,msoTrue,0,0)

        Case "Microsoft Excel"
            App.ActiveSheet.AddPicture(filename, msoFalse, msoTrue, 0, 0)

        Case "Microsoft Word"
            App.ActiveDocument.AddPicture(filename, msoFalse, msoTrue, 0, 0)

      End Select
End Sub

或者,编写COM加载项。

答案 1 :(得分:0)

正如我在评论中所述 - 我无法想象我想要使用你想要准备的解决方案的情况。但是,即使您设置了许多限制(包括不设置对其他应用程序库的引用),也有一种解决方案。请记住,这样的尝试效率不高,我绝不会推荐这样的事情。

以下测试子程序适用于所有三个应用程序:MS Word,MS PowerPoint,MS Excel。代码中注释中的附加信息。

Sub One_Sub_For_Word_Excel_PP()

    Dim XLS As Object
    Dim PP As Object
    Dim WRD As Object

    'this will open instances of all application- to avoid any errors
    Set XLS = CreateObject("Excel.Application")
    Set PP = CreateObject("PowerPoint.Application")
    Set WRD = CreateObject("Word.Application")


    'your code here
    'remember- do not use vba constants like msoFalse but use _
     their numeric values instead

    'simple test
    If Application.Name = "Microsoft Excel" Then
        'do things only for excel
        Debug.Print XLS.Name
    ElseIf Application.Name = "Microsoft PowerPoint" Then
        'do things only for PP
        Debug.Print PP.Name
    Else
        'do things only for Word
        Debug.Print WRD.Name
    End If

    Set XLS = Nothing
    Set PP = Nothing
    Set WRD = Nothing
End Sub

答案 2 :(得分:0)

不是吗

#Const APP = "EXL"

#If APP = "PPT" Then

等?

答案 3 :(得分:0)

我假设您希望相同的代码能够在任何启用VBA的应用程序中运行(但不一定要调用其他应用程序)。所以...

Sub One_Sub_To_Rule_Them_All()
' Modified version of KazJaw's previous post

    Dim oApp As Object
    Set oApp = Application

    Select Case oApp.Name
        Case Is = "Microsoft Excel"
        'do things only for excel

        Case Is = "Microsoft PowerPoint"
        'do things only for PP, eg
           MsgBox oApp.ActivePresentation.Fullname

        Case Is = "Microsoft Word"
        ' do wordthings

        Case Is = "Visio or CorelDraw or Whatever"
        ' do whatever things

        Case Else
            MsgBox "Jumping up and down and waving hands and running around like headless chicken"

    End Select

    Set oApp = Nothing

End Sub

同样,我不会这样做。除了其他异议之外,您还需要将应用程序视为对象以便编译代码,并且当您这样做时,您需要抛弃智能感知。不是一个微不足道的损失。当然,你可以通过开发Word中的Word部分,PPT中的PPT部分来解决这个问题......但在这种情况下,为什么不制作单独的代码模块呢?