none
Verificação com VBA RRS feed

  • Pergunta

  • Olá galera! Eu aqui novamente pedindo um "help" para vocês (EvangelistLion! please!)...

    Então, estou com uma rotina aqui em VBA que envia alguns arquivos via FTP e depois ele deleta os mesmos, porém, estou tendo um problema, antes de ele terminar o envio dos arquivos o VBA já vai executando a SUB que é pra deletar os arquivos, ou seja, os arquivos são deletados antes de serem enviados por FTP (isso ocorre porque o VBA não espera a rotina FTP terminar para executar a outra SUB que é chamada, ele vai executando tudo que vê pela frente! E é lógico que a execução do VBA é bem mais rápido que o FTP), alguém poderia me dar um help com isso? Teria como fazer o VBA ver se o programa está executando (no caso o CMD > FTP) e só mandar a próxima instrução só se esse programa já estiver terminado? Ou sei lá, sugestões? Desde já agradeço!

    Obrigado! 
    segunda-feira, 9 de fevereiro de 2009 17:47

Respostas

  • Pessoal, resolvi o meu problema de uma maneira bem massa, usei umas propriedades do VBA para ver se o processo (no meu caso cmd.exe) está ativo, se ele está ativo ele da um sleep (usei uma outra função sleep que da um pause na aplicação e não aquela que você chama usa uma lib do kernel32) e verifica novamente, caso não esteja mais ativo ele parte para a próxima instrução, segue abaixo o código para quem precisar um dia:

    Option Explicit  
    Private Declare Function OpenProcess Lib "kernel32" ( _  
    ByVal dwDesiredAccess As LongByVal bInheritHandle As LongByVal dwProcessId As LongAs Long 
    Private Declare Function CloseHandle Lib "kernel32" ( _  
    ByVal hObject As LongAs Long 
    Private Declare Function EnumProcesses Lib "PSAPI.DLL" ( _  
    lpidProcess As LongByVal cb As Long, cbNeeded As LongAs Long 
    Private Declare Function EnumProcessModules Lib "PSAPI.DLL" ( _  
    ByVal hProcess As Long, lphModule As LongByVal cb As Long, lpcbNeeded As LongAs Long 
    Private Declare Function GetModuleBaseName Lib "PSAPI.DLL" Alias "GetModuleBaseNameA" ( _  
    ByVal hProcess As LongByVal hModule As LongByVal lpFileName As StringByVal nSize As LongAs Long 
    Private Const PROCESS_VM_READ = &H10  
    Private Const PROCESS_QUERY_INFORMATION = &H400  
     
    Private Function IsProcessRunning(ByVal sProcess As StringAs Boolean 
     
    Const MAX_PATH As Long = 260  
    Dim lProcesses() As Long, lModules() As Long, N As Long, lRet As Long, hProcess As Long 
    Dim sName As String 
     
    sProcess = UCase$(sProcess)  
     
    ReDim lProcesses(1023) As Long 
     
    verifyagain:  
    If EnumProcesses(lProcesses(0), 1024 * 4, lRet) Then 
        For N = 0 To (lRet \ 4) - 1  
            hProcess = OpenProcess(PROCESS_QUERY_INFORMATION Or PROCESS_VM_READ, 0, lProcesses(N))  
                If hProcess Then 
                    ReDim lModules(1023)  
                        If EnumProcessModules(hProcess, lModules(0), 1024 * 4, lRet) Then 
                            sName = String$(MAX_PATH, vbNullChar)  
                            GetModuleBaseName hProcess, lModules(0), sName, MAX_PATH  
                            sName = Left$(sName, InStr(sName, vbNullChar) - 1)  
                                If Len(sName) = Len(sProcess) Then 
                                    If sProcess = UCase$(sName) Then 
                                        IsProcessRunning = True 
                                            If IsProcessRunning = True Then 
                                                Call Sleep  
                                                GoTo verifyagain  
                                            End If 
                                    End If 
                                End If 
                        End If 
                End If 
            CloseHandle hProcess  
        Next N  
    End If 
     
    Debug.Print "Process terminate" 
     
    End Function 
       
    Sub ProcessRunning()  
     
    Debug.Print IsProcessRunning("cmd.exe")  
       
    End Sub 
     
    Sub Sleep()  
     
    Debug.Print Now  
    Application.Wait DateAdd("s", 5, Now)  
    Debug.Print Now  
     
    End Sub 
    • Marcado como Resposta Dandilos terça-feira, 10 de fevereiro de 2009 16:12
    terça-feira, 10 de fevereiro de 2009 16:12

Todas as Respostas

  • Olá Dandilos,

    passei por problema semelhante há pouco tempo. Algumas técnicas que podem lhe ajudar:

    a) Pausar o código por tempo suficiente (o queé difícil de prever). Para isto, você pode usar a API Sleep, que estou postando no final desta mensagem.

    b) Criar uma lógica que, após gravar o arquivo Xyz.txt no servidor FTP, gera um arquivo de retorno Xyz.ret na sua máquina local. Este arquivo de retorno pode ser o próprio arquivo de origem, com outra extensão. Enquanto este arquivo não for gerado, não prossegue o código. Obviamente, você precisa estabelecer um tempo limite para não deixar seu programa travado. A API GetTickCount é útil para ver quanto tempo se passou.



    '***************** Code Start *******************
    ' This code was originally written by Dev Ashish.
    ' It is not to be altered or distributed,
    ' except as part of an application.
    ' You are free to use it in any application,
    ' provided the copyright notice is left unchanged.
    '
    ' Code Courtesy of
    ' Dev Ashish
    '
    Private Declare Sub sapiSleep Lib "kernel32" _
            Alias "Sleep" _
            (ByVal dwMilliseconds As Long)

    Sub sSleep(lngMilliSec As Long)
        If lngMilliSec > 0 Then
            Call sapiSleep(lngMilliSec)
        End If
    End Sub

    Sub sTestSleep()
    Const cTIME = 1000 'in MilliSeconds
        Call sSleep(cTIME)
        MsgBox "Before this Msgbox, I was asleep for " _
            & cTIME & " Milliseconds."
    End Sub
    '***************** Code End *********************



    Exemplo de uso da GetTickCount:

    1. Option Explicit
    2. Private Declare Function GetTickCount Lib "kernel32" () As Long
    3.  
    4.  
    5.     ' Place this code in any Sub or Function
    6.     Dim lngStart As Long
    7.     Dim lngFinish As Long
    8.     Dim lngCounterOne As Long
    9.     Dim lngCounterTwo As Long
    10.    
    11.     ' Record the start "time"
    12.     lngStart = GetTickCount()
    13.    
    14.     ' Some process that you want to time
    15.     For lngCounterOne = 1 To 1000000
    16.         For lngCounterTwo = 1 To 5
    17.         Next lngCounterTwo
    18.     Next lngCounterOne
    19.    
    20.     ' Record the finish "time"
    21.    
    22.     lngFinish = GetTickCount()
    23.    
    24.     ' Display the difference
    25.     MsgBox CStr(lngFinish - lngStart)


     


    Luiz Cláudio Cosenza Vieira da Rocha - http://msmvps.com/blogs/officedev - IT Lab www.itlab.com.br
    terça-feira, 10 de fevereiro de 2009 02:16
    Moderador
  • O sleep eu já sabia, até tentei usar no código. Porém os arquivos que vão ser enviados são sempre uma incógnita, como pode ser 1 arquivo uma vez na outra pode ser 200 entende? Dai acontece o que você falou Luiz, é difícil de prever. Porém nunca usei a outra API que você citou abaixo, irei usá-la e caso de tudo certo marco o post como resposta ok? Enquanto isso quem quiser ajudar postando outra coisa que saiba eu agradeceria!
    terça-feira, 10 de fevereiro de 2009 11:33
  • Pessoal, resolvi o meu problema de uma maneira bem massa, usei umas propriedades do VBA para ver se o processo (no meu caso cmd.exe) está ativo, se ele está ativo ele da um sleep (usei uma outra função sleep que da um pause na aplicação e não aquela que você chama usa uma lib do kernel32) e verifica novamente, caso não esteja mais ativo ele parte para a próxima instrução, segue abaixo o código para quem precisar um dia:

    Option Explicit  
    Private Declare Function OpenProcess Lib "kernel32" ( _  
    ByVal dwDesiredAccess As LongByVal bInheritHandle As LongByVal dwProcessId As LongAs Long 
    Private Declare Function CloseHandle Lib "kernel32" ( _  
    ByVal hObject As LongAs Long 
    Private Declare Function EnumProcesses Lib "PSAPI.DLL" ( _  
    lpidProcess As LongByVal cb As Long, cbNeeded As LongAs Long 
    Private Declare Function EnumProcessModules Lib "PSAPI.DLL" ( _  
    ByVal hProcess As Long, lphModule As LongByVal cb As Long, lpcbNeeded As LongAs Long 
    Private Declare Function GetModuleBaseName Lib "PSAPI.DLL" Alias "GetModuleBaseNameA" ( _  
    ByVal hProcess As LongByVal hModule As LongByVal lpFileName As StringByVal nSize As LongAs Long 
    Private Const PROCESS_VM_READ = &H10  
    Private Const PROCESS_QUERY_INFORMATION = &H400  
     
    Private Function IsProcessRunning(ByVal sProcess As StringAs Boolean 
     
    Const MAX_PATH As Long = 260  
    Dim lProcesses() As Long, lModules() As Long, N As Long, lRet As Long, hProcess As Long 
    Dim sName As String 
     
    sProcess = UCase$(sProcess)  
     
    ReDim lProcesses(1023) As Long 
     
    verifyagain:  
    If EnumProcesses(lProcesses(0), 1024 * 4, lRet) Then 
        For N = 0 To (lRet \ 4) - 1  
            hProcess = OpenProcess(PROCESS_QUERY_INFORMATION Or PROCESS_VM_READ, 0, lProcesses(N))  
                If hProcess Then 
                    ReDim lModules(1023)  
                        If EnumProcessModules(hProcess, lModules(0), 1024 * 4, lRet) Then 
                            sName = String$(MAX_PATH, vbNullChar)  
                            GetModuleBaseName hProcess, lModules(0), sName, MAX_PATH  
                            sName = Left$(sName, InStr(sName, vbNullChar) - 1)  
                                If Len(sName) = Len(sProcess) Then 
                                    If sProcess = UCase$(sName) Then 
                                        IsProcessRunning = True 
                                            If IsProcessRunning = True Then 
                                                Call Sleep  
                                                GoTo verifyagain  
                                            End If 
                                    End If 
                                End If 
                        End If 
                End If 
            CloseHandle hProcess  
        Next N  
    End If 
     
    Debug.Print "Process terminate" 
     
    End Function 
       
    Sub ProcessRunning()  
     
    Debug.Print IsProcessRunning("cmd.exe")  
       
    End Sub 
     
    Sub Sleep()  
     
    Debug.Print Now  
    Application.Wait DateAdd("s", 5, Now)  
    Debug.Print Now  
     
    End Sub 
    • Marcado como Resposta Dandilos terça-feira, 10 de fevereiro de 2009 16:12
    terça-feira, 10 de fevereiro de 2009 16:12
  • Boa Noite pessoal,

    Eu gostaria de saber algo mais simples, que para chegar ate onde vcs estao discutindo, consequentemente voces ja fizeram...

    eu queria uma macro para conectar em uma ftp e disponibilizar arqivos la..eu ja tenho a macro que roda automaticamente, extrai arquivo que eu preciso mas preciso ainda que conecte na ftp colocando senha e usuário.

    Podem me mandar por favor? s se possivel para EMAIL GONE ou EMAIL REMOVED

    Obrigado

    terça-feira, 13 de outubro de 2009 22:52