July 2008 - Posts

Para los que se fueron, para los que se van, para los que volvieron y para los que se quedaron.
Que disfrutéis de, que tengáis, que hayáis tenido, que no perdais la esperanza de tener .... 

unos felices días de paz y descanso!

Paradise

Nos vemos,
Pep Lluis,

Posted by peplluis | 2 comment(s)
Filed under:

Tal como os tengo acostumbrados, con el trasfondo de preguntas que se repiten y repiten, os facilito un ejemplo de cómo rastrear toda la información de nuestro disco “lógico” utilizando el conocido “System.Management” del ‘Framework 2.0’.

En el siguiente ejemplo rellenamos un “DomainUpDown” con los nombres de las características de nuestro disco, a continuación rellenamos un ‘label’ con la descripción de la característica cada vez que el “DUD” cambia de indice… sencillo, verdad? Utilizando este método podremos acceder a las propiedades disponibles sin tener que buscar sus nombres de antemano. A pesar de que os anticipo que a menudo muchos de nosotros intentamos obtener información o características que no están disponibles para ese “disco” o bien no existen!.  No olvidéis que la información es la de WIN32_DiskDrive.

MisDiscos

Para los mas profundos en búsqueda de información mas “Fisica” podeis cambiar la “query” por la de Win32_PhysicalMedia.

Private MisDiscos As New ManagementObjectSearcher("SELECT * FROM Win32_PhysicalMedia")

Espero vuestras conversaciones J
Cuidaros,
Pep Lluis,

Imports System.Management

 

Public Class Form1

    '

    'Obtener toda la informacion de mis discos (Logicos)

    Private MisDiscos As New ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive")

    'Almacen del valor de las caracteristicas segun propiedad

    Private DiscInfo As New ManagementObject

 

    Private Sub Form1_Load(…..) Handles MyBase.Load

        Dim MiInfo = From Hd As ManagementObject In MisDiscos.Get Select Hd

        'Seleccionar la info del disco(0)

        'O bien proporcionar un combo para su seleccion
        DiscInfo = MiInfo(0)

        'Obtener el nombre de la propiedad

        'Rellenar el DUD con los nombres

        Me.DomainUpDown1.Items.AddRange( _

           ( _

              From Pn As Management.PropertyData _

              In DiscInfo.Properties _

              Select Pn.Name _

            ).ToArray)

        'Por defecto seleccionar el primer indice

        Me.DomainUpDown1.SelectedIndex = 1

    End Sub

    '

    ' Al cambiar el indice del item seleccionado...

    '

    Private Sub DomainUpDown1_SelectedItemChanged(...) _
         
Handles DomainUpDown1.SelectedItemChanged

        Try

            'obtener la descripcion de la propiedad

            Descripcion.Text = DiscInfo.Properties(Me.DomainUpDown1.Text).Value

        Catch ex As Exception

            'en caso de error...

            Descripcion.Text = "¿?"

        End Try

    End Sub

End Class

Posted by peplluis | 10 comment(s)
Filed under: ,

Fruto de una pregunta de Jesus, sobre la conveniencia de usar el entorno en una u otro lengua, os dejo un par de argumentos para animaros a seguir la conversación.

Empecé a programar en "Assembler" hace mas de 30 años sin tener conocimiento alguno de Ingles y para aquellos entonces no existía ninguna posibilidad de obtener información alguna en otro lenguaje distinto al “Americano” , respecto a los compiladores o cualquier tema relacionado con la programación. La mayoría de nosotros aprendíamos con el diccionario al lado del teclado… Ni te cuento!

Creo que la mejor idea es decidir en función a tu ámbito de trabajo, no cabe la menor duda que si tu carrera profesional se desarrollara en un entorno de negocio donde se utiliza el Español y el equipo interactúa en Español la mejor decisión es utilizar el Visual Studio en Español, programando el código en “Español” con comentarios, nomenclaturas, definiciones etc. Es increíble gozar del excelente trabajo realizado por MS para proveer a los desarrolladores de una adaptación perfecta a un gran número de idiomas y vale la pena aprovechar todo ese potencial. Utilizar Visual Studio no es una simple decisión de mandatos de Lenguaje y menús… no olvides que toda documentación, ayuda y enlaces es fundamental tenerla en la lengua que hablamos, para de esa forma disponer de un rápido entendimiento y compresión sin dejar dudas en la interpretación Inglés/Español/Frances/Aleman... date cuenta que detrás de cada lenguaje un numeroso equipo de personas que no solo traducen texto, si no que adaptan e interpretan el conocimiento para cada uno de los idiomas/culturas.

