¡Esta es una revisión vieja del documento!
Para acceder al registro de Windows no debemos olvidar incluir con un using el espacio de nombres Microsoft.Win32. También necesitaremos un objeto RegistryKey.
Para acceder al registro debemos ver este como si fuese un objeto ya inicializado, éste objeto .NET lo llama Registry. Sus principales ‘métodos’ son las ramas principales del registro: P.ej: LocalMachine, CurrentUser, CurrentConfig…
.OpenSubKey (<Path de donde querámos ir>)..SubKeyCount.ValuecountCloseGetValue (<Y el elemento que queramos pillar>), esto devolverá un objeto ‘object’.RegistryKey Reg = Registry.LocalMachine; Reg = Reg.OpenSubKey ("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"); object Speed = Reg.GetValue("~MHz");
CreateSubKey: Crea (o abre) una subclaveDeleteSubKey: Elimina una subclaveDeleteSubKeyTree: Elimina una clave y todas las subclavesGetSubKeyNames: Devuelve una matriz de strings con todos los nombres de las subclavesGetValueNames: Devuelve una matriz de strings con los valores de la clave.SetValue: Asigna un valor clave.En las listas, en los formularios y en distintos tipos de objetos puede implementarse el Drag and Drop, esto es, arrastrar desde un objeto a otro y lo que ocurre cuando esto ocurre. Implementar este efecto no es muy complejo:
Para que un objeto pueda recibir datos, éste debe de tener la propiedad boleana AllowDrop a true, a partir de entonces, todo objeto que llegue por arrastre será gestionado.
En el método de hacer “mouse down” sobre el objeto codificaríamos lo que vamos a enviar al otro objeto.
Cuando entre un Drag (DragEnter) en el objeto destino debemos codificar mediante los DragDropEffects como actuará dicho objeto.
Una vez se ha levantado el botón del ratón sobre el objeto destino se ha acabado de hacer la acción DragDrop, esta se ha efectuado sobre el objeto destino por lo que será él quien llame al método. Éste método recibe un parámetro DragEventArgs, que aquí es donde vienen todos los datos que se nos han pasado, para recogerlos debemos llamar al método .Data.GetData() mandándole como parámetro un valor de la enumeración DataFormats (un texto, un fichero…).
El siguiente ejemplo corresponde a un formulario con dos listas y un textbox. Se podrán intercambiar datos entre las dos listas y en el textbox se escribirán las direcciones de los ficheros que le han sido pasados al programa.
Antes de empezar el arrastre pongo las propiedades del propio listBox y del formulario a false, para que, si se hace doble clic no se vuelvan a copiar sobre la lista o si se deja en el formulario no haya ningún error raro por culpa del textBox. Hace que en el objeto lista orígen se inicie el DragDrop mediante la función DoDragDrop, a esta se le pasan dos parámetros: lo que se arrastra y como se arrastra (mediante la enumeración DragDropEffects). Para borrarlo de la lista nos hemos asegurado que al pasar lo devuelto por esta función a string no devuelva un None, lo que devuelve es el como ha recibido el objeto destino el DragDrop. Entonces borro el elemento que hemos cogido y vuelvo a dejarlo todo como estaba.
private void listBox1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e) { int idx = listBox1.SelectedIndex; if (idx >= 0) { listBox1.AllowDrop = false; this.AllowDrop = false; if (listBox1.DoDragDrop(listBox1.Items[idx].ToString(), DragDropEffects.Copy).ToString() != "None") listBox1.Items.RemoveAt(idx); listBox1.AllowDrop = true; this.AllowDrop = true; } }
Lo único que hemos hecho es poner el efecto de DragEventArgs a uno que sea viable para el traspaso de datos.
private void listBox2_DragEnter(object sender, System.Windows.Forms.DragEventArgs e) { e.Effect = DragDropEffects.Copy; }
En este evento se reciben dos parámetros, el objeto que lo ha realizado y los datos enviados, si de estos datos cogemos sus datos (según el tipo de datos los cogeremos de una forma u otra) ya podemos añadirlo a la lista.
private void listBox2_DragDrop(object sender, System.Windows.Forms.DragEventArgs e) { listBox2.Items.Add(e.Data.GetData(DataFormats.StringFormat)); } private void listBox1_DragEnter(object sender, System.Windows.Forms.DragEventArgs e) { e.Effect = DragDropEffects.Copy; } private void listBox1_DragDrop(object sender, System.Windows.Forms.DragEventArgs e) { listBox1.Items.Add(e.Data.GetData(DataFormats.StringFormat)); } private void listBox2_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e) { int idx = listBox2.SelectedIndex; if (idx >= 0) { listBox2.AllowDrop = false; this.AllowDrop = false; if (listBox2.DoDragDrop(listBox2.Items[idx].ToString(), DragDropEffects.Copy).ToString() != "None") listBox2.Items.RemoveAt(idx); listBox2.AllowDrop = true; this.AllowDrop = true; } }
Cuando se arrastra un fichero a un formulario (o objeto de formulario) ya no es un “texto” como antes indicábamos con la enumeración del GetData, sino un FileDrop, esto es, un array de strings que tendrá el mismo número de elementos que archivos se hayan arrastrado, cada elemento es una dirección de archivo.
private void Form1_DragEnter(object sender, System.Windows.Forms.DragEventArgs e) { e.Effect = DragDropEffects.Copy; } private void Form1_DragDrop(object sender, System.Windows.Forms.DragEventArgs e) { string[] FileProp; FileProp = (string[])e.Data.GetData(DataFormats.FileDrop); foreach (string str in FileProp) textBox1.Text += str + " "; }
La clase DateTime nos permite la manipulación de fecha y hora de una forma muy sencilla, contiene fechas y horas. Para la manipulación de estas podemos usar métodos como ToShortDateString, ToShortTimeString, ToLongDateString… que te devuelven strings con la fecha u hora, según se haya seleccionado, del objeto.
Date, Day, Hour, DayOfWeek, DayOfYear, Month, Second, Millisecond… Son propiedades que nos devuelven en números enteros el día, la hora…Now nos devolverá el día y la hora actual en el PC. O Today la fecha actual.
Escribir XML desde C# es fácil, .NET tiene un objeto llamado XmlTextWriter, para acceder a él hemos de hacer referencia a System.Xml (tanto dentro de references como con using).
Para hacer uso de él debemos de saber:
XmlTextWriter XMLW = new XmlTextWriter(Console.Out);
Formatting.Indented.WriteComment, que espera un string.WriteStartElement y el nombre del elemento en un string, y para acabarlo llamando a EndElement.WriteElementString, el nombre de la propiedad, y el valor con dos strings.WriteEndDocument y Close.XmlTextWriter XMLW = new XmlTextWriter(Path, null); XMLW.Formatting = Formatting.Indented; XMLW.WriteStartDocument(); XMLW.WriteComment("Vamos a ver qué sale"); XMLW.WriteStartElement("Libro"); XMLW.WriteElementString("Titulo", "1984"); XMLW.WriteElementString("Autor", "G.Orwell"); XMLW.WriteEndElement(); XMLW.WriteEndDocument(); XMLW.Close();
Tenemos este atributo:
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = true)] class HelpAttribute : System.Attribute { protected string Descripcion; public string Uso; public HelpAttribute (string Explicacion) { this.Descripcion = Explicacion; this.Uso = "nulo"; } public string Description { get { return this.Descripcion; } } }
Y lo vamos a asignar al ensamblado, a una clase y a un método. Cómo podemos acceder a él para recoger sus valores? Lo haremos de las formas siguientes:
<variable HelpAttribute> = <variable Attribute> as HelpAttribute;static void MiraAtrPropio() { HelpAttribute HelpAtr; string AsmName; Process p = Process.GetCurrentProcess(); AsmName = p.ProcessName + ".exe"; Assembly a = Assembly.LoadFrom(AsmName); foreach (Attribute atr in a.GetCustomAttributes(true)) { HelpAtr = atr as HelpAttribute; if (HelpAtr != null) Console.WriteLine("\t {0}",HelpAtr.Description); } }
HelpAttribute.GetCustomAttributes) los mostraremos por pantalla su descripción.GetMethods y los meteremos en una variable MethodInfo, los atributos de esta (con GetCustomAttributes).GetFields metiendolos en una variable del tipo FieldInfo.Type type = typeof(Class1); HelpAttribute HelpAtr; foreach (Attribute atr in type.GetCustomAttributes(true)) { HelpAtr = atr as HelpAttribute; if (HelpAtr != null) Console.WriteLine("\t {0}", HelpAtr.Description); } foreach (MethodInfo metodo in type.GetMethods()) { foreach (Attribute atr in metodo.GetCustomAttributes(true)) { HelpAtr = atr as HelpAttribute; if (HelpAtr != null) { Console.WriteLine("\t\t Método: {0}", metodo.ToString()); Console.WriteLine("\t\t\t {0}", HelpAtr.Description); } } }
La manipulación de archivos se basa en la copia, movimiento y borrado del fichero. Para poder hacer esto existe una clase dentro de System.IO llamada FileInfo. Al crear un objeto de este tipo debemos pasarle al constructor el nombre del archivo principal.
Un objeto FileInfo tiene un método llamado CopyTo, este método recibe como parámetros el nombre del segundo archivo y un boleano con un true si se puede copiar o un false sino.
FileInfo fi = new FileInfo("c:\\burro.txt"); fi.CopyTo("c:\\Hulk\\holass.txt",true);
Para borrar un archivo, sólo tenemos que llamar al método .Delete() del objeto FileInfo. Con este también podemos borrar directorios.
FileInfo fi = new FileInfo("c:\\Hulk\\holass.txt"); fi.Delete();
Método MoveTo y el parámetro es el destino.
Recuerda, las propiedades y métodos han de ser pasadas a string para que puedan leerse.
Además podemos saber cuando se crearon mediante el método: .CreationTime().
O el directorio donde está con .Directory o .DirectoryName.
Con la propiedad bool .Exists podemos saber si el fichero existe.
La propiedad int .Length nos dará su tamaño.
FullPath o OriginalPath pueden ser usados para saber el path del archivo.
.Extension nos dará la extensión del archivo.
Y Attributes sus atributos.
Al guardar sólo bytes en el archivo debemos llamar al método Write del FileStream, éste espera un array de bytes que será lo que meta en el fichero y dos parámetros más, en qué posición del array empezará a meter datos y hasta qué posición.
#region Flujo de bytes class ByteStream { private byte [] ArrayBytes; private byte [] ArrayLeido; private FileStream Fichero; public ByteStream (string path) { ArrayBytes = new byte[255]; ArrayLeido = new byte[255]; Fichero = new FileStream(path, FileMode.Create, FileAccess.ReadWrite); } public void Write () { for (int i = 0; i < 255; i++) ArrayBytes[i] = (byte)i; Fichero.Write(ArrayBytes,0,255); } public void Read () { Fichero.Seek(0, SeekOrigin.Begin); Fichero.Read(ArrayLeido,0,255); for (int i=0; i < 255; i++) Console.WriteLine(ArrayLeido[i]); } } #endregion
Al guardar datos en formato binario escribimos directamente el dato como si fuese el parámetro. Y luego al leer del archivo, debemos saber que tamos leyendo, ya que al BinaryReader se llama al método que sea según lo que deba leer.
#region Flujo Binario class BinaryFlux { private FileStream Fichero; public enum Modo {Leer, Escribir}; public BinaryFlux (string path, Modo mode) { if (mode == Modo.Escribir) Fichero = new FileStream(path, FileMode.Create, FileAccess.Write); if (mode == Modo.Leer) Fichero = new FileStream(path, FileMode.Open, FileAccess.Read); } public void Write () { BinaryWriter Writer = new BinaryWriter(Fichero); Writer.Write('a'); Writer.Write(123); Writer.Write(343.43f); Writer.Write("probando"); Writer.Write((byte)5); Writer.Close(); Fichero.Close(); } public void Read () { BinaryReader Reader = new BinaryReader(Fichero); Fichero.Seek(0,SeekOrigin.Begin); Console.WriteLine(Reader.ReadChar()); Console.WriteLine(Reader.ReadInt32()); Console.WriteLine(Reader.ReadSingle()); Console.WriteLine(Reader.ReadString()); Console.WriteLine(Reader.ReadByte()); Reader.Close(); Fichero.Close(); } } # endregion
Estas se encuentran en el directorio donde se ha instalado .NET/FrameworkSDK/Bin o en la carpeta de sistema /Microsoft.NET/Framework/<versión>.
Los ensamblados son el código compilado por .NET, ya sean librerías o ejecutables. Al iniciar una aplicación se cargan los ensamblados de los que esta depende, a estos se les llama ensamblados referenciados.
Para ver todos los ensamblados referenciados que están ahora cargados desde una aplicación de C# deberemos usar System.Reflection y así, poder acceder a la clase Assembly.
Lo primero que haremos será crear un objeto Assembly e igualarlo al objeto que te devuelva el método GetEntryAssembly(), este devolverá el ensamblado de entrada, éste es el ensamblado que se ejecuta en primer lugar, y el punto de entrada de un ensamblado sería la función que se ejecuta primero (generalmente Main).
Un objeto AssemblyName contiene toda la información de un ensamblado. Si cogemos el ensamblado de entrada y llamamos a su método GetReferencedAssemblies() nos devolverá todos los AssemblyName a los que hace referencia:
Assembly EnsambladoDeEntrada; EnsambladoDeEntrada = Assembly.GetEntryAssembly(); foreach (AssemblyName NombrEnsamblado in EnsambladoDeEntrada .GetReferencedAssemblies()) Console.WriteLine("Ensamblado: {0}", NombrEnsamblado.ToString()); Console.ReadLine();
Para saber qué entradas tiene el ensamblado .NET mira los manifiestos de este. Para que nosotros podamos ver este “manifiesto” usaremos la herramienta ILDASM.
Un nombre seguro en un ensamblado indica que este puede almacenarse en la GAC, para saber si un ensamblado lo tiene éste ha de tener un nombre, una versión, una referencia cultural y una clave pública (todos tienen todos estos atributos excepto la clave pública). Para dar un ensamblado una clave pública primero deberemos crearla con la herramienta sn del framework. Haremos ‘sn –k <nombre de clave>.snk’, se generará una clave en un archivo snk y para incluirla dentro de nuestro ensamblado una de sus propiedades será:
[assembly: AssemblyKeyFile (“<nombre de clave>”)]
Una imágen nativa de un ensamblado es cuando el ensamblado se ejecuta de forma óptima para el procesador, para poder hacer que un ensamblado se ejecute en nuestra máquina local de forma nativa deberemos usar el comando ‘ngen <nombre>’.
En C# podemos acceder a la información de un ensamblado muy fácilmente. Empecemos con el ensamblado de entrada, lo recogemos y para saber sus propiedades usaremos los siguientes métodos:
Assembly EnsambladoDeEntrada; EnsambladoDeEntrada = Assembly.GetEntryAssembly(); Console.Write(EnsambladoDeEntrada.Location);
Para cargar ensamblados dinámicamente usaremos las funciones Load y LoadWithPartialName, a la primera le pasaremos todo el nombre de ensamblado con su path, en cambio la segunda lo buscará en el directorio de la aplicación y en la GAC.
Assembly CargaASM; CargaASM = Assembly.LoadWithPartialName("System.Xml"); Console.WriteLine(CargaASM.ToString());
Para trabajar con este ensamblado deberemos mirar que objetos de éste podemos usar, para ello miraremos los objetos con el método GetExportedTypes y luego si al crear una instancia a este objeto (mediante el método CreateInstance(nombre del objeto)) no es nula es que ese objeto puede ser usado:
Assembly CargaASM; Type[] Tipos; object NewObject; CargaASM = Assembly.LoadWithPartialName("System.Xml"); Tipos = CargaASM.GetExportedTypes(); foreach(Type TASM in Tipos) { try { NewObject = CargaASM.CreateInstance(TASM.ToString()); if (NewObject != null) Console.WriteLine("Con {0} se puede trabajar", TASM.ToString()); else Console.WriteLine("Con {0} NO se puede trabajar", TASM.ToString()); } catch {} }
Las variables pueden ser declaradas como int, byte…. O como System.In32, System.Byte… Para mantener la compatitivilidad con otras aplicaciones .net.
sbyte System.SByte byte System.Byte short System.Int16 ushort System.Uint16 int System.Int32 uint System.Uint32 long System.Int64 ulong System.Uint64 char System.Char float System.Single double System.System.Double bool System.Boolean decimal System.Decimal
while (queue.Count > 0) { current = (string)queue.Dequeue(); }
Un ArrayList la encontramos dentro del espacio de nombres System.Collection, es una lista de objetos dinámica. Sus métodos:
Usando System.Reflection tenemos la posivilidad de acceder a objetos sin saber muy bien su función o su tipo. Para ello lo que hacemos es declarar una variable Type e igualarla al “tipo” (type) devuelto por la función estática de esta misma clase .GetType(<nombre de clase>).
Para ver las “cualidades” del tipo devuelto tenemos los siguientes métodos:
Type t = Type.GetType("System.String"); Console.WriteLine(t.Name); Console.WriteLine(t.UnderlyingSystemType);
En vez de usar un nombre de tipo podemos usar una instancia a una clase:
String LoQueSea = "dfjk"; Type t = LoQueSea.GetType(); Console.WriteLine(t.Name);
Para examinar los procesos que se están ejecutando usamos el tipo “process”, para poder hacer uso de esta clase incluiremos System.Diagnostics. Este trozo de código tan intuitivo cierra todos los procesos menos el que provoca el programa que lo contiene.
String EsteProceso; Process[] p = Process.GetProcesses(); Process ThisProc = Process.GetCurrentProcess(); EsteProceso = ThisProc.ProcessName + ".exe"; foreach (Process proc in p) if (proc.ProcessName != EsteProceso) proc.Kill();
Con un código parecido a este vamos a examinar las clases de este archivo, aunque podríamos escoger cualquier otro ensamblado:
String EsteProceso; Process ThisProc = Process.GetCurrentProcess(); EsteProceso = ThisProc.ProcessName + ".exe"; Assembly a = Assembly.LoadFrom(EsteProceso); Type[] tipo = a.GetTypes(); foreach (Type t in tipo){ Console.WriteLine (t.FullName); Console.WriteLine (t.BaseType.FullName); }
Y ahora vamos a examinar las propiedades, los métodos y los constructores de una clase. Escogemos una clase, en el ejemplo ClassX, y cogemos su tipo mandándola como parámetro dentro de la función typeof. Una vez tengamos el tipo podemos mirar sus constructores con la función GetConstructors() que recoge un array de ConstructorInfo, o us propiedades con GetProperties que el array devuelto es de PropertyInfo….
Type tipo = typeof(ClassX); Console.WriteLine (tipo); ConstructorInfo[] Constructores = tipo.GetConstructors(); foreach(ConstructorInfo i in Constructores) Console.WriteLine(i); PropertyInfo[] Propiedades = tipo.GetProperties(); foreach(PropertyInfo i in Propiedades) Console.WriteLine(i); MethodInfo[] Metodos = tipo.GetMethods(); foreach(MethodInfo i in Metodos) Console.WriteLine(i); MemberInfo[] Miembros = tipo.GetMembers(); foreach(MemberInfo i in Miembros) Console.WriteLine("\t"+i);
El código de la clase Main llama a una función que crea un ensamblado (dentro del dominio de la aplicación) en tiempo de ejecución, dinámico, dentro de este una clase con sus métodos. Luego se crea un MethodInfo y se le llama. Para crear código dinámico debemos usar System.Reflection.Emit.
class Class1 { static Type CodigoDinamico; static void Main(string[] args) { GeneraCodigo(); object o = Activator.CreateInstance(CodigoDinamico); MethodInfo Funcion = CodigoDinamico.GetMethod("Prueba"); Funcion.Invoke(o, null); Console.ReadLine(); } static void GeneraCodigo() { AppDomain DominioAplicacion = AppDomain.CurrentDomain; AssemblyName Ensamblado = new AssemblyName(); Ensamblado.Name = "Prueba"; AssemblyBuilder ASMConstructor = DominioAplicacion.DefineDynamicAssembly(Ensamblado, AssemblyBuilderAccess.Run); ModuleBuilder Modulo = ASMConstructor.DefineDynamicModule("ModuloDelEnsamblado"); TypeBuilder ConstrucTipo = Modulo.DefineType("ClaseDinamica", TypeAttributes.Public); MethodBuilder ConstrucMetodos = ConstrucTipo.DefineMethod("Prueba", MethodAttributes.Public, null, null); ILGenerator MSILcode = ConstrucMetodos.GetILGenerator(); MSILcode.EmitWriteLine("Probando... Probando..."); MSILcode.Emit(OpCodes.Ret); CodigoDinamico = ConstrucTipo.CreateType(); } }
Al ejecutarse un programa se crea un proceso principal, si este programa abre “tareas en segundo plano”, estas serán subprocesos. La multitarea preferente se basa en dedicar a cada proceso (o subproceso) del sistema un espacio de tiempo, si en cambio el sistema tiene varios procesadores habá un multiprocesamiento simétrico. Al crearse un subproceso este recibe una prioridad, cuanta más prioridad tiene más atención le dedica el sistema.
Los subprocesos son aconsejables de usar dentro de aplicaciones con procesos largos, que ese subproceso se vaya ejecutando mientras el usuario sigue con el principal. Aplicaciones que hagan varias cosas a la vez, como por ejemplo en la que un proceso escuche por un puerto y otro mande por otro. Hasta el botón cancelar puede ser usado para eliminar un subproceso.
Para definir un subproceso usamos un objeto System.Threading.Thread. Deberemos definir una función para éste, se la pasaremos mediante un ThreadStart, y para iniciarla deberemos llamar al método Start del objeto Thread.
Thread thr1 = new Thread(new ThreadStart(obj.Metodo1)); thr1.Start();
Para ver las propiedades del thread en el que estemos accederemos al Thread.CurrentThread, y las propiedades que podemos ver son: Name (nombre), Priority (prioridad) y ThreadState (estado), los estados son los de la enumeración FlagsAttribute y un Thread puede tener varios estados ya que este puede haber abierto otros subprocesos.
Podríamos ponerle nombre, así cuando debugasemos sería más fácil localizarlo, para ello, antes de llamar a Start podemos hacer (en el ejemplo anterior): thr1.Name = “Thread1”;
También podríamos indicar su prioridad mediante la propiedad Priority con los valores de la enumeración ThreadPriority. P.ej: thr1.Priority = ThreadPriority.Highest;
Hay otros métodos que también podemos usar:
Recuerda que podemos acceder al thread en el que estamos haciendo Thread.CurrentThread.Abort (p.ej). Desde el propio Thread también podemos indicar una pausa haciendo Thread.Sleep(milisegundos).
Puede ocurrir que dos procesos ataquen a una sóla función y esto puede hacer errar a dicha función, para que esto no ocurra se bloquea una parte del código de la función. Cuando un proceso entra a un código bloqueado mira si está ocupado, si no lo está lo ocupa y cuando acabe con él lo desocupa, si estubiese ocupado espera hasta que este sea desocupado.
Para bloquear parte del código usaremos: lock(this) { <código bloqueado> }.
class Prueba { public void Metodo1 () { Metodo3(1); } public void Metodo2 () { Metodo3(2); } public void Metodo3 (int num) { lock(this) { Thread.Sleep(1000); Console.WriteLine(num); } } } class Class1 { static void Main(string[] args) { Prueba obj = new Prueba(); Thread thr1 = new Thread(new ThreadStart(obj.Metodo1)); thr1.Start(); Thread thr2 = new Thread(new ThreadStart(obj.Metodo2)); thr2.Start(); Console.Read(); } }
El acceso en c# a las librerías dll es muy parecido al de VB6, debemos de conocer las funciones de dicha librería, los parámetros que se le pasan y lo que devuelven. Necesitaremos usar la cláusula [DllImport(“<nombre del archivo dll>”)], para poder acceder a esta usaremos System.Runtime.InteropServices. Después del DllImport debemos declarar las funciones que importamos.
using System; using System.Runtime.InteropServices; namespace ConsoleApplication1 { class Class1 { [DllImport("jbn000.dll")] public static extern char GetJBNVersion (); static void Main(string[] args) { System.Console.WriteLine(GetJBNVersion()); Console.ReadLine(); } } }
Esta clase hace referencia al recolector de basura de .NET y aunque no aconsejan usarla mucho tiene métodos que nos permite saltarnos la administración automática de memoria del framework para pasar a gestionarla nosotros.
Métodos:
Collect Obliga a llevar a cabo la recolección de memoria.KeepAlive Impede que un objeto sea recolectado de forma erronea.SupressFinallize Saca un objeto de la cola de objetos a finalizar.
Estaría bien que en un método Dispose se llamase al método GC.SupressFinallize para que elimine de la cola de objetos Finalizados al objeto ya que no es necesario mantenerlo ahí si este ya ha ejecutado el código de liberación de memoria en Dispose.
También existen métodos para controlar la eliminación de objetos por generaciones (getGenration, Collect, MaxGeneration) que administran los objetos por bloques.
Al añadir un archivo a un proyecto este se añade de varias formas (acción de generación):
System.Reflection.Assembly thisExe; thisExe = System.Reflection.Assembly.GetExecutingAssembly(); string [] resources = thisExe.GetManifestResourceNames(); foreach (string resource in resources) MessageBox.Show(resource);
Un txt con el siguente contenido:
cat001=Hola que tal? Como te va? cat002=A mi muy bien, y a ti?
Podemos convertirlo en un archivo .resources o .resx (o viceversa) mediante la aplicación de generación de recursos: resgen.
Siendo el recurso añadido al proyecto: prueba.resources
string assemblyName = Assembly.GetExecutingAssembly().GetName().Name; string baseName = string.Format( "{0}.prueba", assemblyName ); ResourceManager recurso = new ResourceManager(baseName, Assembly.GetExecutingAssembly()); Console.WriteLine(recurso.GetString("cat01"));
Siendo el recurso añadido al proyecto desde el editor: pruRes.resx
baseName = string.Format( "{0}.pruRes", assemblyName ); recurso = new ResourceManager(baseName, Assembly.GetExecutingAssembly()); Console.WriteLine(recurso.GetString("cas01"));
System.Reflection.Assembly thisExe; thisExe = System.Reflection.Assembly.GetExecutingAssembly(); string AssemblyName = thisExe.GetName().Name; System.IO.Stream file = thisExe.GetManifestResourceStream(AssemblyName + ".a.BMP"); this.pictureBox1.Image = Image.FromStream(file);
this.pictureBox1.Image = Image.FromFile("img.BMP");
System.Reflection.Assembly thisExe; thisExe = System.Reflection.Assembly.LoadFile("images.dll"); string [] resources = thisExe.GetManifestResourceNames();
System.IO.Stream fs = Assembly.GetExecutingAssembly().GetManifestResourceStream("YourAssembly.XMLFile1.xml"); DataSet ds = new DataSet(); ds.ReadXml(fs);
Para crear un servicio COM+ el código se ha de compilar como una librería dinámica y las clases han de heredar de ServicedComponent (dentro de System.EnterpriseServices, recuerda hacer referencia a la dll).
También deberemos indicar mediante el atributo .NET ObjectPooling que la clase ha de agruparse en COM+, éste recibe dos números enteros: el tamaño mínimo y el tamaño máximo.
El CLR no actuará, por lo que si queremos crear un destructor ha de ser del modo tradicional ~NombreClase() { … }.
Para que forme parte de la agrupación de objetos COM+ se debe reemplazar el método virtual CanBePooled() y hacer que devuelva true.
Los métodos virtuales Activate y Deactivate también pueden ser reemplazados. Activate se invoca cuando el objeto se elimina de la agrupación y se asigna a un cliente y Deactivate cuando vuelve a la aplicación. El constructor y el destructor de la clase sólo se invocan una vez, cosa muy distinta a como actúan estos métodos.
Los componentes COM+ deben tener un nombre seguro, que tenga clave pública.
Antes de registrar un componente COM+ podemos ponerlo en la GAG, para registrarlo usaremos la herramienta regsvcs del framework, esta requiere un argumento /appname:<…>, este especifica el nombre del COM+, si al ejecutarlo ya existe un componente con este nombre, las clases de éste se agregarán al que ya existían. Entonces el registro de programa.dll quedará así:
regsvcs /appname:ProgramaCom programa.dll
Y el código de un servicio COM puede ser este:
using System.EnterpriseServices; [assembly: AssemblyKeyFile("..\\..\\key.snk")] namespace ClaseCom { [ObjectPooling(5,10)] public class PowerCom : System.EnterpriseServices.ServicedComponent { public PowerCom() {} ~PowerCom() {} public new bool CanBePooled() { return true; } public new void Activate() {} public new void Deactivate() {} } }
Y para registrarlo:
regsvcs /appname:prueba clasecom.dll
Anteriormente se usaba el siguiente comando: REGSVR32
Ahora ya es un componente COM+ registrado.
Otros atributos de System.EnterpriseServices son:
region. Ponemos #region un nombre y el código y luego #endregion.ndoc.nini