hoy me ha tocado hacer unas pruebecillas de compatibilidad con veriosnes anteriores de flash.
En determinadas circunstancias no me dejaba instalar versiones antíguas aludiendo que hay versiones 'más recientes'.
Finalmente he encontrado que en:
[-HKEY_LOCAL_MACHINE\SOFTWARE\Macromedia\FlashPlayer\SafeVersions]
se alamcena esa información.
Eso mismo incluido en un archivo .reg (bien formado) nos borraría la clave.
Wow! Cómo pasa el tiempoooooo. El anterior post es muy, muy, muy viejo. Si lo que quieres es utilizar el VS2008 tendrás q tener en cuenta algunas variaciones.
Imports System
Imports System.Threading
' la clase miHilo contiene la información necesaria para
' la tarea, el método que la realiza y el delegado al
' que llamaremos cuando la tarea concluya.
'
Public Class miHilo
' Información a procesar
Private pParrafada As String
Private pValor As Integer
' Delegado utilizado para ejecutar el método callback
' cuando finalice la tarea.
Private pCallback As CallBackDef
' El constructor obtiene la información de estado y el
' delegado del callback.
Public Sub New(ByVal texto As String, ByVal numero As Integer, _
ByVal callback As CallBackDef)
pParrafada = texto
pValor = numero
pCallback = callback
End Sub
' El procedimiento del hilo realiza las tareas, como
' formatear e imprimir un documento, y despues invoca
' al delegado con el número de líneas impresas.
Public Sub Tarea()
Console.WriteLine(parrafada, valor)
If Not pCallback Is Nothing Then pCallback(1)
End Sub
End Class
' Delegado que define la firma del método del callback
'
Public Delegate Sub CallBackDef(ByVal numLineas As Integer)
' Punto de entrada del ejemplo
'
Public Class Ejemplo
Public Shared Sub Main()
' Suministrar la información requerida por el trabajo
Dim hiloEjemplo As New miHilo( "Este informe muestra {0} líneas.", 42, New CallBackDef(AddressOf MostrarResultado) )
Dim t As New Thread(AddressOf hiloEjemplo.Tarea)
t.Start()
Console.WriteLine("El hilo principal lanza la tarea y espera.")
t.Join()
Console.WriteLine("La tarea idependiente ha concluido; Finaliza el hilo principal.")
End Sub
' El método de callback debe coincidir con la firma del
' delegado.
'
Public Shared Sub MostrarResultado(ByVal numLineas As Integer)
Console.WriteLine("El trabajo independiente ha imprimido {0} líneas.", numLineas)
End Sub
End Class
Imports System.Threading
' la clase miHilo contiene la información necesaria para
' la tarea, el método que la realiza y el delegado al
' que llamaremos cuando la tarea concluya.
'
Public Class miHilo
' Información a procesar
Private pParrafada As String
Private pValor As Integer
' Delegado utilizado para ejecutar el método callback
' cuando finalice la tarea.
Private pCallback As CallBackDef
' El constructor obtiene la información de estado y el
' delegado del callback.
Public Sub New(ByVal texto As String, ByVal numero As Integer, _
ByVal callback As CallBackDef)
pParrafada = texto
pValor = numero
pCallback = callback
End Sub
' El procedimiento del hilo realiza las tareas, como
' formatear e imprimir un documento, y despues invoca
' al delegado con el número de líneas impresas.
Public Sub Tarea()
Console.WriteLine(parrafada, valor)
If Not pCallback Is Nothing Then pCallback(1)
End Sub
End Class
' Delegado que define la firma del método del callback
'
Public Delegate Sub CallBackDef(ByVal numLineas As Integer)
' Punto de entrada del ejemplo
'
Public Class Ejemplo
Public Shared Sub Main()
' Suministrar la información requerida por el trabajo
Dim hiloEjemplo As New miHilo( "Este informe muestra {0} líneas.", 42, New CallBackDef(AddressOf MostrarResultado) )
Dim t As New Thread(AddressOf hiloEjemplo.Tarea)
t.Start()
Console.WriteLine("El hilo principal lanza la tarea y espera.")
t.Join()
Console.WriteLine("La tarea idependiente ha concluido; Finaliza el hilo principal.")
End Sub
' El método de callback debe coincidir con la firma del
' delegado.
'
Public Shared Sub MostrarResultado(ByVal numLineas As Integer)
Console.WriteLine("El trabajo independiente ha imprimido {0} líneas.", numLineas)
End Sub
End Class
Esto es una traducción de un artículo de Matthew Arnheiter que se puede encontrar en devx.com (http://www.devx.com/DevX/10MinuteSolution/20365/0/page/4). Explica de manera muy sencilla como adentrarse en el mundo de la programación multihilo con VB.NET. Me pareció muy útil tenerlo traducido para entenderlo mucho mejor... Espero que también le sea útil a cualquera que llegue hasta aquí. En cualquier caso el mérito es de Mathew, a quien NO tengo el gusto de conocer ;).
Ya que VB.Net corre en un Entorno Común de Ejecución (Common Language Runtime) adquiere nuevas capacidades, una de ellas es la habilidad para crear aplicaciones multi-hilo sin restricciones.
Trabajando con Hilos
VB.NET hace sencillo comenzar a trabajar con hilos, Hay algunas peculiaridades que veremos luego, pero lancémonos ya a crear un simple formulario que cree un nuevo hilo para que funcione como un proceso de fondo. La primera cosa que necesitaremos es crear el proceso de fondo en un nuevo hilo. El siguiente código se ejecuta infinitamente – es un bucle infinito.
Este código ejecuta el bucle indefinidamente añadiendo ítems en cada iteración a un cuadro de lista (listbox) del formulario. Como observación complementaria, si no estás familiarizado con VB.NET te habrás dado cuenta de algunas cosas más que no no se pueden hacer en VB6.
Una vez que tenemos un proceso de trabajo creado, necesitamos asignar este bloque de código a un nuevo hilo y comenzar su ejecución. Para realizar esto utilizamos el objeto Thread que es parte del espacio de nombres (namespace) System.Threading de las clases del Framework .NET- Cuando instanciamos una nueva clase Thread, en su constructor le pasamos una referencia al bloque de código que queremos ejecutar. El siguiente código crea un nuevo objeto Hilo y le pasa su referencia al ProcesodeFondo:
El operador AddressOf crea un objeto delegado del método ProcesodeFondo. En VB.NET un delegado es un puntero a una type-safe función de un objeto. Una vez q se ha instanciado el hilo, arrancamos la ejecución del código llamando al método Start() del Hilo.
Manteniendo todo bajo control
Después del arranque del hilo, tienes algún control sobre su estado utilizando algunos métodos del objeto Thread. Puedes pausar su ejecución llamando al método Thread.Sleep. Este método toma un valor entero que determina cuánto tiempo debe dormir el hilo. Si quisiéramos ralentizar la adición de ítemes al cuadro de lista en el ejemplo anterior, incluiremos una llamada al método Sleep como en este ejemplo de código:
CurrentThread es una propiedad estática y pública que permite adquirir una referencia al hilo en ejecución.
También podemos hacer dormir al hilo (Sleep) por un periodo de tiempo indefinido llamando a Thread.Sleep (System.Threading.Timeout.Infinite). Para sacar al hilo de este ‘sueño’ podemos llamar al método Thread.Interrupt.
Muy parecidos a Sleep e Interrupt son Suspend y Resume. Suspend nos permite bloquear un hilo hasta que otro hilo llame a Thread.Resume. La diferencia entre Sleep y Suspend es que éste último no pone al hilo en estado de espera inmediatamente. El hilo se suspende hasta que el runtime .NET determina que está en un punto de ejecución seguro para suspenderlo. Sleep pone al hilo en estado de espera inmediatamente.
Por último Thread.Abort detiene la ejecución de un hilo. En nuestro sencillo ejemplo, queremos añadir otro botón en el formulario que nos permita detener el proceso. Para ello lo único que tenemos que hacer es una llamada al método Thread.Abort, así:
Aquí es donde se puede ve el poder del multithreading. El formulario se nuestra más suelto al usuario porque está corriendo en un Thread.Sleep(System.Threading.Timeout.Infinite).
Pasando datos entre Procedimientos Multihilo
El último ejemplo muestra una situación muy frecuente. La programación multihilo conlleva complicaciones que hay evitar mediante código. Un problema que nos vamos a encontrar es pasar información a y desde el procedimiento al constructor de la clase Thread, Por citar un ejemplo, el procedimiento que arranca un hilo no le puede pasar ningún parámetro ni se le pueden devolver datos a él.
Esto se debe a que el procedimiento que le pasamos al constructor no puede tener parámetros ni un valor de retorno. Para evitar esto, envolvemos el procedimiento en una clase donde los parámetros el método son escritos como campos de la clase.
Un sencillo ejemplo de esto sería un procedimiento que calculase el cuadrado de un número:
Para hacer que este procedimiento esté disponible en un Nuevo hilo, tenemos que envolverlo en una clase:
Utilizamos este código para lanzar el procedimiento CalcularCuadrado en un nuevo hilo:
Observa que una vez que se arranca el hilo no inspeccionamos el resultado (cuadrado) de la clase, porque no tenemos garantías de que se haya ejecutado una vez que hayamos llamado al método Start del hilo.
Hay varias maneras de retornar valores desde otros hilos. La forma más sencilla es provocar un evento cuando el hilo se ha completado. Veremos también otro método de retornar valores en la siguiente sección cuando hablemos de sincronización. El siguiente código añade las declaraciones del evento a la ClaseCuadrado.
Capturar los eventos en el código llamante no cambia mucho desde VB6, se siguen declarando las variables WithEvents y se maneja el evento en un procedimiento. La parte que ha cambiado es que declaramos que un procedimiento maneja el evento utilizando la palabra reservada Handles y no bajo la nomenclatura de Object_Event como en VB6.
Con este método conviene tener en cuenta que es el procedimiento el que maneja el evento, en este caso CuadradoEventHandler, correrá dentro del hilo que provocó el evento. No corre dentro del hilo desde el que se está ejecutando el formulario.
Sincronizando los hilos
VB.NET contiene algunas sentencias que proporcionan sincronización de hilos. En el ejemplo del cuadrado de un número, podríamos querer sincronizar el hilo que hace los calculos para esperar la finalización del cálculo para que podamos recoger el resultado. Otro ejemplo podría ser que tuviéramos un hilo ordenando un array y que quisiéramos esperar a que estuviese ordenado para poder utilizarlo. Para realizar estas sincronizaciones, VBNET proporciona la sentencia SyncLockEnd SynLock y el método Thread.Join.
SynLock obtiene un bloqueo exclusivo a la referencia de un objeto que se le pasa. Obteniendo este bloqueo exclusivo podemos asegurarnos de que múltiples hilos no accederán a datos compartidos o que el código se ejecutará en múltiples hilos. Un objeto que nos conviene utilizar en estos casos es el objeto System.Type asociado a cada clase. El objeto System.Type puede ser recuperado utilizando el método GetType.
Finalmente, el método Thread.Join nos permite esperar un determinado tiempo hasta que el hilo se haya completado. Si el hilo se completa antes del tiempo especificado, Thread.Join devuelve True (Verdadero), de lo contrario devuelve False (Falso). En el ejemplo del cuadrado, si no hubiéramos querido utilizar eventos, podríamos haber llamado al método Thread.Join para saber si había acabado el cálculo. El código hubiera quedado así:
Haciéndolo de esta forma conviene tener en cuenta que el procedimiento es quien maneja el evento, en este caso CuadradoEventHandler, correrá dentro del hilo que provocó el evento. No corre dentro del hilo desde el que el se ejecuta el formulario.
Ya que VB.Net corre en un Entorno Común de Ejecución (Common Language Runtime) adquiere nuevas capacidades, una de ellas es la habilidad para crear aplicaciones multi-hilo sin restricciones.
Trabajando con Hilos
VB.NET hace sencillo comenzar a trabajar con hilos, Hay algunas peculiaridades que veremos luego, pero lancémonos ya a crear un simple formulario que cree un nuevo hilo para que funcione como un proceso de fondo. La primera cosa que necesitaremos es crear el proceso de fondo en un nuevo hilo. El siguiente código se ejecuta infinitamente – es un bucle infinito.
Private Sub ProcesodeFondo()
Dim i As Integer = 1
Do While True
ListBox1.Items.Add("Iteraciones: " + i)
i += 1
Loop
End Sub
Este código ejecuta el bucle indefinidamente añadiendo ítems en cada iteración a un cuadro de lista (listbox) del formulario. Como observación complementaria, si no estás familiarizado con VB.NET te habrás dado cuenta de algunas cosas más que no no se pueden hacer en VB6.
- Asignar valores a una variable ene l momento de su declaración.
- Utilizar el operador +=, en lugar de i=1+1
- No se utiliza la palabra clave Call.
Una vez que tenemos un proceso de trabajo creado, necesitamos asignar este bloque de código a un nuevo hilo y comenzar su ejecución. Para realizar esto utilizamos el objeto Thread que es parte del espacio de nombres (namespace) System.Threading de las clases del Framework .NET- Cuando instanciamos una nueva clase Thread, en su constructor le pasamos una referencia al bloque de código que queremos ejecutar. El siguiente código crea un nuevo objeto Hilo y le pasa su referencia al ProcesodeFondo:
Dim t As Thread
t = New Thread(AddressOf Me.ProcesodeFondo)
t.Start()
El operador AddressOf crea un objeto delegado del método ProcesodeFondo. En VB.NET un delegado es un puntero a una type-safe función de un objeto. Una vez q se ha instanciado el hilo, arrancamos la ejecución del código llamando al método Start() del Hilo.
Manteniendo todo bajo control
Después del arranque del hilo, tienes algún control sobre su estado utilizando algunos métodos del objeto Thread. Puedes pausar su ejecución llamando al método Thread.Sleep. Este método toma un valor entero que determina cuánto tiempo debe dormir el hilo. Si quisiéramos ralentizar la adición de ítemes al cuadro de lista en el ejemplo anterior, incluiremos una llamada al método Sleep como en este ejemplo de código:
Private Sub ProcesodeFondo()
Dim i As Integer = 1
Do While True
ListBox1.Items.Add("Iteraciones: " + i)
i += 1
Thread.CurrentThread.Sleep(2000)
Loop
End Sub
CurrentThread es una propiedad estática y pública que permite adquirir una referencia al hilo en ejecución.
También podemos hacer dormir al hilo (Sleep) por un periodo de tiempo indefinido llamando a Thread.Sleep (System.Threading.Timeout.Infinite). Para sacar al hilo de este ‘sueño’ podemos llamar al método Thread.Interrupt.
Muy parecidos a Sleep e Interrupt son Suspend y Resume. Suspend nos permite bloquear un hilo hasta que otro hilo llame a Thread.Resume. La diferencia entre Sleep y Suspend es que éste último no pone al hilo en estado de espera inmediatamente. El hilo se suspende hasta que el runtime .NET determina que está en un punto de ejecución seguro para suspenderlo. Sleep pone al hilo en estado de espera inmediatamente.
Por último Thread.Abort detiene la ejecución de un hilo. En nuestro sencillo ejemplo, queremos añadir otro botón en el formulario que nos permita detener el proceso. Para ello lo único que tenemos que hacer es una llamada al método Thread.Abort, así:
Private Sub Button2_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button2.Click
t.Abort()
End Sub
Aquí es donde se puede ve el poder del multithreading. El formulario se nuestra más suelto al usuario porque está corriendo en un Thread.Sleep(System.Threading.Timeout.Infinite).
Pasando datos entre Procedimientos Multihilo
El último ejemplo muestra una situación muy frecuente. La programación multihilo conlleva complicaciones que hay evitar mediante código. Un problema que nos vamos a encontrar es pasar información a y desde el procedimiento al constructor de la clase Thread, Por citar un ejemplo, el procedimiento que arranca un hilo no le puede pasar ningún parámetro ni se le pueden devolver datos a él.
Esto se debe a que el procedimiento que le pasamos al constructor no puede tener parámetros ni un valor de retorno. Para evitar esto, envolvemos el procedimiento en una clase donde los parámetros el método son escritos como campos de la clase.
Un sencillo ejemplo de esto sería un procedimiento que calculase el cuadrado de un número:
Function Cuadrado(ByVal Value As Double) As Double
Return Value * Value
End Function
Para hacer que este procedimiento esté disponible en un Nuevo hilo, tenemos que envolverlo en una clase:
Public Class ClaseCuadrado
Public Valor As Double
Public Cuadrado As Double
Public Sub CalcularCuadrado()
Cuadrado = Valor * Valor
End Sub
End Class
Utilizamos este código para lanzar el procedimiento CalcularCuadrado en un nuevo hilo:
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
Dim oCuadrado As New ClaseCuadrado()
t = New Thread(AddressOf oCuadrado.CalcularCuadrado)
oCuadrado.Valor = 30
t.Start()
End Sub
Observa que una vez que se arranca el hilo no inspeccionamos el resultado (cuadrado) de la clase, porque no tenemos garantías de que se haya ejecutado una vez que hayamos llamado al método Start del hilo.
Hay varias maneras de retornar valores desde otros hilos. La forma más sencilla es provocar un evento cuando el hilo se ha completado. Veremos también otro método de retornar valores en la siguiente sección cuando hablemos de sincronización. El siguiente código añade las declaraciones del evento a la ClaseCuadrado.
Public Class ClaseCuadrado
Public Valor As Double
Public Cuadrado As Double
Public Event HiloCompleto(ByVal Cuadrado As Double)
Public Sub CalcularCuadrado()
Cuadrado = Valor * Valor
RaiseEvent HiloCompleto(Cuadrado)
End Sub
End Class
Capturar los eventos en el código llamante no cambia mucho desde VB6, se siguen declarando las variables WithEvents y se maneja el evento en un procedimiento. La parte que ha cambiado es que declaramos que un procedimiento maneja el evento utilizando la palabra reservada Handles y no bajo la nomenclatura de Object_Event como en VB6.
Dim WithEvents oCuadrado As ClaseCuadrado
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
oCuadrado = New ClaseCuadrado()
t = New Thread(AddressOf oCuadrado.CalcularCuadrado)
oCuadrado.Valor = 30
t.Start()
End Sub
Sub CuadradoEventHandler(ByVal Cuadrado As Double) _
Handles oCuadrado.HiloCompleto
MsgBox("El cuadrado es " & Cuadrado )
End Sub
Con este método conviene tener en cuenta que es el procedimiento el que maneja el evento, en este caso CuadradoEventHandler, correrá dentro del hilo que provocó el evento. No corre dentro del hilo desde el que se está ejecutando el formulario.
Sincronizando los hilos
VB.NET contiene algunas sentencias que proporcionan sincronización de hilos. En el ejemplo del cuadrado de un número, podríamos querer sincronizar el hilo que hace los calculos para esperar la finalización del cálculo para que podamos recoger el resultado. Otro ejemplo podría ser que tuviéramos un hilo ordenando un array y que quisiéramos esperar a que estuviese ordenado para poder utilizarlo. Para realizar estas sincronizaciones, VBNET proporciona la sentencia SyncLockEnd SynLock y el método Thread.Join.
SynLock obtiene un bloqueo exclusivo a la referencia de un objeto que se le pasa. Obteniendo este bloqueo exclusivo podemos asegurarnos de que múltiples hilos no accederán a datos compartidos o que el código se ejecutará en múltiples hilos. Un objeto que nos conviene utilizar en estos casos es el objeto System.Type asociado a cada clase. El objeto System.Type puede ser recuperado utilizando el método GetType.
Public Sub CalcularCuadrado()
SyncLock GetType(ClaseCuadrado)
Cuadrado = Valor * Valor
End SyncLock
End Sub
Finalmente, el método Thread.Join nos permite esperar un determinado tiempo hasta que el hilo se haya completado. Si el hilo se completa antes del tiempo especificado, Thread.Join devuelve True (Verdadero), de lo contrario devuelve False (Falso). En el ejemplo del cuadrado, si no hubiéramos querido utilizar eventos, podríamos haber llamado al método Thread.Join para saber si había acabado el cálculo. El código hubiera quedado así:
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
Dim oCuadrado As New ClaseCuadrado()
t = New Thread(AddressOf oCuadrado.CalcularCuadrado)
oCuadrado.Valor = 30
t.Start()
If t.Join(500) Then
MsgBox(oCuadrado.Cuadrado)
End If
End Sub
Haciéndolo de esta forma conviene tener en cuenta que el procedimiento es quien maneja el evento, en este caso CuadradoEventHandler, correrá dentro del hilo que provocó el evento. No corre dentro del hilo desde el que el se ejecuta el formulario.
Tenemos un servidor con win 2003 y la necesidad de crear en él un recurso compartido, pero con otro nombre de máquina. Porque sabemos q en un futuro no muy lejano tendremos una nueva máquina que sí tendra ese segundo nombre...Nada más fácil, pensarás, un nuevo registro DNS y a correr...
PEEEROOOOOO... En los clientes verás aparecer un bonito mensaje:
PEEEROOOOOO... En los clientes verás aparecer un bonito mensaje:
"No estuvo conectado porque existe un nombre duplicado en la red. Vaya a Sistema en Panel de control para cambiar el nombre de equipo y volverlo a intentar"
Una característica de seguridad de windows 2003 es la de enviar un mensaje de error a una estación q se conecte a un recurso compartido pero refiriéndose a él con otro nombre de máquina.
http://support.microsoft.com/kb/914056 Habla de ello (en otro contexto de error) pero da la solución:
Editando
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\lanmanserver\parametersy añadiendo:
DisableStrictNameChecking REG_DWOD Valor=1Queda resuelto. (El nombre de la clave es auto-explicativo).