从命令行或批处理文件运行Excel宏的方法是什么?

83

我有一个Excel VBA宏,需要在从批处理文件访问文件时运行,但不是每次打开文件时都要运行(因此不使用打开文件事件)。有没有办法从命令行或批处理文件中运行宏?我不熟悉这样的命令。

假设您的环境是Windows NT。


1
使用vbscript/jscript和Windows脚本宿主是一个选择吗? - madaboutcode
11个回答

90

你可以使用VBScript文件启动Excel,打开工作簿并运行宏。

将下面的代码复制到记事本中。

更新“MyWorkbook.xls”和“MyMacro”参数。

将其保存为vbs扩展名,并运行它。

Option Explicit

On Error Resume Next

ExcelMacroExample

Sub ExcelMacroExample() 

  Dim xlApp 
  Dim xlBook 

  Set xlApp = CreateObject("Excel.Application") 
  Set xlBook = xlApp.Workbooks.Open("C:\MyWorkbook.xls", 0, True) 
  xlApp.Run "MyMacro"
  xlApp.Quit 

  Set xlBook = Nothing 
  Set xlApp = Nothing 

End Sub 

运行宏的关键代码是:

xlApp.Run "MyMacro"


11
这正是我在寻找的!它起作用了。但是,为了使其无故障运行,我需要添加一些更改:
  1. 它应该是“xlApp.Run”。
  2. 在退出之前,应使用“xlApp.SaveAs”,否则宏所做的修改将不会保存。(可以使用“xlApp.DisplayAlerts = False” 避免相关弹出窗口)
  3. 在退出之前,应调用“xlApp.ActiveWorkbook.Close”,否则电子表格将保持打开状态(虽然是隐藏的),这会禁用进一步编辑。
总的来说,这正是我在寻找的 :)
- Polymeron
1
还要考虑添加 xlApp.Visible = True,否则您将看不到Excel或任何可能出现的对话框。 - Rachel Hettinger
1
当我逐字运行此脚本时,进程“EXCEL.exe”不会关闭。 - André C. Andersen
1
@Robert Mearns 我使用了这个VBS以批处理模式运行一个宏(该宏在交互模式下完美运行)。我运行了这个VBS,但是没有任何响应。我怀疑Set xlApp = CreateObject("Excel.Application")在我的系统上无法工作。您能否指导我如何使其正常工作? - Mubeen Shahid
如果您的Excel文件受到密码保护,并且您想以读写方式打开它,您需要如何调整您的代码? - Jason Samuels
显示剩余4条评论

25

最简单的方法是:

1)从批处理文件启动Excel,打开包含宏的工作簿:

EXCEL.EXE /e "c:\YourWorkbook.xls"

2) 在工作簿的 Workbook_Open 事件中调用你的宏,例如:

Private Sub Workbook_Open()
    Call MyMacro1          ' Call your macro
    ActiveWorkbook.Save    ' Save the current workbook, bypassing the prompt
    Application.Quit       ' Quit Excel
End Sub

现在这将会把控制权返回给你的批处理文件去执行其他操作。


3
考虑到这一点,即使我没有通过批处理文件打开它,它也会运行,这将导致在未禁用宏的情况下无法使用该文件本身。 - Polymeron
1
这个问题可以通过修改注册表设置来解决,该设置告诉Excel所设置的安全级别。 - bvukas
当然,使用数字签名工作簿总是有帮助的,即使只是测试证书 :) - bvukas
1
有没有其他方法可以不用Excel来完成这个任务呢?我的意思是,有没有其他更专门的程序可以快速从命令行执行宏? - skan
2
如果我以后需要更改某些内容,但不想运行宏,该如何打开文件? - wviana

7
下面的方法可以从批处理文件中运行定义的Excel宏,它使用环境变量将宏名称从批处理传递到Excel。
将此代码放入批处理文件中(使用您的路径到EXCEL.EXE和工作簿):
Set MacroName=MyMacro
"C:\Program Files\Microsoft Office\Office15\EXCEL.EXE" "C:\MyWorkbook.xlsm"