Si por el contrario tu futuro se fija en el entorno anglosajón y tu negocio interactuara con equipos o desarrolladores de otros países, entonces no cabe duda que la mejor opción sea tomar el esfuerzo de pensar en “Ingles” y realizar tus desarrollos como si vivieras en un país de lengua Inglesa, incluyendo entorno, documentación…etc.

Para sacar el mayor provecho a nuestra capacidad, es fundamental desenvolvernos en el lenguaje en el que tenemos nuestros pensamientos… de esa forma evitamos tener que andar “traduciendo” ganando consecuentemente tiempo y concentración.

Saludos a todos,
Pep Lluis,

Posted by peplluis | with no comments
Filed under:

A menudo en los foros aparece la pregunta de cómo actualizar una BD utilizando un DataGridView. Aquí os dejo una forma de realizarlo. Espero que os sea útil.

Saludos,
Pep Lluis,

'
'Definir enlace a datos y objetos del form

Private MiConexion As New SqlConnection( _

   "Datasource=.\SQLEXPRESS;AttachDbFilename=C:\Temp\NORTHWND.MDF" + _
   ";Integrated Security=True;Connect Timeout=30;User Instance=True")
Private MiAdaptador As New SqlDataAdapter("SELECT * FROM Shippers", MiConexion)
Private MiDataSet As New DataSet()

Private MiEnlazador As New BindingSource

 

Private MidataGriView As New DataGridView

Private BotonGuardar As New Button

'

'En tiempo de carga...
Private Sub Form1_Load(…..) Handles MyBase.Load
    MessageBox.Show(My.Computer.FileSystem.CurrentDirectory)

    'Poner titulo a la aplicacion

    Me.Text = "Mantenimiento de Shippers"

    'Añadir DataGriView

    MidataGriView.Dock = DockStyle.Top

    Me.Controls.Add(MidataGriView)

    BotonGuardar.Dock = DockStyle.Bottom

    'Añadir Boton de Guardar

    BotonGuardar.Text = "Guardar Cambios"

    Me.Controls.Add(BotonGuardar)

    AddHandler BotonGuardar.Click, AddressOf Guardar
    Dim commandbuilder As New SqlCommandBuilder(Me.MiAdaptador)

    MiConexion.Open()

    MiAdaptador.Fill(MiDataSet)

    MiEnlazador.DataSource = MiDataSet.Tables(0)

    MidataGriView.DataSource = MiEnlazador

End Sub

'

'Actualizar la tabla enlazada con el DataGridView

Private Sub Guardar(…..)
    Me.MiAdaptador.Update(CType(Me.MiEnlazador.DataSource, DataTable))

End Sub

Posted by peplluis | 25 comment(s)
Filed under: ,

Muchos de nosotros, sobre todo los históricos de VB, hemos pasado días enteros escribiendo sentencias donde abundan un buen numero de liados entramados de condicionales…

If Expresion1 And (Not Expresion2) And Expresion3 Then ....

Es normal dentro de nuestra concentración al escribir código, que pongamos nuestro foco de atención en resolver el planteamiento más que en imaginarnos lo que ocurre en el momento de su ejecución. Sin ir más lejos cuántos de nosotros nos abstraemos del algoritmo y pensamos en las miles o millones de veces que llegara a ejecutarse la evaluación de dichas expresiones. Y cuántos de nosotros  a pesar de ejecutarse en un procesador capaz de recorrer  millones de Instrucciones por segundo, intentamos abstraernos en un pensamiento “ecologista” en tanto a no malbaratar la circulación inútil de ‘bitios’. La respuesta es “Algunos de nosotros SI pensamos en todo esto” y como no, VB también!

Ahora toca preguntarnos ¿y esto que viene a contarnos?... la respuesta seria pues AndAlso, what else!

Cuando detrás de un condicional ‘If’ agrupamos varias expresiones enlazadas con operadores, a saber ‘Or’… ‘And’, debemos tener muy en cuenta que el resultado será fruto de la evaluación de todos ellos con el consecuente consumo de procesador.

