Esta es la segunda versión del Descargador, en esta segunda parte se implementaron múltiples conexiones a un mismo servidor para acelerar la descarga. Las conexiones las va agregando en el ListView en forma de Nodos, los cuales trabajan de la misma forma que un TreeView, cada conexión posee un estado el cual es graficado en forma de progreso en el ListView. También se implementó un formulario al estilo ToolTip como el Ares, donde se muestra en forma de Celdas el progreso de cada petición.
Nota: No todos los servidores soportan múltiples conexiones, en estos casos trabajará con una sola.
Este es un proyecto de un descargador múltiple de archivos en la web, en su proceso de descarga nos informa el nombre del archivo, tipo, estado de la descarga, progreso en forma gráfica, velocidad de descarga, tiempo restante, bytes descargados.
También tenemos la opción de pausar, retomar o cancelar la descarga, el proyecto utiliza el módulo clase CDownload, al cual le he hecho algunas reformas para poder pausar y reanudar la descarga, entre otras.
Para mostrar el progreso utilicé la clase cListViewProgress y algunas apis para cambiar algunos aspectos del Toolbar y el ListView, el proyecto podrá apreciarse mejor si éste está compilado ya que de esa forma se aplicarán los temas de Windows.
Módulo Clase para mostrar barras de progreso en un ListView, anteriormente ya había publicado este módulo, pero le he implementado algunas reformas tales como poder utilizar los temas de Windows, y reducir notablemente el parpadeo de este al repintarse. Si miran el ejemplo para descargar notarán que la modificación del texto de los SubItem lo hago mediante funciones del módulo que utilizan Apis, ya que es una forma más óptima porque no produce el repintado total del ListView, además no hace que el ScrollBar de este vuelva a 0, esto más que nada es para cuando se muestren progresos muy frecuentes tal como lo hace el ejemplo. Las tolerancias que maneja es de 0 a 100, pero cualquiera es libre de modificar el código e implementarle el Mínimo y Máximo.

Este es un Módulo Clase que realicé hace un tiempo atrás pero los link de descarga se habían perdido, le he realizado algunas reformas para optimizar su uso, esta clase sirve para poder crear un tipo de ranking (sistema de votos) dentro de un ListView, puede servir para catalogar archivos de música, video, juegos o relacionarlo de alguna forma con una base de datos. La puntuación es sólo de uno a cinco, estos valores deben ser cargados en el SubItem donde quieran que aparezca la gráfica, cuando el usuario hace click para realizar su votación la clase dispara un evento con el número de items y el nuevo valor, las imágenes de la gráfica se deben cargar en un ImageList, son tres imágenes las cuales representan una imágen seleccionada, una resaltada y otra en escala de grises.

Estas dos funciones sirven para comprimir y descomprimir un array de una forma muy rápida y según el caso puede reducirle el tamaño hasta 10 veces, esto depende del tamaño del mismo o si los datos que este contengan no están comprimidos (por ejemplo no comprimirá el array de una imágen .JPG o un archivo .ZIP, si de una imágen BMP un archivo .EXE). las funciones utilizan las Apis de NTDLL.DLL
* Nota: Algunos antivirus detectan estas Apis como una posible amenaza, es un dato para tener en cuenta si alguna vez la aplicación es marcada como un virus.
Option Explicit
Private Declare Function RtlGetCompressionWorkSpaceSize Lib "NTDLL" (ByVal flags As Integer, WorkSpaceSize As Long, UNKNOWN_PARAMETER As Long) As Long
Private Declare Function NtAllocateVirtualMemory Lib "ntdll.dll" (ByVal ProcHandle As Long, BaseAddress As Long, ByVal NumBits As Long, regionsize As Long, ByVal flags As Long, ByVal ProtectMode As Long) As Long
Private Declare Function RtlCompressBuffer Lib "NTDLL" (ByVal flags As Integer, ByVal BuffUnCompressed As Long, ByVal UnCompSize As Long, ByVal BuffCompressed As Long, ByVal CompBuffSize As Long, ByVal UNKNOWN_PARAMETER As Long, OutputSize As Long, ByVal WorkSpace As Long) As Long
Private Declare Function RtlDecompressBuffer Lib "NTDLL" (ByVal flags As Integer, ByVal BuffUnCompressed As Long, ByVal UnCompSize As Long, ByVal BuffCompressed As Long, ByVal CompBuffSize As Long, OutputSize As Long) As Long
Private Declare Function NtFreeVirtualMemory Lib "ntdll.dll" (ByVal ProcHandle As Long, BaseAddress As Long, regionsize As Long, ByVal flags As Long) As Long
Public Function Compress(Data() As Byte, Out() As Byte) As Long
Dim WorkSpaceSize As Long
Dim WorkSpace As Long
ReDim Out(UBound(Data) * 1.13 + 4)
RtlGetCompressionWorkSpaceSize 2, WorkSpaceSize, 0
NtAllocateVirtualMemory -1, WorkSpace, 0, WorkSpaceSize, 4096, 64
RtlCompressBuffer 2, VarPtr(Data(0)), UBound(Data) + 1, VarPtr(Out(0)), (UBound(Data) * 1.13 + 4), 0, Compress, WorkSpace
NtFreeVirtualMemory -1, WorkSpace, 0, 16384
ReDim Preserve Out(Compress)
End Function
Public Function DeCompress(Data() As Byte, dest() As Byte) As Long
If UBound(Data) Then
Dim lBufferSize As Long
ReDim dest(UBound(Data) * 12.5)
RtlDecompressBuffer 2, VarPtr(dest(0)), (UBound(Data) * 12.5), VarPtr(Data(0)), UBound(Data), lBufferSize
If lBufferSize Then
ReDim Preserve dest(lBufferSize - 1)
DeCompress = lBufferSize - 1
End If
End If
End Function
Igual que la función superior esta sirve para pintar una imágen de forma ampliada pero manteniendo su contorno original utilizando GDI PLUS, esto nos da como ventaja poder utilizar gráficos .PNG entre otros. Nótese que si ponemos el form con AutoRedraw = True la función trabaja más rápido.

