Pergunta

Eu tenho uma macro do Excel VBA que preciso executar ao acessar o arquivo a partir de um arquivo em lote, mas nem toda vez que a abro (portanto, não usando o evento de arquivo aberto). Existe uma maneira de executar a macro a partir da linha de comando ou arquivo em lote? Não estou familiarizado com esse comando.

Assuma um ambiente Windows NT.

Foi útil?

Solução

Você pode iniciar o Excel, abrir a pasta de trabalho e executar a macro a partir de um arquivo VBScript.

Copie o código abaixo no bloco de notas.

Atualizar o 'Myworkbook.xls' e 'MymacroParâmetros.

Salve -o com uma extensão VBS e execute -o.

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 

A linha -chave que executa a macro é:

xlapp.run "mymacro"

Outras dicas

A maneira mais simples de fazer é:

1) Inicie o Excel do seu arquivo em lote para abrir a pasta de trabalho que contém sua macro:

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

2) Ligue para sua macro da pasta de trabalho Workbook_Open evento, 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

Isso agora retornará o controle ao seu arquivo em lote para fazer outro processamento.

O método mostrado abaixo permite executar a macro do Excel definida a partir do arquivo em lote, ele usa a variável de ambiente para passar o nome da macro do lote para o Excel.

Coloque este código no arquivo em lote (use seus caminhos para EXCEL.EXE e para a pasta de trabalho):

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

Coloque este código no objeto 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

E coloque seu código no Módulo VBA Excel, como a seguinte:

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

Inicie o arquivo em lote e obtenha o resultado:

macro

Para o caso, quando você não pretende executar nenhuma macro, basta colocar um valor vazio Set MacroName= para o lote.

Você pode escrever um VBScript para criar uma instância do Excel através do método createObject (), depois abrir a pasta de trabalho e executar a macro. Você pode ligar diretamente no VBScript ou ligar para o VBScript de um arquivo em lote.

Aqui está um recurso que acabei de tropeçar na Accross:http://www.codeguru.com/forum/showthread.php?t=376401

Eu sempre testei o número de pastas de trabalho abertas na Workbook_open (). Se for 1, a pasta de trabalho foi aberta pela linha de comando (ou o usuário fechou todas as pastas de trabalho e depois abriu esta).

If Workbooks.Count = 1 Then

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

    ThisWorkbook.Save

    Application.Quit

End If

Se você estiver mais confortável trabalhando dentro do Excel/VBA, use o evento aberto e teste o ambiente: tenha um arquivo de sinal, uma entrada de registro ou uma variável de ambiente que controla o que o evento aberto faz.

Você pode criar o arquivo/configuração do lado de fora e testar dentro (use GetenViromentVariable para Env-Vars) e teste com facilidade. Eu escrevi VBScript, mas as semelhanças com o VBA me causam mais angústia do que facilidade ..

mais

Pelo que entendi o problema, você deseja usar uma planilha normalmente a maioria/algumas vezes, mas a executa em lote e faça algo extra/diferente. Você pode abrir a folha da linha de comando do Excel.exe, mas não pode controlar o que ela faz, a menos que saiba onde está. O uso de uma variável de ambiente é relativamente simples e facilita o teste da planilha.

Para esclarecer, use a função abaixo para examinar o ambiente. Em um módulo declarar:

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

No evento aberto da pasta de trabalho (como outros):

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

Adicione o código ativo conforme aplicável. No arquivo em lote, use

set InBatch=TRUE

Em vez de comparar diretamente as strings (o VB não as encontrará iguais, pois GetenvironmentVariable retorna uma sequência de comprimento 255) Escreva este:

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 

@ Robert: Eu tentei adaptar seu código com um caminho relativo e criei um arquivo em lote para executar o VBS.

O VBS começa e fecha, mas não inicia a macro ... alguma idéia de onde o problema poderia estar?

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

Eu removi o "Application.quit" porque minha macro está chamando uma forma de usuário cuidando dele.

Felicidades

EDITAR

Na verdade, eu trabalhei, caso alguém queira executar um formulário de usuário "igualmente" um aplicativo independente:

Questões que eu estava enfrentando:

1 - Eu não queria usar o evento da ASSIM_OPEN, pois o Excel está bloqueado apenas na leitura. 2 - O comando em lote é limitado que o fato de que (a meu conhecimento) não pode chamar a macro.

Eu escrevi uma macro pela primeira vez para lançar minha forma de usuário ao ocultar o aplicativo:

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

Eu então criei um VBS para lançar esta macro (fazendo isso com um caminho relativo foi 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"

E finalmente fiz um arquivo em lote para executar o VBS ...

@echo off
pushd %~dp0
cscript Add_Client.vbs

Observe que eu também incluí o "Volto para Visível" no meu 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 qualquer forma, obrigado pela sua ajuda, e espero que isso ajude se alguém precisar

Você pode verificar se o Excel já está aberto. Não há necessidade de criar outro não é

   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

Eu sou parcial para C#. Eu executei o seguinte usando o Linqpad. Mas poderia facilmente ser compilado com o CSC e executado pela linha de comando chamado.

Não se esqueça de adicionar pacotes do Excel ao espaço para nome.

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;
    }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top