Cliente Ftp con el Api wininet

Este es un programa de ejemplo con el código fuente para acceder a un servidor vía Ftp y poder realizar operaciones básicas utilizando el api de windows


Las opciones principales son:

  • Subir y bajar archivos
  • Eliminar y renombrar carpetas y archivos
  • Listar los mismos en un control ListView (no es nada del otro mundo)
  • algunas otras opciones

El ejemplo utiliza un módulo de clase que tiene las funciones descritas arriba.

Nota , El programa mientras lo hacía, no lo llegué a testear a fondo, solo lo probé con mi servidor Ftp y no me surgió errores, con lo cual no quiere decir que no los tenga, en todo caso si le encontrás alguno y querés avisarme, enviame un mail para ver si lo puedo ojear y poder corregirlo :)

Imágen del ejemplo:

vista del formulario con el control Listview que lista los archivos remotos del FTP y los demás comandos del programa

Código fuente del módulo de clase:

  1. Private Const MAX_PATH = 260
  2. ‘Constante para el atributo de directorio
  3. Private Const FILE_ATTRIBUTE_DIRECTORY = &H10
  4. ‘— tipos de archivos — para el Upload y Download
  5. Private Const FTP_TRANSFER_TYPE_UNKNOWN = &H0
  6. Private Const FTP_TRANSFER_TYPE_ASCII = &H1
  7. Private Const FTP_TRANSFER_TYPE_BINARY = &H2
  8. ‘Puerto FTP
  9. Private Const INTERNET_DEFAULT_FTP_PORT = 21
  10. Private Const INTERNET_SERVICE_FTP = 1
  11. ‘ Modo de conexión FTP
  12. Private Const INTERNET_FLAG_PASSIVE = &H8000000
  13. Private Const PassiveConnection As Boolean = True
  14. ‘— formas de entrar en internet —
  15. ‘ usa config del registro
  16. Private Const INTERNET_OPEN_TYPE_PRECONFIG = 0
  17. ‘ directo a internet
  18. Private Const INTERNET_OPEN_TYPE_DIRECT = 1
  19. ‘ via proxy
  20. Private Const INTERNET_OPEN_TYPE_PROXY = 3
  21. Private Const INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY = 4
  22. ‘Type para atributos de fecha y hora de archivos
  23. Private Type FILETIME
  24. dwLowDateTime As Long
  25. dwHighDateTime As Long
  26. End Type
  27. ‘Otros atributos de archivo tamaño, nombre, fecha etc..
  28. Private Type WIN32_FIND_DATA
  29. dwFileAttributes As Long
  30. ftCreationTime As FILETIME
  31. ftLastAccessTime As FILETIME
  32. ftLastWriteTime As FILETIME
  33. nFileSizeHigh As Long
  34. nFileSizeLow As Long
  35. dwReserved0 As Long
  36. dwReserved1 As Long
  37. cFileName As String * MAX_PATH
  38. cAlternate As String * 14
  39. End Type
  40. ‘ Declaraciones Apis
  41. ‘***************************************************************
  42. Private Declare Function InternetCloseHandle _
  43. Lib “wininet.dll” (ByVal hInet As Long) As Integer
  44. ‘Establece una conexión a internet para poder iniciar sesión Ftp
  45. Private Declare Function InternetConnect _
  46. Lib “wininet.dll” Alias “InternetConnectA” _
  47. (ByVal hInternetSession As Long, _
  48. ByVal sServerName As String, _
  49. ByVal nServerPort As Integer, _
  50. ByVal sUserName As String, _
  51. ByVal sPassword As String, _
  52. ByVal lService As Long, ByVal lFlags As Long, _
  53. ByVal lContext As Long) As Long
  54. ‘función api que Conecta al Ftp
  55. Private Declare Function InternetOpen _
  56. Lib “wininet.dll” Alias “InternetOpenA” _
  57. (ByVal sAgent As String, ByVal lAccessType As Long, _
  58. ByVal sProxyName As String, _
  59. ByVal sProxyBypass As String, _
  60. ByVal lFlags As Long) As Long
  61. ‘Función que Establece el path corriente
  62. Private Declare Function FtpSetCurrentDirectory _
  63. Lib “wininet.dll” Alias “FtpSetCurrentDirectoryA” _
  64. (ByVal hFtpSession As Long, _
  65. ByVal lpszDirectory As String) As Boolean
  66. ‘api que Recupera el path donde estamos ubicados
  67. Private Declare Function FtpGetCurrentDirectory _
  68. Lib “wininet.dll” Alias “FtpGetCurrentDirectoryA” _
  69. (ByVal hFtpSession As Long, _
  70. ByVal lpszCurrentDirectory As String, _
  71. lpdwCurrentDirectory As Long) As Long
  72. ‘Api para Crear un directorio
  73. Private Declare Function FtpCreateDirectory _
  74. Lib “wininet.dll” Alias “FtpCreateDirectoryA” _
  75. (ByVal hFtpSession As Long, _
  76. ByVal lpszDirectory As String) As Boolean
  77. ‘Api que Elimina un directorio del FTP
  78. Private Declare Function FtpRemoveDirectory _
  79. Lib “wininet.dll” Alias “FtpRemoveDirectoryA” _
  80. (ByVal hFtpSession As Long, _
  81. ByVal lpszDirectory As String) As Boolean
  82. ‘Para Borrar un fichero
  83. Private Declare Function FtpDeleteFile _
  84. Lib “wininet.dll” Alias “FtpDeleteFileA” _
  85. (ByVal hFtpSession As Long, _
  86. ByVal lpszFileName As String) As Boolean
  87. ‘Función que Renombra un fichero
  88. Private Declare Function FtpRenameFile _
  89. Lib “wininet.dll” Alias “FtpRenameFileA” _
  90. (ByVal hFtpSession As Long, _
  91. ByVal lpszExisting As String, _
  92. ByVal lpszNew As String) As Boolean
  93. ‘Recupera un archivo
  94. Private Declare Function FtpGetFile Lib “wininet.dll” _
  95. Alias “FtpGetFileA” (ByVal hConnect As Long, _
  96. ByVal lpszRemoteFile As String, _
  97. ByVal lpszNewFile As String, ByVal fFailIfExists As Long, _
  98. ByVal dwFlagsAndAttributes As Long, ByVal dwFlags As Long, _
  99. ByRef dwContext As Long) As Boolean
  100. ‘Escribe un archivo
  101. Private Declare Function FtpPutFile Lib “wininet.dll” _
  102. Alias “FtpPutFileA” (ByVal hConnect As Long, _
  103. ByVal lpszLocalFile As String, _
  104. ByVal lpszNewRemoteFile As String, ByVal dwFlags As Long, _
  105. ByVal dwContext As Long) As Boolean
  106. ‘Api Para manejar los errores
  107. Private Declare Function InternetGetLastResponseInfo _
  108. Lib “wininet.dll” Alias “InternetGetLastResponseInfoA” _
  109. (lpdwError As Long, ByVal lpszBuffer As String, _
  110. lpdwBufferLength As Long) As Boolean
  111. ‘Busca el primer archivo de un path
  112. Private Declare Function FtpFindFirstFile Lib “wininet.dll” _
  113. Alias “FtpFindFirstFileA” (ByVal hFtpSession As Long, _
  114. ByVal lpszSearchFile As String, _
  115. lpFindFileData As WIN32_FIND_DATA, _
  116. ByVal dwFlags As Long, ByVal dwContent As Long) As Long
  117. ‘api para buscar el siguiente archivo
  118. Private Declare Function InternetFindNextFile Lib “wininet.dll” _
  119. Alias “InternetFindNextFileA” (ByVal hFind As Long, _
  120. lpvFindData As WIN32_FIND_DATA) As Long
  121. Public Enum e_TipoTransferencia
  122. [ BINARIO ] = FTP_TRANSFER_TYPE_BINARY
  123. [ ASCII ] = FTP_TRANSFER_TYPE_ASCII
  124. [ DESCONOCIDO ] = FTP_TRANSFER_TYPE_UNKNOWN
  125. End Enum
  126. ‘Handle de la conexión Ftp
  127. Dim HandleConect As Long
  128. ‘Handle de la conexión a Internet
  129. Dim hOpen As Long
  130. ‘Variables locales
  131. Private m_DirectorioActual As String
  132. Private m_Usuario As String
  133. Private m_PassWord As String
  134. Private m_Servidor As String
  135. Private m_DirAnterior As String
  136. Private m_listView As ListView
  137. Private m_TipoTransferencia As Long
  138. Private m_form As Form
  139. Private ctrl As Object
  140. ‘Funciones Varias para el manejo de archivos y carpetas en el servidor Ftp
  141. ‘***********************************************************************
  142. ‘***********************************************************************
  143. ‘Rutina que conecta al Servidor Ftp
  144. Public Function ConectarFtp(Optional ControlStatus As Object _
  145. = Nothing) As Boolean
  146. ‘Verificamos que los datos de la cuenta estén establecidas, si no mostramos un _
  147. mensaje y salimos
  148. If m_Usuario = “” Or m_Servidor = “” Or m_PassWord = “” Then
  149. MsgBox “No se puede conectar. Verifique el Nombre de usuario,” _
  150. & “El nombre del Servidor y la contraseña que estén establecidas”, vbCritical
  151. ConectarFtp = False
  152. Exit Function
  153. End If
  154. Set ctrl = ControlStatus
  155. Status “…Intentando conectar a: ” & m_Servidor
  156. m_form.MousePointer = vbHourglass
  157. ‘Abrimos una conección a Internet
  158. hOpen = InternetOpen(vbNullString, _
  159. INTERNET_OPEN_TYPE_PRECONFIG, vbNullString, _
  160. vbNullString, 0)
  161. If hOpen = 0 Then
  162. Status “Error en la conexión a internet, compruebe la conexión”
  163. m_form.MousePointer = vbDefault
  164. ConectarFtp = False
  165. Exit Function
  166. End If
  167. ‘Conectamos al servidor FTP, pasandole los datos: login y servidor
  168. HandleConect = InternetConnect(hOpen, m_Servidor, _
  169. INTERNET_DEFAULT_FTP_PORT, m_Usuario, _
  170. m_PassWord, INTERNET_SERVICE_FTP, _
  171. IIf(PassiveConnection, INTERNET_FLAG_PASSIVE, 0), 0)
  172. If HandleConect = 0 Then
  173. Status “Error. Compruebe los datos del servidor Ftp sin son correctos”
  174. m_form.MousePointer = vbDefault
  175. ConectarFtp = False
  176. Exit Function
  177. End If
  178. Status “Conectado a: ” & m_Servidor
  179. m_form.MousePointer = vbDefault
  180. ConectarFtp = True
  181. End Function
  182. ‘Desconecta del servidor FTP
  183. ‘**************************************************
  184. Public Sub Desconectar()
  185. Dim ret As Long
  186. ‘cierra la conexion FTP
  187. ret = InternetCloseHandle(HandleConect)
  188. If ret = 0 Then Status “Error al desconectar”: Exit Sub
  189. ‘cierra la conexion a internet
  190. ret = InternetCloseHandle(hOpen)
  191. If ret = 0 Then Status “Error al desconectar”: Exit Sub
  192. Status “Desconectado de: ” & m_Servidor
  193. Class_Terminate
  194. End Sub
  195. ‘Recupera el directorio actual donde estamos ubicados
  196. ‘*****************************************************
  197. Public Function GetDirectorioActual() As String
  198. ‘Crea un buffer para el path
  199. m_DirectorioActual = String(MAX_PATH, 0)
  200. ‘Obtenemos el directorio actual
  201. ret = FtpGetCurrentDirectory(HandleConect, m_DirectorioActual, _
  202. Len(m_DirectorioActual))
  203. GetDirectorioActual = m_DirectorioActual
  204. End Function
  205. ‘Establecemos el Directorio Actual
  206. ‘****************************************************
  207. Public Sub CambiarDirectorio(PathDirectorio As String)
  208. Dim pData As WIN32_FIND_DATA
  209. Dim hFind As Long ‘handle usado para buscar fichs en FTP
  210. Dim ret As Long
  211. Dim strDir As String
  212. strDir = Replace(m_DirectorioActual, Chr(0), “”)
  213. If strDir = “/” And PathDirectorio = “../Subir un nivel” Then: Exit Sub
  214. m_form.MousePointer = vbHourglass
  215. If PathDirectorio = “../Subir un nivel” Then
  216. pos = InStrRev(strDir, “/”)
  217. strDir = Left(strDir, pos)
  218. ‘Cambia al Directorio Ftp al directorio especificado
  219. ret = FtpSetCurrentDirectory(HandleConect, strDir)
  220. If ret = 0 Then
  221. Status “Error al cambiar de directorio.”
  222. End If
  223. m_form.MousePointer = vbDefault
  224. Exit Sub
  225. End If
  226. ‘Cambia al Directorio especificado
  227. ret = FtpSetCurrentDirectory(HandleConect, strDir & “/” & PathDirectorio)
  228. If ret = 0 Then
  229. Status “Error al cambiar de directorio”
  230. End If
  231. m_form.MousePointer = vbDefault
  232. End Sub
  233. ‘Crea un nuevo directorio
  234. ‘*******************************************
  235. Public Sub CrearDirectorio(NameDirectorio As String)
  236. ‘Creamos la nueva carpeta
  237. ret = FtpCreateDirectory(HandleConect, NameDirectorio)
  238. If Not ret Then
  239. Status “Error al crear el directorio, compruebe el nombre que sea válido”
  240. Else
  241. m_listView.ListItems.Add , , NameDirectorio, , “carpeta”
  242. m_listView.ListItems(m_listView.ListItems.Count).Selected = True
  243. m_listView.SetFocus
  244. End If
  245. End Sub
  246. ‘Crea o sube un nuevo Archivo.
  247. ‘********************************************
  248. Public Sub SubirArchivo(localArchivo As String, NombreArchivoRemoto As String)
  249. ‘ ( Upload ) Envía el fichero al servidor FTP
  250. ret = FtpPutFile(HandleConect, localArchivo, NombreArchivoRemoto, _
  251. m_TipoTransferencia, 0)
  252. If ret Then
  253. m_listView.ListItems.Add , , NombreArchivoRemoto, , “archivo”
  254. m_listView.ListItems(m_listView.ListItems.Count).Selected = True
  255. m_listView.SetFocus
  256. Else
  257. Status “Error al subir el fichero:” & NombreArchivoRemoto
  258. End If
  259. End Sub
  260. ‘Renombra un archivo en el directorio Ftp corriente
  261. ‘****************************************************
  262. Public Sub RenombrarArchivo(Archivo As String, nuevoNombre As String)
  263. ret = FtpRenameFile(HandleConect, Archivo, nuevoNombre)
  264. If ret Then
  265. m_listView.SelectedItem.Text = nuevoNombre
  266. m_listView.SetFocus
  267. Else
  268. Status “Error al renombrar el fichero:” & nuevoNombre
  269. End If
  270. End Sub
  271. Public Sub ObtenerArchivo(ArchivoRemoto As String, ArchivoLocal As String, _
  272. Optional SobreEscribir As Boolean = False)
  273. ‘recupera fichero del servidor FTP: ArchivoRemoto es el nombre del archivo remoto
  274. ‘ArchivoLocal es el nombre y ruta donde se colocará el archivo en local
  275. ret = FtpGetFile(HandleConect, ArchivoRemoto, ArchivoLocal, _
  276. SobreEscribir, 0, m_TipoTransferencia, 0)
  277. If ret Then
  278. Status “Archivo descargado correctamente:”
  279. m_listView.SetFocus
  280. Else
  281. Status “Error al intentar descargar el fichero: ” & ArchivoRemoto
  282. End If
  283. End Sub
  284. ‘Eliminar Archivo del servidor
  285. Public Sub EliminarArchivo(Archivo As String)
  286. ret = FtpDeleteFile(HandleConect, Archivo)
  287. If Not ret Then
  288. Status “Error. No se pudo eliminar el archivo: ” & Archivo
  289. End If
  290. End Sub
  291. ‘Elimina un directorio
  292. ‘***********************************************************************
  293. Public Sub EliminarDirectorio(Directorio As String)
  294. ‘elimina el directorio
  295. ret = FtpRemoveDirectory(HandleConect, Directorio)
  296. If Not ret Then
  297. Status “Error. No se pudo eliminar el Directorio: ” & Directorio
  298. End If
  299. End Sub
  300. Private Sub Status(mensaje As String)
  301. On Error GoTo SubError
  302. ctrl = mensaje
  303. Exit Sub
  304. SubError:
  305. If Err.Number = 91 Then Resume Next
  306. End Sub
  307. ‘Lista los archivos el el LV
  308. ‘***********************************************************************
  309. Public Sub ListarArchivos()
  310. Dim pData As WIN32_FIND_DATA
  311. Dim hFind As Long ‘handle usado para buscar fichs en FTP
  312. Dim ret As Long ‘valor devuelto por API
  313. m_form.MousePointer = vbHourglass
  314. ‘crea un buffer
  315. pData.cFileName = String(MAX_PATH, 0)
  316. ‘busca el primer fichero
  317. hFind = FtpFindFirstFile(HandleConect, “*.*”, pData, 0, 0)
  318. m_listView.ListItems.Clear
  319. ‘Si Hfind vale 0 es porque no hay archivos ni directorios
  320. If hFind = 0 Then
  321. m_listView.ListItems.Add , , “../Subir un nivel”, , “carpeta”
  322. m_form.MousePointer = vbDefault
  323. Exit Sub
  324. End If
  325. m_listView.ListItems.Add , , “../Subir un nivel”, , “carpeta”
  326. If pData.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY Then
  327. m_listView.ListItems.Add , , pData.cFileName, , “carpeta”
  328. Else
  329. m_listView.ListItems.Add(, , pData.cFileName, , “archivo”).SubItems(1) = _
  330. Round((pData.nFileSizeLow / 1024), 2) & ” Kb”
  331. End If
  332. ’si no hay mas Archivos sale
  333. If hFind = 0 Then
  334. m_form.MousePointer = vbDefault
  335. Exit Sub
  336. End If
  337. Do
  338. ‘crea un buffer
  339. pData.cFileName = String(MAX_PATH, 0) ’se llena con nulos
  340. ‘ busca el siguiente archivo
  341. ret = InternetFindNextFile(hFind, pData)
  342. ’si no hay ficheros, no sigue
  343. If ret = 0 Then Exit Do
  344. If pData.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY Or _
  345. pData.dwFileAttributes = 0 Then
  346. ‘Agrega el nombre del directorio al control ListView
  347. m_listView.ListItems.Add , , pData.cFileName, , “carpeta”
  348. Else
  349. ‘agrega el archivo y Muestra el tamaño del mismo
  350. m_listView.ListItems.Add(, , pData.cFileName, , “archivo”).SubItems(1) = _
  351. Round((pData.nFileSizeLow / 1024), 2) & ” Kb”
  352. End If
  353. Loop
  354. ‘Cerramos el handle de búsqueda anterior
  355. InternetCloseHandle hFind
  356. m_listView.Sorted = True
  357. m_form.MousePointer = vbDefault
  358. End Sub
  359. ‘Actualiza la lista de Archivos y directorios en el ListView
  360. ‘************************************************************
  361. Public Sub Actualizar()
  362. Dim pData As WIN32_FIND_DATA
  363. Dim hFind As Long ‘handle usado para buscar fichs en FTP
  364. Dim ret As Long ‘valor devuelto por API
  365. m_form.MousePointer = vbHourglass
  366. ‘crea un buffer
  367. pData.cFileName = String(MAX_PATH, 0)
  368. ‘busca el primer fichero
  369. hFind = FtpFindFirstFile(HandleConect, “*.*”, pData, 0, 0)
  370. m_listView.ListItems.Clear
  371. If hFind = 0 Then
  372. m_listView.ListItems.Add , , “../Subir un nivel”, , “carpeta”
  373. m_form.MousePointer = vbDefault
  374. Exit Sub
  375. End If
  376. m_listView.ListItems.Add , , “../Subir un nivel”, , “carpeta”
  377. If pData.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY Then
  378. m_listView.ListItems.Add , , pData.cFileName, , “carpeta”
  379. Else
  380. m_listView.ListItems.Add(, , pData.cFileName, , “archivo”).SubItems(1) = _
  381. Round((pData.nFileSizeLow / 1024), 2) & ” Kb”
  382. End If
  383. ’si no hay mas Archivos sale
  384. If hFind = 0 Then
  385. m_form.MousePointer = vbDefault
  386. Exit Sub
  387. End If
  388. Do
  389. ‘buffer
  390. pData.cFileName = String(MAX_PATH, 0) ’se llena con nulos
  391. ‘ Busca el siguiente File
  392. ret = InternetFindNextFile(hFind, pData)
  393. ’si no hay mas arhivos, no sigue buscando
  394. If ret = 0 Then Exit Do
  395. ‘Archivo
  396. If pData.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY Or pData.dwFileAttributes = 0 Then
  397. m_listView.ListItems.Add , , pData.cFileName, , “carpeta”
  398. m_listView.ListItems.Add(, , pData.cFileName, , “carpeta”).ListSubItems(0) = _
  399. pData.ftCreationTime.dwHighDateTime
  400. Else
  401. m_listView.ListItems.Add(, , pData.cFileName, , “archivo”).SubItems(1) = _
  402. Round((pData.nFileSizeLow / 1024), 2) & ” Kb”
  403. End If
  404. Loop
  405. ‘Cerramos el handle de búsqueda
  406. InternetCloseHandle hFind
  407. m_listView.Sorted = True
  408. m_form.MousePointer = vbDefault
  409. End Sub
  410. Public Sub Inicializar(Formulario As Form)
  411. Set m_form = Formulario
  412. End Sub
  413. ‘Para los errores
  414. ‘************************************************+
  415. Private Sub ShowError()
  416. Dim lngNumError As Long
  417. Dim strMemoError As String
  418. Dim lngTamBuffer As Long
  419. ‘—————————–
  420. ‘Tamaño del buffer
  421. InternetGetLastResponseInfo lngNumError, _
  422. strMemoError, lngTamBuffer
  423. ‘crea buffer
  424. strMemoError = String(lngTamBuffer, 0)
  425. ‘Recupera informacion del error
  426. InternetGetLastResponseInfo lngNumError, _
  427. strMemoError, lngTamBuffer
  428. ‘Mostrar el error en un msgbox
  429. MsgBox “Error ” & CStr(lngNumError) & “: ” & strMemoError, _
  430. vbOKOnly Or vbCritical
  431. End Sub
  432. ‘Nombre de usuario de la cuenta Ftp
  433. ‘**********************************
  434. Public Property Get Usuario() As String
  435. Usuario = m_Usuario
  436. End Property
  437. Public Property Let Usuario(ByVal vNewValue As String)
  438. m_Usuario = vNewValue
  439. End Property
  440. ‘Nombre del servidor Ftp
  441. ‘***********************
  442. Public Property Get Servidor() As String
  443. Servidor = m_Servidor
  444. End Property
  445. Public Property Let Servidor(ByVal vNewValue As String)
  446. m_Servidor = vNewValue
  447. End Property
  448. ‘Contraseña de la cuenta FTP
  449. ‘***************************
  450. Public Property Get PassWord() As String
  451. PassWord = m_PassWord
  452. End Property
  453. Public Property Let PassWord(ByVal vNewValue As String)
  454. m_PassWord = vNewValue
  455. End Property
  456. ‘Establece el ListView donde listar los ficheros
  457. ‘***********************************************
  458. Public Property Get ListView() As ListView
  459. Set ListView = m_listView
  460. End Property
  461. Public Property Set ListView(ByVal vNewValue As ListView)
  462. Set m_listView = vNewValue
  463. End Property
  464. ‘Propiedad para el Modo de Transferencia que se va a utilizar
  465. ‘***************************************************************
  466. Public Property Get TipoTransferencia() As e_TipoTransferencia
  467. TipoTransferencia = m_TipoTransferencia
  468. End Property
  469. Public Property Let TipoTransferencia(NewData As e_TipoTransferencia)
  470. m_TipoTransferencia = NewData
  471. End Property
  472. Private Sub Class_Terminate()
  473. On Local Error Resume Next
  474. ‘Cerramos la sesión FTP y la conexión a internet
  475. InternetCloseHandle HandleConect
  476. InternetCloseHandle hOpen
  477. ‘Eliminamos las variables de objeto (Listview - Form )
  478. Set ctrl = Nothing
  479. Set ListView = Nothing
  480. Set m_form = Nothing
  481. End Sub
Escrito en Visual Basic. Etiquetas: .

2 comentarios para “Cliente Ftp con el Api wininet”

  1. aBeL Dice:

    Como estan man.,
    Oye se ve muy interesante tu ejemplo, pero no seas gacho.
    me podras pasar el codigo fuente del q ya estan jalando
    digo lo q vienen siendo las formas , la clase y todo el proyecto
    Es q ya llevo ratote intentando hcaer q jale ete q pusiste
    pero no se como jijos echarlo andar.

    No se q llevan los botones pls.

    Saludos ygracias por tu ayuda.

  2. EMGA Dice:

    por casualidad no tienes este mismo code pero para .net
    ya que me gustaria ver como queda en el vb.net

Escribe un comentario