Option Explicit
' ----------------------------------------
' Autor Leandro Ascierto
' Web www.leandroascierto.com.ar
' ----------------------------------------
Private Declare Function GdipDrawImageRectRectI Lib "gdiplus" (ByVal hGraphics As Long, ByVal hImage As Long, ByVal dstX As Long, ByVal dstY As Long, ByVal dstWidth As Long, ByVal dstHeight As Long, ByVal SrcX As Long, ByVal SrcY As Long, ByVal SrcWidth As Long, ByVal SrcHeight As Long, ByVal srcUnit As Long, Optional ByVal imageAttributes As Long = 0, Optional ByVal Callback As Long = 0, Optional ByVal CallbackData As Long = 0) As Long
Private Declare Function GdipSetInterpolationMode Lib "gdiplus" (ByVal graphics As Long, ByVal InterpolationMode As Long) As Long
Private Declare Function GdipSetPixelOffsetMode Lib "gdiplus" (ByVal graphics As Long, ByVal PixelOffsetMode As Long) As Long
Private Declare Function GdipCreateFromHDC Lib "gdiplus" (ByVal hdc As Long, ByRef graphics As Long) As Long
Private Declare Function GdipDeleteGraphics Lib "gdiplus" (ByVal graphics As Long) As Long
Private Declare Function GdipLoadImageFromFile Lib "gdiplus" (ByVal FileName As Long, ByRef image As Long) As Long
Private Declare Function GdiplusStartup Lib "gdiplus" (ByRef token As Long, ByRef lpInput As GDIPlusStartupInput, Optional ByRef lpOutput As Any) As Long
Private Declare Function GdiplusShutdown Lib "gdiplus" (ByVal token As Long) As Long
Private Declare Function GdipDisposeImage Lib "gdiplus" (ByVal image As Long) As Long
Private Type GDIPlusStartupInput
GdiPlusVersion As Long
DebugEventCallback As Long
SuppressBackgroundThread As Long
SuppressExternalCodecs As Long
End Type
Private Const GdiPlusVersion As Long = 1&
Private Const QualityModeHigh As Long = 2&
Private Const InterpolationModeNearestNeighbor As Long = QualityModeHigh + 3
Private Const PixelOffsetModeHalf As Long = QualityModeHigh + 2
Dim GdipToken As Long
Dim m_hImage As Long
Private Sub RenderStretchPlus(ByVal DestHdc As Long, _
ByVal DestX As Long, _
ByVal DestY As Long, _
ByVal DestW As Long, _
ByVal DestH As Long, _
ByVal hImage As Long, _
ByVal x As Long, _
ByVal y As Long, _
ByVal Width As Long, _
ByVal Height As Long, _
ByVal Size As Long)
Dim hGraphics As Long
Dim Sx2 As Long
Sx2 = Size * 2
If GdipCreateFromHDC(DestHdc, hGraphics) = 0 Then
Call GdipSetInterpolationMode(hGraphics, InterpolationModeNearestNeighbor)
Call GdipSetPixelOffsetMode(hGraphics, PixelOffsetModeHalf)
GdipDrawImageRectRectI hGraphics, hImage, DestX, DestY, Size, Size, x, y, Size, Size, &H2, 0&, 0&, 0& 'TOP_LEFT
GdipDrawImageRectRectI hGraphics, hImage, DestX + Size, DestY, DestW - Sx2, Size, x + Size, y, Width - Sx2, Size, &H2, 0&, 0&, 0& 'TOP_CENTER
GdipDrawImageRectRectI hGraphics, hImage, DestX + DestW - Size, DestY, Size, Size, x + Width - Size, y, Size, Size, &H2, 0&, 0&, 0& 'TOP_RIGHT
GdipDrawImageRectRectI hGraphics, hImage, DestX, DestY + Size, Size, DestH - Sx2, x, y + Size, Size, Height - Sx2, &H2, 0&, 0&, 0& 'MID_LEFT
GdipDrawImageRectRectI hGraphics, hImage, DestX + Size, DestY + Size, DestW - Sx2, DestH - Sx2, x + Size, y + Size, Width - Sx2, Height - Sx2, &H2, 0&, 0&, 0& 'MID_CENTER
GdipDrawImageRectRectI hGraphics, hImage, DestX + DestW - Size, DestY + Size, Size, DestH - Sx2, x + Width - Size, y + Size, Size, Height - Sx2, &H2, 0&, 0&, 0& 'MID_RIGHT
GdipDrawImageRectRectI hGraphics, hImage, DestX, DestY + DestH - Size, Size, Size, x, y + Height - Size, Size, Size, &H2, 0&, 0&, 0& 'BOTTOM_LEFT
GdipDrawImageRectRectI hGraphics, hImage, DestX + Size, DestY + DestH - Size, DestW - Sx2, Size, x + Size, y + Height - Size, Width - Sx2, Size, &H2, 0&, 0&, 0& 'BOTTOM_CENTER
GdipDrawImageRectRectI hGraphics, hImage, DestX + DestW - Size, DestY + DestH - Size, Size, Size, x + Width - Size, y + Height - Size, Size, Size, &H2, 0&, 0&, 0& 'BOTTOM_RIGHT
Call GdipDeleteGraphics(hGraphics)
End If
End Sub
Private Sub RenderPlusFromFile(ByVal DestHdc As Long, _
ByVal DestX As Long, _
ByVal DestY As Long, _
ByVal DestW As Long, _
ByVal DestH As Long, _
ByVal FileName As String, _
ByVal x As Long, _
ByVal y As Long, _
ByVal Width As Long, _
ByVal Height As Long, _
ByVal Size As Long)
Dim hImg As Long
Call GdipLoadImageFromFile(StrPtr(FileName), hImg)
Call RenderStretchPlus(DestHdc, DestX, DestY, DestW, DestH, hImg, x, y, Width, Height, Size)
Call GdipDisposeImage(hImg)
End Sub
Private Sub InitGDI()
Dim GdipStartupInput As GDIPlusStartupInput
GdipStartupInput.GdiPlusVersion = GdiPlusVersion
Call GdiplusStartup(GdipToken, GdipStartupInput, ByVal 0)
End Sub
Private Sub TerminateGDI()
Call GdiplusShutdown(GdipToken)
End Sub
Private Sub Command1_Click()
Cls
RenderPlusFromFile Me.hdc, 5, 5, 230, 230, App.Path & "\Image2.png", 0, 0, 158, 93, 26
End Sub
Private Sub Form_Load()
Call InitGDI
Call GdipLoadImageFromFile(StrPtr(App.Path & "\BotonesVista.png"), m_hImage)
Me.AutoRedraw = True 'Utilizando GDIPlus + AutoRedraw = True, es mas rapido
End Sub
Private Sub Form_Terminate()
Call GdipDisposeImage(m_hImage)
Call TerminateGDI
End Sub
Private Sub Option1_Click(Index As Integer)
Cls
RenderStretchPlus Me.hdc, 10, 10, 120, 80, m_hImage, 0, 21 * Index, 11, 21, 3
End Sub

