Para los que no saben que es un API… un API(Application Programming Interface) o en castellano “Interfaz de Programación de Aplicaciones” es [gracias Wikipedia :o)] :
Un conjunto de funciones residentes en bibliotecas (generalmente dinámicas, también llamadas DLLs por sus siglas en inglés, término usado para referirse a éstas en Windows) que permiten que una aplicación corra bajo un determinado sistema operativo. En este caso se refiere a las aplicaciones Windows. Debido a su estrecha relación con el desarrollo de software, los programas en sus especificaciones generalmente explicitan la versión de la API del sistema operativo, mediante diversas nomenclaturas tales como la versión específica del sistema operativo (para Windows 98, por ejemplo), o explicitando la versión del conjunto de bibliotecas (Plataforma Win32, etc.). Las funciones API se dividen en varias categorías:
- Depuración y manejo de errores
- E/S de dispositivos
- DLLs, procesos e hilos
- Comunicación entre procesos
- Manejo de la memoria
- Monitoreo del desempeño
- Manejo de energía
- Almacenamiento
- Información del sistema
- GDI (interfaz para dispositivos gráficos) de Windows (tales como impresoras)
- Interfaz de usuario de Windows
Bueno a lo nuestro.. “y entonces José para que es todo eso, si VB (Visual Basic) tiene un montón de clases, funciones y procedimientos que nos permiten hacer cosas con el sistema operativo” , es cierto pero no todo se puede hacer con lo nativo de Visual Basic, veamos un ejemplo especifico; se requiere hacer un programa en VB de descarga de archivos de Internet, donde nos muestre una barra con el avance de la descarga y obviamente antes nos habra mostrado el tamaño total de la descarga.
Como lo resolvemos??? Existe en VB6 el control Inet y en Vb.Net la clase Net.WebClient, pero con ninguno de ellos podremos hacer una barra de progreso real.
Asi que para eso usaremos el API “WinInet” que como su nombre lo indica esta en el archivo “WinInet.dll” dentro de la carpeta de Windows\system32.
Ahora si, a resolver el problema..
Hagamos la Interfaz usando el diseñador de formularios en VB2005 de tal forma que nos quede algo asi:
Ok, ahora agregamos un modulo que se llame WinInet.bas y declaramos las funciones de la API que usaremos:
Option Explicit
Public Const INTERNET_OPEN_TYPE_PRECONFIG = 0
Public Const INTERNET_OPEN_TYPE_DIRECT = 1
Public Const INTERNET_OPEN_TYPE_PROXY = 3
Public Const scUserAgent = "VB OpenUrl"
Public Const INTERNET_FLAG_RELOAD = &H80000000Public Const HTTP_QUERY_CONTENT_LENGTH = 5
Public Const HTTP_QUERY_LAST_MODIFIED = 11Public Declare Function InternetOpen Lib "wininet.dll" Alias "InternetOpenA" _
(ByVal sAgent As String, ByVal lAccessType As Long, ByVal sProxyName As String, _
ByVal sProxyBypass As String, ByVal lFlags As Long) As LongPublic Declare Function InternetOpenUrl Lib "wininet.dll" Alias "InternetOpenUrlA" _
(ByVal hOpen As Long, ByVal sUrl As String, ByVal sHeaders As String, _
ByVal lLength As Long, ByVal lFlags As Long, ByVal lContext As Long) As LongPublic Declare Function InternetReadFile Lib "wininet.dll" _
(ByVal hFile As Long, ByVal sBuffer As String, ByVal lNumBytesToRead As Long, _
lNumberOfBytesRead As Long) As IntegerPublic Declare Function InternetCloseHandle Lib "wininet.dll" _
(ByVal hInet As Long) As IntegerPublic Declare Function HttpQueryInfo Lib "wininet.dll" Alias "HttpQueryInfoA" _
(ByVal hHttpRequest As Long, ByVal lInfoLevel As Long, ByRef sBuffer As Any, _
ByRef lBufferLength As Long, ByRef lIndex As Long) As Boolean
Una explicacion rápida (el artículo se volvería demasiado extenso si explico a profundidad cada uno de ellos):
InternetOpen: Abre la conexión a Internet.
InternetOpenUrl: Abre la dirección desde donde descargaremos el archivo.
InternetReadFile: Lee o descarga el archivo desde la dirección abierta.
HttpQueryInfo: Lee o extrae algun tipo de información de una dirección en Internet.
InternetCloseHandle: Cierra la conexión abierta a Internet
Listo, ahora que tenemos las funciones hay que usarlas. En el formulario que creamos anteriormente lo que nos interesa es que al presionar el boton etiquetado “Iniciar” descargue el archivo ingresado en la caja de texto al lado de la etiqueta “Ruta(URL):”; ademas deberemos cambiar el nombre de algunos objetos como sigue:
La barra de progreso : pgDownload
La Etiqueta de Tamaño del archivo: lblFileSize
La Etiqueta de Bytes descargados: lblBytesDownloaded
La etiqueta de Estado: LblEstado
entonces el código para ello seria el siguiente:
Private Sub Command1_Click()
DownloadFile Text1.text, “c:\Downloads\archivo.txt”
End Sub
Public Function DownloadFile(FileOrigen As String, FileDestino As String) As Boolean
'On Error GoTo errhandle
Dim hOpen As Long
Dim HOpenURL As Long
Dim sUrl As String
Dim bDoLoop As Boolean
Dim bRet As Boolean
Dim sReadBuffer As String * 2048
Dim lNumberOfBytesRead As Long
Dim sBuffer As String
Dim percent As Integer
Dim file As String
Dim flen As Long
pgDownload.Value = 0
lblFileSize.Caption = 0
lblBytesDownloaded.Caption = 0
'MsgBox "voy a conectar" + vbCrLf + FileOrigen + vbCrLf + FileDestino
sUrl = FileOrigen 'url
hOpen = InternetOpen(scUserAgent, INTERNET_OPEN_TYPE_PRECONFIG, vbNullString, vbNullString, 0)
HOpenURL = InternetOpenUrl(hOpen, sUrl, vbNullString, 0, INTERNET_FLAG_RELOAD, 0)
'MsgBox "conectado!!"
DownloadFile = False
Me.LblEstado.Caption = "Descargando.."
Me.LblEstado.Refresh
bDoLoop = True
Dim cnt As Long
cnt = 0
DownloadFile = True
While bDoLoop
sReadBuffer = vbNullString
bRet = InternetReadFile(HOpenURL, sReadBuffer, Len(sReadBuffer), lNumberOfBytesRead)
sBuffer = sBuffer & Left$(sReadBuffer, lNumberOfBytesRead)
'percent = Int((Len(sBuffer) / flen) * 100)
cnt = cnt + lNumberOfBytesRead
If (cnt > 10000) Then
lblBytesDownloaded.Caption = CStr(Len(sBuffer))
lblBytesDownloaded.Refresh
cnt = 0
End If
pgDownload.Value = lblBytesDownloaded.Caption
If Not CBool(lNumberOfBytesRead) Then
bDoLoop = False
End If
Wend
'Kill FileDestino
Open FileDestino For Binary Access Write As #2
Put #2, , sBuffer
Close #2
pgDownload.Value = 100
lblBytesDownloaded.Caption = file
lblBytesDownloaded.Refresh
If HOpenURL <> 0 Then InternetCloseHandle (HOpenURL)
If hOpen <> 0 Then InternetCloseHandle (hOpen)
End Function
Con eso seria suficiente, espero a alguien le sirva este programita, a mi me sirvio mucho; le hice algunas modificaciones para que me sirva de un actualizador de EXE's en mi red corporativa, si alguien desea que le explique como lo hice e avisan para un siguiente post jeje.
Caramba!!! Jose, en otras palabras (corrigeme si me equivoco) es (un tipo de) pariente/primo/lo-que-seqa (con un GUI) del WGET de los sistemas *nix? Bueno a mi me lo parece :)
ResponderEliminarBueno.. sea lo que sea esta genial!!!
Gracias por compartir tu conocimiento con nosotros =P
(P.D. Gracias tambien por tus experiencias migrando de MSSQL a PostgreSQL, mira que me han caido como anillo al dedo por que en la escuela tenemos un proyecto que trata (casualmente) de montar/comparar/etc... un RDBMS diferente a MSSQL y mi equipo y yo elegimos Postgres,,, Gracias!!! Muchas gracias)
Jose buenos dias me gustaria saber un poco mas acerca de esto pues intenté implementar lo que expusiste aca pero no entendí como, si es posible dejame tu correo para escribirte o escribeme al mio jhonlagosx@hotmail.com
ResponderEliminar