将以下代码放入Excel VBA的ThisWorkBook对象中:

Private Sub Workbook_Open()
    Dim strMacroName As String
    strMacroName = CreateObject("WScript.Shell").Environment("process").Item("MacroName")
    If strMacroName <> "" Then Run strMacroName
End Sub

将您的代码放入Excel VBA模块中,如下所示:

Sub MyMacro()
    MsgBox "MyMacro is running..."
End Sub

运行批处理文件并获取结果:

宏对话框

如果您不打算运行任何宏,请在批处理中将值为空Set MacroName=


5
你可以编写VBScript通过CreateObject()方法创建Excel实例,然后打开工作簿并运行宏。你可以直接调用VBScript或从批处理文件中调用VBScript。
这里是我刚刚发现的一个资源: http://www.codeguru.com/forum/showthread.php?t=376401

4
如果您更喜欢使用Excel/VBA进行工作,可以使用打开事件并测试环境:可以有一个信号文件、注册表条目或控制打开事件的环境变量。您可以在外部创建文件/设置,然后在内部进行测试(使用GetEnviromentVariable获取env-vars)并轻松测试。我已经编写了VBScript,但与VBA的相似之处使我感到更加焦虑而不是放心。
根据我的理解,您想要大部分/部分时间正常使用电子表格,但希望它可以批处理并执行某些额外/不同的操作。您可以从excel.exe命令行打开该表格,但除非它知道位置否则无法控制它所做的内容。使用环境变量相对简单,并且使测试电子表格变得容易。请使用下面的函数来检查环境。在模块中声明:
Private Declare Function GetEnvVar Lib "kernel32" Alias "GetEnvironmentVariableA" _
    (ByVal lpName As String, ByVal lpBuffer As String, ByVal nSize As Long) As Long

Function GetEnvironmentVariable(var As String) As String
Dim numChars As Long

    GetEnvironmentVariable = String(255, " ")

    numChars = GetEnvVar(var, GetEnvironmentVariable, 255)

End Function

在工作簿打开事件中(与其他事件一样):
Private Sub Workbook_Open()
    If GetEnvironmentVariable("InBatch") = "TRUE" Then
        Debug.Print "Batch"
    Else
        Debug.Print "Normal"
    End If
End Sub

根据需要添加活动代码。在批处理文件中,使用以下命令:

set InBatch=TRUE

内置的environ函数也可以工作吗?Environ("InBatch") - Gregor y

3

我一直在Workbook_Open()函数中测试打开的工作簿数量。如果是1,则说明该工作簿是通过命令行打开的(或者用户关闭了所有工作簿,然后打开了这个)。

If Workbooks.Count = 1 Then

    ' execute the macro or call another procedure - I always do the latter  
    PublishReport

    ThisWorkbook.Save

    Application.Quit

End If

3

不要直接比较字符串(VB不会认为它们相等,因为GetEnvironmentVariable返回长度为255的字符串),请写成这样:

Private Sub Workbook_Open()     
    If InStr(1, GetEnvironmentVariable("InBatch"), "TRUE", vbTextCompare) Then
        Debug.Print "Batch"  
        Call Macro
    Else    
        Debug.Print "Normal"     
    End If 

End Sub 

1
我通常将宏存储在与工作簿分开的xlam 加载项中,因此我想打开一个工作簿,然后运行存储在另外地方的宏。由于这需要一个VBS脚本,我想使其“便携”,以便可以通过传递参数使用它。这是最终脚本,它需要3个参数。
  • 工作簿的完整路径
  • 宏名称
  • [可选] 包含宏的单独工作簿的路径

我这样测试它:

"C:\Temp\runmacro.vbs" "C:\Temp\Book1.xlam" "Hello"

"C:\Temp\runmacro.vbs" "C:\Temp\Book1.xlsx" "Hello" "%AppData%\Microsoft\Excel\XLSTART\Book1.xlam"

runmacro.vbs:

Set args = Wscript.Arguments