Expresión 1

AND Expresión 2

Resultado

Verdadero

Verdadero

Verdadero

Verdadero

Falso

Falso

Falso

Verdadero

Falso

Falso

Falso

Falso

 

Pero para que tanto ruido?
Intentando buscar justificaciones, escribiendo un poquito más tendremos a nuestra disposición ‘AndAlso’

Expresión 1

ANDALSO Expresión 2

Resultado

Verdadero

Verdadero

Verdadero

Verdadero

Falso

Falso

Falso

No se Evalúa

Falso

 

Aun así seguro que mas de uno ponéis cara de extrañados, bien el matiz se encuentra en que “No se Evalúa” significa que “No se procesa” por lo que si encadenamos varias evaluaciones de expresiones con ‘and’, usando ‘andalso’ ahorraremos en consumo de proceso, por lo que solo continuara evaluando las expresiones si la precedente es ‘Verdadera’ y finalizara la evaluación del resto de expresiones al obtener el primer ‘falso’.

Sin duda simpáticas historias.
Pep Lluis,

Por Cierto os he hablado de 'OrElse'... vaya! pues tambien existe!

Expresión 1

Expresión 2

Resultado

Verdadero

No se evalúa

Verdadero

Falso

Verdadero

Verdadero

Falso

Falso

Falso

Lo de WhatElse vamos a dejarlo para otro dia jajajajaja.

Posted by peplluis | with no comments
Filed under: ,

Que nadie se lo tome a mal! Pero después de reírnos un rato, nos encontramos a menudo perdiendo la tarde en búsqueda de cómo realizar las cosas más sencillas. Intentando dar respuesta a la repetida pregunta de cómo posicionarnos dentro de nuestro DataGridView… Ahí va la respuesta:

Dim Columna As Integer = 0, Fila As Integer = 0
Me.DataGridView1.CurrentCell = _
   Me.DataGridView1(Columna, Fila)

La de tumbos que a veces damos, porque creo que difícil no es! J
Saludos,
Pep Lluis,

Posted by peplluis | 11 comment(s)
Filed under:

En algunas ocasiones he leído alguna respuesta en los foros contestando la forma en que podemos enumerar nuestros puertos “COM” y dejarlos listos para ser seleccionados por el usuario… sin entrar en valorar complejas respuestas con ‘For Each’ ‘Add’ y etc, os dejo un código ejemplo de cómo… pero en una sola línea!!

Me.ComboBox1.Items.AddRange(My.Computer.Ports.SerialPortNames.ToArray)

... luego en 'ComboBox1.SelectedIndexChanged'
PuertoSerie.Close()
PuertoSerie.PortName = ComboBox1.SelectedItem
PuertoSerie.Open()

Saludos,
Pep Lluis,

Posted by peplluis | 8 comment(s)
Filed under:

A cuerda de una pregunta en el foro (para principiantes),  donde se cuestiona porque el ‘timer’ deja de funcionar y no refresca el paso de los segundos cuando efectuamos una llamada a un procedimiento... vamos a exponer el siguiente argumento para intentar esclarecerlo.

Nuestro ‘Form’ se está rondando en su hilo de ejecución... por lo que cuando efectúas la llamada para "procesar la rutina", el ‘timer’ deja de refrescarse por falta de turno de ejecución al estar (nuestro hilo) ocupado en espera de recibir el retorno de la llamada a tal procedimiento.

Para no bloquear nuestro hilo de ejecución y poder continuar con otras tareas, deberemos llamar a ese proceso creando un nuevo hilo de ejecución, utilizando ‘Threading.Thread’ … aquí dejo un ejemplo donde muestra las dos situaciones de una forma muy básica.

En situación de ejecución, nuestro ‘form’ visualiza la fecha y hora actual en la barra de titulo. Al pulsar sobre el botón 1 se lanza la llamada al procedimiento 'readline' en espera de leer una línea recibida por el puerto serie, todo el ‘form’ quedara congelado hasta recibir esa línea, que de buena tinta sabemos que nunca llegara J  por lo tanto la barra de titulo quedara inanimada, pues el hilo está ocupado y el ‘timer1’ no dispone de turno de ejecución para dispar los eventos ‘tick’.

