Usuário com melhor resposta
Verificação com VBA

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!
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 Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long Private Declare Function CloseHandle Lib "kernel32" ( _ ByVal hObject As Long) As Long Private Declare Function EnumProcesses Lib "PSAPI.DLL" ( _ lpidProcess As Long, ByVal cb As Long, cbNeeded As Long) As Long Private Declare Function EnumProcessModules Lib "PSAPI.DLL" ( _ ByVal hProcess As Long, lphModule As Long, ByVal cb As Long, lpcbNeeded As Long) As Long Private Declare Function GetModuleBaseName Lib "PSAPI.DLL" Alias "GetModuleBaseNameA" ( _ ByVal hProcess As Long, ByVal hModule As Long, ByVal lpFileName As String, ByVal nSize As Long) As Long Private Const PROCESS_VM_READ = &H10 Private Const PROCESS_QUERY_INFORMATION = &H400 Private Function IsProcessRunning(ByVal sProcess As String) As 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
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 SubSub 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:-
Option Explicit
-
Private Declare Function GetTickCount Lib "kernel32" () As Long
-
-
-
' Place this code in any Sub or Function
-
Dim lngStart As Long
-
Dim lngFinish As Long
-
Dim lngCounterOne As Long
-
Dim lngCounterTwo As Long
-
-
' Record the start "time"
-
lngStart = GetTickCount()
-
-
' Some process that you want to time
-
For lngCounterOne = 1 To 1000000
-
For lngCounterTwo = 1 To 5
-
Next lngCounterTwo
-
Next lngCounterOne
-
-
' Record the finish "time"
-
-
lngFinish = GetTickCount()
-
-
' Display the difference
-
MsgBox CStr(lngFinish - lngStart)
Luiz Cláudio Cosenza Vieira da Rocha - http://msmvps.com/blogs/officedev - IT Lab www.itlab.com.br -
-
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!
-
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 Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long Private Declare Function CloseHandle Lib "kernel32" ( _ ByVal hObject As Long) As Long Private Declare Function EnumProcesses Lib "PSAPI.DLL" ( _ lpidProcess As Long, ByVal cb As Long, cbNeeded As Long) As Long Private Declare Function EnumProcessModules Lib "PSAPI.DLL" ( _ ByVal hProcess As Long, lphModule As Long, ByVal cb As Long, lpcbNeeded As Long) As Long Private Declare Function GetModuleBaseName Lib "PSAPI.DLL" Alias "GetModuleBaseNameA" ( _ ByVal hProcess As Long, ByVal hModule As Long, ByVal lpFileName As String, ByVal nSize As Long) As Long Private Const PROCESS_VM_READ = &H10 Private Const PROCESS_QUERY_INFORMATION = &H400 Private Function IsProcessRunning(ByVal sProcess As String) As 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
-
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