ws = WScript.Arguments.Item(0)
macro = WScript.Arguments.Item(1)
If wscript.arguments.count > 2 Then
 macrowb= WScript.Arguments.Item(2)
End If

LaunchMacro

Sub LaunchMacro() 
  Dim xl
  Dim xlBook  

  Set xl = CreateObject("Excel.application")
  Set xlBook = xl.Workbooks.Open(ws, 0, True)
  If wscript.arguments.count > 2 Then
   Set macrowb= xl.Workbooks.Open(macrowb, 0, True)
  End If
  'xl.Application.Visible = True ' Show Excel Window
  xl.Application.run macro
  'xl.DisplayAlerts = False  ' suppress prompts and alert messages while a macro is running
  'xlBook.saved = True ' suppresses the Save Changes prompt when you close a workbook
  'xl.activewindow.close
  xl.Quit

End Sub 

1

@ Robert: 我尝试使用相对路径调整了您的代码,并创建了一个批处理文件来运行VBS。

VBS可以启动并关闭,但没有启动宏……不知道问题出在哪里?

Option Explicit

On Error Resume Next

ExcelMacroExample

Sub ExcelMacroExample() 

  Dim xlApp 
  Dim xlBook 

  Set xlApp = CreateObject("Excel.Application")
  Set objFSO = CreateObject("Scripting.FileSystemObject")
  strFilePath = objFSO.GetAbsolutePathName(".") 
  Set xlBook = xlApp.Workbooks.Open(strFilePath, "Excels\CLIENTES.xlsb") , 0, True) 
  xlApp.Run "open_form"


  Set xlBook = Nothing 
  Set xlApp = Nothing 

End Sub

我删除了“Application.Quit”,因为我的宏调用了一个用户窗体来处理它。
谢谢
编辑
实际上,我已经解决了这个问题,以防有人想要运行类似独立应用程序的用户窗体:
我面临的问题:
1- 我不想使用Workbook_Open事件,因为Excel被锁定为只读。 2- 批处理命令受到限制,即(据我所知)它不能调用宏。
我首先编写了一个启动我的用户窗体并隐藏应用程序的宏:
Sub open_form()
 Application.Visible = False
 frmAddClient.Show vbModeless
End Sub

然后我创建了一个vbs文件来启动这个宏(使用相对路径有些棘手):

dim fso
dim curDir
dim WinScriptHost
set fso = CreateObject("Scripting.FileSystemObject")
curDir = fso.GetAbsolutePathName(".")
set fso = nothing

Set xlObj = CreateObject("Excel.application")
xlObj.Workbooks.Open curDir & "\Excels\CLIENTES.xlsb"
xlObj.Run "open_form"

最终我编写了一个批处理文件来执行VBS脚本...

@echo off
pushd %~dp0
cscript Add_Client.vbs

请注意,我还在我的Userform_QueryClose中包含了“设置回可见”的内容。
Private Sub cmdClose_Click()
Unload Me
End Sub

Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
    ThisWorkbook.Close SaveChanges:=True
    Application.Visible = True
    Application.Quit
End Sub

无论如何,感谢您的帮助,我希望这会对需要帮助的人有所帮助。

1
我偏爱C#。我在linqpad中运行了以下代码。但是这也可以用csc编译并通过命令行调用运行。
不要忘记将Excel包添加到命名空间。
void Main()
{
    var oExcelApp = (Microsoft.Office.Interop.Excel.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application");
    try{
        var WB = oExcelApp.ActiveWorkbook;
        var WS = (Worksheet)WB.ActiveSheet;
        ((string)((Range)WS.Cells[1,1]).Value).Dump("Cell Value"); //cel A1 val
        oExcelApp.Run("test_macro_name").Dump("macro");
    }
    finally{
        if(oExcelApp != null)
            System.Runtime.InteropServices.Marshal.ReleaseComObject(oExcelApp);
        oExcelApp = null;
    }
}

我从未见过LINQPad或CSC,所以感谢您提供了一种独特的解决方案! - HackSlash

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接