Sin embargo al hacer clic sobre el segundo botón, este crea un nuevo hilo de ejecución que apunta al mismo procedimiento pero con una nueva asignacion de ejecucion, haciendo autónomo su proceso en la llamada al procedimiento, así pues en este caso la barra de titulo reflejara en todo momento la fecha y hora, con independencia de si el procedimiento a finalizado o no, pues el hilo principal del 'form' continuara atendiendo y repartiendo la ejecución entre todos los objetos que tiene a su cargo... inclusive el nuevo hilo.

Para rodar este ejemplo, solo tienes que crear un nuevo proyecto ‘winform’ añadir un ‘timer’ y dos ‘Button’.

Espero que os sea útil y pido ‘sorrys’ por el rollo!
Pep Lluis,

Public Class Form1
    Private Puerto As New System.IO.Ports.SerialPort

    Private Sub Form1_Load(…..) Handles MyBase.Load
        Me.Timer1.Interval = 1000
        Me.Timer1.Enabled = True
        Me.Button1.Text = "Llamar Procedimiento"
        Me.Button2.Text = "Ejecutar nuevo Hilo"
        Puerto = My.Computer.Ports.OpenSerialPort("COM1")
    End Sub


    Private Sub Timer1_Tick(…..) Handles Timer1.Tick
        Me.Text = Date.Now
    End Sub

    Private Sub Button1_Click(…..) Handles Button1.Click
        Me.Button1.Enabled = False
        Me.Text = "*Ejecucion sin crear Hilo "
        Procedimiento()
        Me.Button1.Enabled = True
    End Sub

    Private Sub Button2_Click(…..) Handles Button2.Click
        Me.Button2.Enabled = False
        Me.Text = "*Ejecutar creando un nuevo Hilo"
        Dim MiHilo As New Threading.Thread(AddressOf Procedimiento)
        MiHilo.Start()
        'el timer continua con su ejecucion...        
        'Antes de lanzar una nueva llamada
        'deberiamos cancelar el hilo en espera
        'ejecutando : MiHilo.Abort() o controlando
        'su estado o control por ejemplo con :
        'MiHilo.IsAlive
        'MiHilo.Suspend()
        'MiHilo.Sleep()
    End Sub

    Private Sub Procedimiento()
        '
        'Esta funcion esta efectuando una llamada
        'a un procedimento que no finalizara hasta
        'completarse o exceder su tiempo de espera.
        Dim datos = Puerto.ReadLine
    End Sub
End
Class

Posted by peplluis | with no comments
Filed under:

En la mayoría de antiguos protocolos de comunicaciones “sobre todo Serie”, disponemos de algunos mecanismos para la detección y corrección de errores en el intercambio de tramas. En concreto hablando del puerto serie, a primer nivel disponemos del control de paridad con el que conseguimos descartar algunos de los errores de transmisión a nivel de byte, sin embargo muchos protocolos implementan un control a nivel de trama, en el que se realiza una suma de verificación de todos los bytes transmitidos. Esto es conocido como FCS o CRC que no deja de ser una referencia a un ‘checksum’ o verificación redundante. El resultado de la misma es añadido al final de la trama y enviado con el resto de datos. Una vez recibido por el terminal o dispositivo se efectuara la misma operación calculando de nuevo la FCS y comprobando que coincide con la transmitida… con ello conseguiremos tener un elevado porcentaje de confianza en tanto la integridad de los datos recibidos.

El cálculo puede presentarse más o menos complejo dependiendo de la implementación de esta verificación según el protocolo, aunque la mayoría de ellos se conforman con aplicar un simple ‘XOR’… veamos un ejemplo común:

    '
    ' Calculo de la FCS de una trama
    ' Esta funcion devolvera el valor hexadecimal
    ' en forma de dos caracters ASCII

    Private Function Fcs(ByVal Trama As String) As String
        Dim MiFcs As Integer = 0
        For Each c In Trama
            MiFcs = Asc(c) Xor MiFcs
        Next
        Return Hex(MiFcs).ToString
    End Function

Para los amantes de bool... Recordemos la tabla para el ‘Or’ Exclusivo : MiFcs = Asc(c) Xor MiFcs

p

q

p ≠ q

Falso

Falso

Falso

