Sunday 17 July 2011

WMI fuertemente tipado


Hola a todos,


hacía mucho tiempo que no tenía la ocasión de trabajar con WMI (Windows Management Instrumentation) y como siempre me ha parecido un recurso excepcional, me he decidido a dedicarle un post.


WMI nos proporciona una manera unificada de acceder a la información del sistema, es extensible por nuestras aplicaciones y fácilmente consultable mediante WQL, evitando de esta forma las consultas engorrosas a las APIs de Windows o al registro. WMI es accesible desde .Net a través del espacio de nombres System.Management y desde script, ya que está expuesto por COM.


WMI es muy potente porque, además de consultar información del sistema, también podemos modificarla e incluso realizar un amplio abanico de operaciones que van desde iniciar procesos a habilitar adaptadores de red, pasando por formatear particiones. Pero quizás, lo que le otorga mayor versatilidad, es poder realizar estas operaciones en ordenadores remotos, siempre que tengamos suficientes privilegios, claro está.


También tiene inconvenientes, como todo en esta vida. Algunos de ellos son, por ejemplo, que no nos libramos de incompatibilidades entre las diferentes versiones del sistema operativo, el servicio Winmgmt debe estar ejecutándose en la máquina, las consultas pueden tener un rendimiento muy pobre, a la hora de cruzar información entre tablas el WQL es poco intuitivo y bastante complicado y seguro que muchas otras más que ahora mismo no recuerdo.


Mgmtclassgen


Os recomiendo esta utilidad que nos permite generar clases .Net a partir de clases WMI, de tal manera que podremos acceder a los atributos y operaciones de estos objetos mediante métodos y propiedades fuertemente tipados. Las clases generadas son bastante básicas y será trabajo nuestro modificarlas en el caso de que queramos realizar consultas complejas o bien optimizar el acceso a los datos, pero nos ahorra una gran cantidad de código que nos permite tener una aplicación mucho más legible.


Aquí os dejo una enlace que explica el uso de esta utilidad: http://msdn.microsoft.com/en-us/library/2wkebaxa(v=VS.100).aspx


Por ejemplo si ejecutamos el comando mgmtclassgen win32_process, se nos generará el archivo Process.cs que incluirá la clase Process,


De manera que pasaremos a acceder a la información de la siguiente manera:


   1:  foreach(Process ps in Process.GetInstances())
   2:  {
   3:      Console.WriteLine(ps.Name);
   4:  }



En lugar de lo que teníamos que hacer antes:


   1:  System.Management.ManagementScope mgmtScope = new System.Management.ManagementScope();
   2:  mgmtScope.Path.NamespacePath = "root\\CimV2";
   3:  System.Management.ManagementPath pathObj = new System.Management.ManagementPath();
   4:  pathObj.ClassName = "win32_process";
   5:  pathObj.NamespacePath = "root\\CimV2";
   6:  System.Management.ManagementClass clsObject = new System.Management.ManagementClass(mgmtScope, pathObj, null);
   7:  System.Management.EnumerationOptions enumOptions = new System.Management.EnumerationOptions();
   8:  enumOptions.EnsureLocatable = true;
   9:  foreach (System.Management.ManagementBaseObject obj in clsObject.GetInstances(enumOptions))
  10:  {
  11:      Console.WriteLine(obj["Name"].ToString());
  12:  }



Ganando no solo legibilidad en nuestro código sino también comprobación de tipos en tiempo de compilación y evitamos errores en tiempo de ejecución por ejemplo por haber escrito mal el nombre de un atributo.


Otro aspecto a tener en cuenta es que esta utilidad se basa en el esquema existente en la máquina donde se ejecuta la utilidad, con lo que las clases generadas pueden variar el comportamiento si se ejecutan en otros sistemas operativos.


Early vs Late Bound


Las clases generadas por esta utilidad intentan proporcionarnos un enfoque early-bound en lugar del late-bound que es el que tenemos por defecto utilizando las clases bajo System.Management. ¿Esto quiere decir que tenemos que decidir entre usar una aproximación late-bound o un acceso fuertemente tipado? Nada más lejos de la realidad, la utilísima propiedad AutoCommit que podemos establecer a false en cualquier momento nos permite trabajar con el objeto en memoria antes de enlazarlo con el objeto real. Además, también disponemos de la propiedad LateBoundObject que nos proporciona acceso al objeto WMI subyacente.


Trabajar con early bound es la manera recomendada por Microsoft y la que deberíamos utilizar en la mayoría de las ocasiones por las ventajas que he comentado previamente. Sin embargo, hay ocasiones en las que es necesario utilizar un enfoque late-bound. Por ejemplo, si no conocemos en tiempo de diseño si un método o atributo existirá en tiempo de ejecución. También podemos encontrarnos que hay operaciones que son imposibles de realizar con una aproximación early-bound debido al diseño del componente, como por ejemplo la instalación de un nuevo driver de impresora. A continuación muestro un ejemplo de uso de la propiedad AutoCommit:


   1:  Printerdriver driver = Printerdriver.CreateInstance();
   2:  driver.AutoCommit = false;
   3:  driver.LateBoundObject["Name"] = "Epson AL-2600";
   4:  driver.SupportedPlatform = "Windows x64";
   5:  uint rc = Printerdriver.AddPrinterDriver(driver.LateBoundObject);

Más info en:


http://msdn.microsoft.com/en-us/library/aa394554(v=VS.85).aspx

No comments: