Introducción:
En esta nueva revisión de mi utilidad gsBuscarTexto he
corregido algún que otro bug o forma no correcta de funcionar, como
por ejemplo, que al abrir desde el menú contextual siempre (o casi) se añadían los directorios
seleccionados a los que ya hubiera en la lista de directorios, o que al seleccionar solo un
directorio no se mostrara.
Esta versión está preparada para reemplazar, pero no reemplaza, lo que hace es que si llega a
hacer los cambios (mejor dicho, se cumple las condiciones para hacer el cambio), lo que hace es
mostrar en una ventana, el fichero original y el texto cambiado, que lo quieres guardar, pues tu
mismo... esto lo dejaré así hasta que compruebe que todo funciona.
Los cambios no se pueden hacer en las extensiones marcadas como no utilizables, ahora mismo
he puesto estas versiones como "no utilizables":
.*; .com; .exe; .dll; .lib; .tlb; .bin; .ocx; .zip; .rar; .cab; .jpg; .png; .gif; .tif; .ico;
.bmp
Más abajo te explico más cosas sobre esto de reemplazar.
Nota:
Te recomiendo que solo uses la opción de cambiar/reemplazar con ficheros de texto... no sea que
no se guarde bien. Los de tipo RTF también los soporta, ya que uso un control
RichTextbox para mostrar
el texto.
Además de esta opción cuasi-reemplazadora, también he añadido la opción de buscar palabras
completas.
También he puesto que si se producen errores se guarde en el LOG de Windows, pero solo cuando
se ejecute como administrador, ya que si se ejecuta como usuario normal, se guardan en otra
ubicación; esto no es porque yo quiera, sino por la forma de trabajar de las clases de .NET para
esto de los "logs".
Te explico:
La clase EventLog (definida en System.Diagnostics) guarda la información en el
registro de eventos de Windows. Ese registro de eventos es lo que se conoce como Logs de Windows
y se accede desde las Herramientas administrativas>Event Viewer. Y para utilizar esta
clase hay que tener privilegios de administrador... aunque mirando y remirando en la
documentación no lo indica, al menos de forma clara (vamos, que
yo no lo he visto por ningún lado).
Por otro lado, si usamos la clase definida en el objeto My de Visual Basic,
particularmente
My.Application.Log, ésta lo que hace es guardar lo que le indiquemos en un fichero. Ese
fichero
se guarda en la carpeta indicada por la variable de entorno %APPDATA%, que según estemos
trabajando en un Windows 2000/XP/2003 o en un Windows Vista/2008 se guardará en un sitio o en
otro, ya que esa variable de entorno apuntará a un directorio o a otro según la versión del
S.O., a saber:
%APPDATA% en XP es: C:\Documents and Settings\<usuario>\Application Data
%APPDATA% en Vista es: C:\Users\<usuario>\AppData\Roaming
Y después de ese directorio, se usará el nombre de la empresa, el nombre del producto y la
versión:
Con Windows XP, el directorio sería:
C:\Documents and Settings\<usuario>\Application Data\<empresa>\<ProductName>\<versión>
Con Windows Vista sería:
C:\Users\<usuario>\AppData\Roaming\<empresa>\<ProductName>\<versión>
Nota:
Cuando se guarda con My.Application.Log, el nombre del fichero será <productName>.log,
por
ejemplo, en esta utilidad, el nombre de ese fichero será: gsBuscarTexto.log.
El código que uso para guardar esa información lo he puesto en un método aparte, con idea de
que se compruebe cómo se está ejecutando la aplicación y así sea más cómodo de guardar, en lugar
de andar haciendo esa comparación en cada uno de los sitios en los que se quiera guardar la info
en el LOG de la aplicación.
En realidad, yo guardo esa información cuando se produce un error (que yo tengo controlado) y
cuando se inicia o se cierra el formulario principal, es decir, cada vez que se inicia la
aplicación y se cierra.
Friend Shared Sub EscribirEventLog(ByVal msg As String, ByVal tipo As EventLogEntryType)
' Solo si se tienen permisos de administrador
If EsAdministrador Then
EventLog.WriteEntry(NombreAplicacion, _
msg & _
vbCrLf & "v" & FileVersion & " " & DateTime.Now.ToString, _
tipo)
Else
Dim tipoVB As TraceEventType = TraceEventType.Information
Select Case tipo
Case EventLogEntryType.Error
tipoVB = TraceEventType.Error
Case EventLogEntryType.Information
tipoVB = TraceEventType.Information
Case EventLogEntryType.Warning
tipoVB = TraceEventType.Warning
Case Else
tipoVB = TraceEventType.Information
End Select
My.Application.Log.WriteEntry(msg & _
vbCrLf & "v" & FileVersion & " " & DateTime.Now.ToString, _
tipoVB)
End If
End Sub
En ese código, EsAdministrador es una variable de solo lectura definida a nivel de
clase, que
se asigna en el constructor compartido de la clase, con idea de que no se tenga que estar
ejecutando el código de comprobación cada vez que queramos saber ese dato. La variable (o campo
de la clase) la he declarado compartida (Shared, static par los de C#) y amiga (Friend,
internal
para los de C#), con idea de que se pueda usar desde los otros formularios de la aplicación.
La variable FileVersion es una propiedad de solo lectura (también compartida)
que utiliza la
versión que muestra al ver las propiedades del fichero ejecutable desde el explorador de
Windows, es decir el valor de "file version", que no es la misma versión que la
del ensamblado, ya que es el valor que se usa en el atributo AssemblyFileVersion,
mientras que
la versión del ensamblado es la que se asigna con el atributo AssemblyVersion; de esta
forma,
se guarda la versión de la revisión que se está usando.
Este es el código que yo he usado en esta utilidad para este tema del FileVersion,
fíjate que
uso Static para indicar que las variables mantengan el valor (esto
no se puede hacer en C# y además este Static no tiene nada que ver con el static
de C# que es
como el Shared de VB), de esa forma, el código que asigna el valor a la variable
laVersion solo
se ejecuta la primera vez que se llame a este método, y gracias a que Static mantiene los
valores, en las llamadas posteriores a esta propiedad se seguirá usando ese mismo valor.
Friend Shared ReadOnly Property FileVersion() As String
Get
' Solo asignar la info, la primera vez que se solicite (09/Feb/08)
Static yaEstuve As Boolean
Static laVersion As String
If yaEstuve = False Then
Dim ensamblado As System.Reflection.Assembly = _
System.Reflection.Assembly.GetExecutingAssembly
Dim fvi As System.Diagnostics.FileVersionInfo = _
System.Diagnostics.FileVersionInfo.GetVersionInfo(ensamblado.Location)
' Asignar la cadena de la versión del fichero
laVersion = fvi.FileVersion
' Esto hará que no se vuelva a ejecutar este código
yaEstuve = True
End If
Return laVersion
End Get
End Property
Nota:
La versión usada para la carpeta en la que se guarda el fichero .LOG es la versión del
ensamblado, no la versión del "file version".
En esta nueva revisión también le he añadido el formulario "Acerca de" que suelo usar
en mis
aplicaciones (ver figura 1), en ese formulario muestro lo típico: nombre, versión y descripción
de la aplicación, además de la versión del sistema operativo y el procesador en el que se
ejecuta.
Figura 1. La ventana Acerca De de la utilidad
Para obtener la información del sistema operativo (una cadena con la versión y el service
pack que tenga), utilizo la propiedad VersionString de la propiedad OSVersion de
la clase
Environmet definida en el espacio de nombres System.
Para averiguar la información del procesador, he usado la variable de entorno
%PROCESSOR_IDENTIFIER% y para saber si el sistema operativo es de 32 ó 64 bits, he usado
la
variable de entorno %PROCESSOR_ARCHITECTURE%; ésta variable contiene un valor x86
si es de 32
bits o, por ejemplo, AMD64 si es de 64 bits. En realidad, si el procesador es de 64 bits,
puede
ser AMD64 o IA64, por tanto, lo que hago es comprobar si tiene un "64" en la
cadena devuelta y
si no lo tiene, es que es de 32 (x86).
En el siguiente código tienes cómo obtener los valores de las variables de entorno.
El código que uso para crear esa cadena en la parte de "Sistema operativo" de la figura 1 es:
Dim sbSO As New System.Text.StringBuilder
sbSO.AppendLine("Sistema operativo: " & vbCrLf & _
System.Environment.OSVersion.VersionString)
Try
Dim procBits As String
procBits = System.Environment.GetEnvironmentVariable("PROCESSOR_IDENTIFIER")
sbSO.AppendFormat("Procesador: {0}", procBits)
procBits = System.Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE")
If procBits.Contains("64") Then
sbSO.AppendLine(" (x64)")
Else
sbSO.AppendLine(" (x86)")
End If
Catch ex As Exception
End Try
Permitir reemplazar textos en los ficheros
Como te comenté al principio, la aplicación ya está preparada para la siguiente
funcionalidad: reemplazar textos en los
ficheros (cambiar lo hallado por lo que indiquemos).
Pero esa opción la voy a "complicar" un poco. A saber:
- Primero es que solo se puede activar y usar si se ejecuta como administrador.
- Lo segundo es que solo se podrán realizar cambios en los tipos de ficheros que se indiquen
- Además de que habrá ciertas extensiones (tipos de ficheros en los que no se podrán hacer
cambios, por ejemplo, en los.exe, .com, .dll, etc). Más que nada para evitar que por error se
modifiquen ficheros que pueden ser cruciales para el funcionamiento del sistema operativo o de
cualquier otra aplicación que tengamos instalada.
- Lo siguiente es que se podrá hacer copias de los ficheros en los que se reemplace.
Debido a estas restricciones, el proceso de "cambio" será más lento que el de búsqueda,
aunque espero que no mucho más.
Y para que puedas probar todas estas opciones y cómo usarlas, en la ventana de configuración
se puede
probar algo de esta nueva funcionalidad, entre otras cosas, la forma de agregar extensiones a la
lista (ver figura 2), ya que al arrastrar una serie de ficheros en esa caja de textos, se
añadirán las extensiones de los ficheros soltados (siempre que no estuvieran ya, es decir, no se
repetirán extensiones). También se comprueba que no se añadan extensiones de las no permitidas,
por tanto, si se arrastra un ejecutable (.exe), esa extensión no se añade.
Como puedes ver en la figura 2, el escudito verde que se muestra indica que solo se puede
ejecutar como administrador.
¿Por qué reemplazar/cambiar textos solo cómo administrador?
Por lo que te comenté antes, que es "potencialmente" peligroso hacer cambios en los ficheros,
y
aunque se de la posibilidad de hacer una copia, puede que esa opción la desactives, y después te
des cuenta de que has "metido la pata hasta el gaznate" y ya no haya vuelta atrás, salvo que
tuvieras una copia de seguridad, pero según la ley de Murphy, nunca la tendrás hecha cuando te
pase alguna catástrofe.
Te explico algo simple que puede ocurrir.
Cuando cambias textos, salvo que indiques que se usen palabras completas, puede ser que
busques "Forma" y quieras cambiar solo esa palabra por "Aspecto".
Pues bien, si no te das cuenta, puede que acabes teniendo cosas como "Aspectoto",
"Aspectoción"
y "conAspector", (jooor... como
el chiquitoooorrr...
no puedor, no puedor... jaarrrr) ya que si no usas las opciones de palabras completas (esta
opción quiero añadirla también cuando esté todo esto de buscar/reemplazar) y de
distinguir entre mayúsculas y minúsculas, pues... cambiará todo lo que encuentre de la palabra
"forma", y si tienes "formato", "formación" o "conformar", pues... y
pueden pasar cosas peores.
Así que... si quieres cambiar textos, pues... tendrás que indicarlo expresamente, para que si
ocurre algo "raro", no se lo achaques al autor de la utilidad... ¿vale? Pues eso... el que
avisa...
Pero esto todavía no está implementado totalmente en esta versión, sino que estará en una
siguiente
revisión, pero mientras puedes ir probando, y si te apetece, puedes reportar los bugs o las
mejoras que quieras,
usando el link que hay en la ventana de Acerca de (ver figura 1).
Figura 2. Opciones para reemplazar textos
Pues eso... bájate el ejecutable y lo pruebas, que seguro que te va a gustar más que la
versión anterior.
Y ya sabes, si te sobran unos "céntimos", pues los vas ahorrando hasta que tengas para invitarme
a algo, je, je.
Nos vemos.
Guillermo