Falso

Verdadero

Verdadero

Verdadero

Falso

Verdadero

Verdadero

Verdadero

Falso

Entonces solo nos faltara alinear los valores binarios del resultado anterior; efectuar el ‘Xor’ y continuar efectuando la misma operación hasta agotar el ultimo byte. Demostrar el tema de acarreos y resultados con 16/32 bits en hexadecimal lo dejamos para otro dia J o bién podeis continuar leyendo en : http://www.ietf.org/rfc/rfc2615.txt?number=2615 Por ahora me conformo pensando que :  Hex(MiFcs).ToString, soluciona mi problema. 

Resultado_Anterior

0

1

0

1

0

1

0

1

Byte_Actual

0

0

1

1

1

0

0

1

Resultado_Actual

0

1

1

0

1

1

0

0

Ya no os podéis quejar que con el avance de los lenguajes nos alejamos de los ‘Bites’.

Saludos,
Pep Lluis,

PD. EN VB6 Tenia este aspecto

'

' ** Calculo de la Fcs

' Al mas puro VB6

'

Private Function Fcs$(Var)

Dim p As Integer, q As Integer

 For p = 1 To Len(Var)

   q = q Xor Asc(Mid$(Var, p, 1))

 Next p

Fcs$ = Right$("0" + Hex$(q), 2)

End Function

 

Posted by peplluis | with no comments
Filed under:

Algunas de las preguntas relacionadas con SQL Express y los errores generados al intentar abrir una conexión en una implementación diferente de la máquina de desarrollo, son debidas a que el usuario no dispone del suficiente ‘Grant Access’ J

Desde el símbolo de sistema (Ejecutando como Administrador) y entendiendo que no dispones del  'Management Studio' :

Cmd Grant Access

Salud!

Posted by peplluis | with no comments
Filed under:

Aquí una idea de cómo utilizar MDF y MDB’s.

En este ejemplo utilizamos la tabla de proveedores de una MDB para rellenar un DataGridView de los productos del proveedor en la MDF de 'NorthWnd' seleccionado en el Combo. 

Combo+Datagrid

Debo advertir que el siguiente codigo no ejemplo de metodologia, tan solo pretende enseñar en un solo ejemplo como conectar una BD Access y otra de SQL, pero en ningun caso es un modelo de uso, pues en realidad nunca he trabajado con una aplicacion que utilice los dos formatos conjuntamente.

Imports System.Data.OleDb

Imports System.Data.SqlClient

 

Public Class Form1

    Private WithEvents ComboBox1 As New ComboBox

    Private WithEvents DataGridView1 As New DataGridView

    '

    'Definir enlace a datos y objetos del form

    Private SQLConexion As New SqlConnection( _

        "Data Source=.\SQLEXPRESS;AttachDbFilename=C:\Temp\Northwnd.mdf" + _

        ";Integrated Security=True;Connect Timeout=30;User Instance=True")

 

    Private MDBConexion As New OleDbConnection( _
        "Provider=Microsoft.Jet.OLEDB.4.0;" + _

        "Data Source=C:\Temp\bd1.mdb")

 

    Private Sub Form1_Load() Handles Me.Load

        Me.Controls.Add(ComboBox1)

        Me.ComboBox1.Dock = DockStyle.Top

        AddHandler ComboBox1.SelectedIndexChanged, AddressOf Obtener_Articulos

 

        Me.Controls.Add(Me.DataGridView1)

        Me.DataGridView1.Dock = DockStyle.Fill

 

        Me.ComboBox1.DisplayMember = "CompanyName"

        Me.ComboBox1.ValueMember = "SupplierID"

        Me.ComboBox1.DataSource = Obtener_Proveedores()

    End Sub

    '

    ' Cargar el DGV con la seleccion de articulos segun el proveedor

    Private Sub Obtener_Articulos()

        Dim Articulos = _
          "SELECT * FROM Products Where SupplierId = " + _
          ComboBox1.SelectedValue.ToString

        SQLConexion.Open()

        Dim MiSqladapter As New SqlDataAdapter

        MiSqladapter.SelectCommand = New SqlCommand(Articulos, SQLConexion)

        Dim MiTabla As New DataTable()

        MiSqladapter.Fill(MiTabla)

        SQLConexion.Close()

        Me.DataGridView1.DataSource = MiTabla

    End Sub

    '

    ' Obtener la tabla de proveedores como 'datasource del ComboBox'

    Private Function Obtener_Proveedores()

        MDBConexion.Open()

        Dim MDBadapter As New OleDbDataAdapter("Select * from Suppliers", MDBConexion)

        Dim MiTabla As New DataTable()

        MDBadapter.Fill(MiTabla)

        Return MiTabla

    End Function

 

