2010-01-12 68 views
52

Tengo una macro de Excel VBA que necesito ejecutar cuando accedo al archivo desde un archivo de proceso por lotes, pero no cada vez que lo abro (de ahí que no utilice el evento de archivo abierto). ¿Hay alguna forma de ejecutar la macro desde la línea de comando o el archivo por lotes? No estoy familiarizado con tal comando.¿Cómo se ejecutan las macros de Excel desde la línea de comandos o el archivo por lotes?

Supongamos un entorno Windows NT.

+1

¿Está usando vbscript/jscript con Windows scripting host una opción? – madaboutcode

Respuesta

64

Puede iniciar Excel, abrir el libro de trabajo y ejecutar la macro desde un archivo VBScript.

Copie el código abajo en el Bloc de notas.

actualización de la 'MyWorkbook.xls' y 'MiMacro' parámetros.

Guárdelo con una extensión vbs y ejecútelo.

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 

La línea clave que se ejecuta la macro es:

xlApp.Run "MiMacro"

+8

¡Esto es lo que estaba buscando! Funciona. Debo añadir un par de cambios necesarios para que esto funcione sin problemas técnicos: 1. Es "xlApp.Run". 2. Antes de abandonar, se debe usar xlApp.SaveAs o no se guardarán las modificaciones realizadas por la macro. (se puede usar xlApp.DisplayAlerts = False) para evitar ventanas emergentes relacionadas. 3. Antes de cerrar, debe invocarse xlApp.ActiveWorkbook.Close o la hoja de cálculo permanece abierta (aunque oculta), lo que desactiva la edición posterior. En general, esto es lo que estaba buscando :) – Polymeron

+1

También considere agregar 'xlApp.Visible = True'; de lo contrario, no verá Excel ni ninguno de sus cuadros de diálogo que puedan aparecer. –

+1

El proceso 'EXCEL.exe' no se cierra cuando ejecuto este script textualmente. –

4

puede escribir un vbscript para crear una instancia de excel mediante el método createobject(), luego abra el libro de trabajo y ejecute la macro. Puede llamar a vbscript directamente o llamar a vbscript desde un archivo por lotes.

Aquí es un recurso Me tropecé al otro lado: http://www.codeguru.com/forum/showthread.php?t=376401

2

Si estás más cómodo trabajando dentro de Excel/VBA, utilice el evento abierto y probar el entorno: o bien tener un archivo de señal, una entrada de registro o una variable de entorno que controla lo que hace el evento abierto.

Puede crear el archivo/configuración afuera y probar el interior (use GetEnviromentVariable para env-vars) y realice pruebas fácilmente. He escrito VBScript, pero las similitudes con VBA me causa más angustia que la facilidad ..

[más]

Según entiendo el problema, desea utilizar una hoja de cálculo normalmente la mayor parte/parte del tiempo aún no se han se ejecuta en lote y hacer algo extra/diferente. Puede abrir la hoja desde la línea de comandos excel.exe pero no puede controlar lo que hace a menos que sepa dónde está. El uso de una variable de entorno es relativamente simple y facilita la prueba de la hoja de cálculo.

Para aclarar, utilice la función siguiente para examinar el entorno. En un declarar módulo:

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 

En el evento abierto libro de trabajo (como otros):

Private Sub Workbook_Open() 
    If GetEnvironmentVariable("InBatch") = "TRUE" Then 
     Debug.Print "Batch" 
    Else 
     Debug.Print "Normal" 
    End If 
End Sub 

Añadir en el código activo según sea el caso. En el archivo por lotes, utilice

set InBatch=TRUE 
14

La forma más sencilla de hacerlo es:

1) Iniciar Excel de su archivo por lotes para abrir el libro que contiene la macro:

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

2) Llame a su macro de evento del libro Workbook_Open, tales como:

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

Esto volverá ahora t él controla su archivo por lotes para hacer otro procesamiento.

+2

Pensé en eso, pero se ejecutaría incluso si no lo abría a través del archivo de proceso por lotes, lo que hace que el archivo sea imposible de usar sin deshabilitar primero las macros. – Polymeron

+1

Esto es fácil de resolver modificando una configuración de registro que le indica a Excel qué nivel de seguridad está configurado. – bvukas

+0

Por supuesto, la firma digital del libro de trabajo siempre ayuda, incluso con un certificado de prueba :) – bvukas

2

En lugar de comparar directamente las cuerdas (VB no encontrarlos igual desde GetEnvironmentVariable devuelve una cadena de longitud 255) escribir esto:

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 
2

que siempre han puesto a prueba el número de libros abiertos en Workbook_Open(). Si es 1, entonces el libro de trabajo fue abierto por la línea de comando (o el usuario cerró todos los libros de trabajo, luego abrió este).

If Workbooks.Count = 1 Then 

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

    ThisWorkbook.Save 

    Application.Quit 

End If 
2

@ Robert: Me han tratado de adaptar su código con una ruta relativa, y ha creado un archivo por lotes para ejecutar el EBV.

La VBS se inicia y se cierra pero no inicia la macro ... ¿Alguna idea de dónde podría estar el problema?

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 

He eliminado el "Application.Quit" porque mi macro está llamando a una forma de usuario que se encarga de ello.

Saludos

EDITAR

que realmente han trabajado a cabo, por si acaso alguien quiere ejecutar un formulario de usuario "igual" una aplicación independiente:

Problemas que estaba enfrentando:

1 - No quería utilizar el evento Workbook_Open ya que Excel está bloqueado en solo lectura. 2 - El comando por lotes está limitado por el hecho de que (que yo sepa) no puede llamar a la macro.

escribí por primera vez una macro para lanzar mi UserForm al tiempo que oculta la aplicación:

Sub open_form() 
Application.Visible = False 
frmAddClient.Show vbModeless 
End Sub 

Entonces creé un VBS para lanzar esta macro (hacerlo con una ruta relativa ha sido complicado):

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" 

Y finalmente hice un archivo por lotes para ejecutar el VBS ...

@echo off 
pushd %~dp0 
cscript Add_Client.vbs 

Tenga en cuenta que También he incluido el "Set de nuevo a visible" en mi 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 

De todos modos, gracias por su ayuda, y espero que esto ayudará si alguien lo necesita

0

Puede comprobar si Excel ya está abierto. No hay necesidad de crear otro isntance

If CheckAppOpen("excel.application") Then 
      'MsgBox "App Loaded" 
      Set xlApp = GetObject(, "excel.Application") 
    Else 
      ' MsgBox "App Not Loaded" 
      Set wrdApp = CreateObject(,"excel.Application") 
    End If 
0

Soy parcial a C#. Ejecuté lo siguiente usando linqpad. Pero podría compilarse fácilmente con csc y ​​ejecutar el llamado desde la línea de comando.

No olvide agregar paquetes de Excel al espacio de nombres.

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; 
    } 
} 
2

El método se muestra a continuación permite ejecutar macro Excel definido de archivo por lotes, que utiliza variable de entorno para pasar nombre de macro de lote a Excel.

poner este código al archivo por lotes (utilizar sus caminos a EXCEL.EXE y al libro):

Set MacroName=MyMacro 
"C:\Program Files\Microsoft Office\Office15\EXCEL.EXE" "C:\MyWorkbook.xlsm" 

Pon este código a Excel VBA ThisWorkbook del objeto:

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

y poner su código para Excel Módulo VBA, como el siguiente:

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

Ejecute el archivo por lotes y obtenga th resultado e:

macro's dialog

Para el caso en el que no tiene intención de ejecutar cualquier macro sólo hay que poner valor vacío Set MacroName= al lote.

Cuestiones relacionadas