End Class

Posted by peplluis | with no comments
Filed under: ,

Sorprendentemente continúan llegando inquietudes preguntando cómo se abre una BD de Access en las nuevas versiones de VB.  Algunos asiduos a este formato han sufrido el desconcertante mensaje… no está en el equipo local? Cuando la realidad es que no esta implementado!

Para dar una buena explicación, recibimos este mensaje cuando utilizamos ‘OLEDB’ en un sistema X64 y ese es el detalle. No existe una implementación de ‘OLEDB’ para 64 bits.

La única solución es desarrollar en 32Bits, aunque esto ultimo NO signifique que tengamos que reinstalar el sistema operativo... tan solo nesitaremos seleccionar ‘X86’ como ‘CPU de destino’ en las ‘Opciones de Compilación Avanzadas’ de la pestaña ‘Compilar’ en las propiedades de ‘My Project’

Espero que esto os ahorre alguna que otra hora de busqueda.
Pep Lluis,

Posted by peplluis | 72 comment(s)
Filed under: ,

Este es uno de los textos de error que mas amenudo se enfrenta a los que intentan actualizar la informacion enlazada de un DGV’s y una MDB.

Aunque en muchos otros foros/post se advierte de debemos utilizar nombres de campo que no esten reservados, caemos y volvemos a caer en el error de usar nombres con caracteres no admitidos. Un simple espacio al nombrar el campo provocara una excepcion tanto en la operación de ‘INSERT’ Como ‘UPDATE’. Suerte que a grandes males… grandes remedios J

Ejemplo :   el Nombre ‘Columna A’ generara una excepcion
Sin embargo  el nombre ‘Columna_A’ no genera ninguna excepcion… asi de simple.

Os recuerdo el enlace con la lista de palabras reservadas que no pueden utilizarse para nombrar los campos de una MDB que posteriormente utilizaremos enlazada con un DataGridView y un ‘OleDb.OleDbCommandBuilder(MiMdbAdaptador)’

http://support.microsoft.com/kb/248738

En caso contrario las únicas opciones disponibles para continuar utilizando dichos nombres, será construir el’INSERT’… ‘UPDATE’ commands de forma manual o utilizar la opción de ‘Origen de Datos’ generado por Visual Studio.

Saludos,
Pep Lluis,

Posted by peplluis | 1 comment(s)
Filed under: ,

Independientemente de las mil y una formas para filtrar/formatear entradas de texto, me gustan las sencillas sin retorcimientos. Aquí te dejo una idea de cómo aplicar reglas cuando se trata de todo un form, aunque trabajandolo puedes customizar el comportamiento en funcion al control que tiene el foco. No olvides que tambien dispones de un espacio de nombres sensacional :

Imports System.Text.RegularExpressions

Aunque como te digo, en determinadas ocasiones cabe aplicar lo sencillo si con ello cubrimos las necesidades. ;-)
El siguiente ejemplo demuestra como filtrar la pulsación de cualquier tecla que no sea numerica o coma.

Private Sub Form1_Load() Handles MyBase.Load
    Me.KeyPreview = True
End Sub 

Protected Overrides Function ProcessDialogKey(ByVal keyData As System.Windows.Forms.Keys) As Boolean
    Select Case keyData
        ' 48 a 57  = numericas encima teclado alfabetico
        ' 97 a 106 = Numericas teclado numerico
        Case 48 To 57, 97 To 106, Keys.Oemcomma
            'Solo devolver las pulsaciones que pasan el filtro
            Return MyBase.ProcessDialogKey(keyData)
        Case Else
            'Evitar la propagacion de la pulsacion
            'de teclas que no nos interesan
            Return True
    End Select
End Function

Lo Bueno y simple… Dos veces bueno!
Pep Lluis

Posted by peplluis | 4 comment(s)
Filed under: