jueves, 21 de febrero de 2013

ISO/IEC 25010:2011 - Characteristics summary

The  international  standard  ISO/IEC 25010 (ISO/IEC 9126) defines two quality models that provides a consistent terminology for specifying, measuring and evaluating system and software product quality:
  • A  quality  in  use  model  composed  of  five  characteristics that relate to the outcome of interaction when a product is used in a particular context of use.
  • A  product  quality  model  composed  of  eight  characteristics that relate to static properties of software and dynamic properties of the computer system.
Quality in use model

Quality in use characteristics and subcharacteristics
  • Effectiveness: accuracy and completeness with which users achieve specified goals.
  • Efficiency: resources expended in relation to the accuracy and completeness with which users achieve goals.
  • Satisfaction: degree to which user needs are satisfied when a system is used in a specified context of use.
    • Usefulness: user is satisfied with their perceived achievement of pragmatic goals.
    • Trust: stakeholders has confidence that a product or system will behave as intended.
    • Pleasure: user obtains pleasure from fulfilling their personal needs.
    • Comfort: user is satisfied with physical comfort.
  • Freedom from risk: degree to which a system mitigates the risk to economic status, human life, health, or the environment.
    • Economic risk mitigation: system mitigates the potential risk to financial status in the intended contexts of use. 
    • Health and safety risk mitigation: system mitigates the potential risk to people in the intended contexts of use.
    • Environmental risk mitigation: system mitigates the potential risk to property or the environment in the intended contexts of use.
  • Context coverage: degree to which a system can be used with effectiveness, efficiency, freedom from risk and satisfaction in specified contexts of use and in contexts beyond those initially explicitly identified.
    • Context completeness: system can be used in all the specified contexts of use.
    • Flexibility: system can be used in contexts beyond those initially specified in the requirements

Product quality model

Product quality characteristics and subcharacteristics

  • Functional suitability: degree to which a system provides functions that meet stated needs when used under specified conditions.
    • Functional completeness: degree to which the set of functions covers all the specified tasks and user objectives.
    • Functional correctness: system provides the correct results with the needed degree of precision.
    • Functional appropriateness: the functions facilitate the accomplishment of specified tasks and objectives.
  • Performance efficiency: performance relative to the amount of resources used under stated conditions.
    • Time behaviour: response, processing times and throughput rates of a system, when performing its functions, meet requirements.
    • Resource utilization: the amounts and types of resources used by a system, when performing its functions, meet requirements.
    • Capacity: the maximum limits of a product or system parameter meet requirements.
  • Compatibility: degree to which a system can exchange information with systems, and/or perform its required functions, while sharing the same hardware or software environment.
    • Co-existence: product can perform its functions efficiently while sharing environment and resources with other products.
    • Interoperability: a system can exchange information with other systems and use the information that has been exchanged.
  • Usability: degree to which a system can be used with effectiveness, efficiency and satisfaction in a specified context of use.
    • Appropriateness recognizability: users can recognize whether a system is appropriate for their needs, even before it is implemented.
    • Learnability: system can be used to achieve specified goals of learning to use the system.
    • Operability: system has attributes that make it easy to operate and control.
    • User error protection: system protects users against making errors.
    • User interface aesthetics: user interface enables pleasing and satisfying interaction for the user.
    • Accessibility: system can be used by people with the widest range of characteristics and capabilities.
  • Reliability: degree to which a system performs specified functions under specified conditions for a specified period of time.
    • Maturity: system meets needs for reliability under normal operation.
    • Availability: system is operational and accessible when required for use.
    • Fault tolerance: system operates as intended despite the presence of hardware or software faults.
    • Recoverability: system can recover data affected and re-establish the desired state of the system is case of an interruption or a failure.
  • Security: degree to which a system protects information and data so that persons or other products or systems have the degree of data access appropriate to their types and levels of authorization.
    • Confidentiality: system ensures that data are accessible only to those authorized to have access.
    • Integrity: system prevents unauthorized access to, or modification of, computer programs or data.
    • Non-repudiation: actions or events can be proven to have taken place, so that the events or actions cannot be repudiated later.
    • Accountability: actions of an entity can be traced uniquely to the entity.
    • Authenticity: the identity of a subject or resource can be proved to be the one claimed.
  • Maintainability: degree of effectiveness and efficiency with which a system can be modified by the intended maintainers.
    • Modularity: system is composed of components such that a change to one component has minimal impact on other components.
    • Reusability: an asset can be used in more than one system, or in building other assets.
    • Analysability: effectiveness and efficiency with which it is possible to assess the impact of an intended change.
    • Modifiability: system can be effectively and efficiently modified without introducing defects or degrading existing product quality.
    • Testability: effectiveness and efficiency with which test criteria can be established for a system.
  • Portability: degree of effectiveness and efficiency with which a system can be transferred from one hardware, software or other operational or usage environment to another.
    • Adaptability: system can effectively and efficiently be adapted for different or evolving hardware, software or usage environments.
    • Installability: effectiveness and efficiency with which a system can be successfully installed and/or uninstalled.
    • Replaceability: product can be replaced by another specified software product for the same purpose in the same environment.

lunes, 6 de agosto de 2012

Localización (traducción) con Entity Framework

Aquí comparto una forma para localizar (o traducir) entidades de una base de datos SQL mediante Entity Framework.


Me he topado con el problema de la traducción a diferentes idiomas de los datos de base de datos SQL para aplicaciones que utilizan .NET Entity Framework.

Aquí, se propone una solución simple que consiste en unos pocos cambios a una base de datos existente (nuevas tablas de traducción, sin modificación de las tablas existentes), y un método para traducir automáticamente entidades de datos mapeadas con Entity Framework.




jueves, 24 de marzo de 2011

Juego de la vida en C#

Aquí comparto un simulador de juego de la vida hecho en C# 4.0 (WinForms).

Características:

- Variables como Algoritmo, Edad máxima, Ocupación y Tamaño del universo son configurables.
(Presionar F1 para ver la ayuda de las teclas rápidas para modificar estas variables).

- Uso de PLinq para aprovechar al máximo la capacidad de procesadores multinúcleo.

- Uso de Bloqueo de bits (LockBits) para agilizar el rendimiento de la manipulación de la imagen del universo.

Capturas de algunos de los patrones que se pueden lograr:






Presionar F1 para mostrar la ayuda en pantalla.

Algunos algoritmos interesantes que puedes probar (presionando la tecla A) son:

AlgoritmoDescripcion
5678/35678(caótico) diamantes, catástrofes
/3(estable) casi todo es una chispa
1358/357(caótico) un reino equilibrado de amebas
23/3(caótico) "Juego de la Vida de Conway"
23/36(caótico) "HighLife" (tiene replicante)
235678/3678(estable) mancha de tinta que se seca rápidamente
34/34(crece) "Vida 34"


Descarga el código fuente desde Aquí
Si sólo quieres el ejecutable: Aquí

Notas: Necesitarás el .NET Framework 4.0 para poder correr el simulador.

Aquí: http://gols.codeplex.com la última versión en inglés



viernes, 18 de marzo de 2011

Herramientas de comparación y merge en TFS

Los que usamos TFS (Team Foundation Server) para el control de código fuente, sabemos que la herramienta de merge por defecto (Diffmerge) es bastante pobre.

Por suerte Visual Studio 2010 permite configurar el software para comparaciones y merge de código que hagamos dentro de TFS.

Aquí les ofrezco una breve comparación entre Diffmerge y otras dos populares herramientas (WinMerge y KDiff), además de los pasos necesarios para configurarlas dentro de Visual Studio.


Diffmerge (TFS)

• Es la herramienta por defecto del TFS para comparaciones y merges.
• No hay posibilidad de cambiar el tamaño de la fuente.
• La visibilidad del cambio es por línea, no se indica la parte de la línea que cambió.
• Interfaz poco intuitiva y no configurable.


KDiff3 (sourceforge)

• Posibilidad de cambiar el tamaño de la fuente para mayor visibilidad.
• Los cambios se resaltan con códigos de colores en la parte de la línea que sufrió cambios.
• La parte inferior muestra claramente los conflictos que deben ser resueltos manualmente.
• Interfaz configurable.
• Es open source (GNU GENERAL PUBLIC LICENSE)


• Posibilidad de cambiar el tamaño de la fuente para mayor visibilidad.
• Los cambios se resaltan con colores en la parte de la línea que sufrió cambios.
• La parte inferior muestra claramente la diferencia en el conflicto seleccionado.
• Permite visualizar rápidamente todos los cambios del archivo.
• Es open source (GNU GENERAL PUBLIC LICENSE)
• Interfaz configurable.

Estas dos últimas herramientas (WinMerge y KDiff) son bastante similares y oferecen prácticamente la misma funcionalidad, pero sin duda son las mejores herramientas de merge para Windows.
Cuestión de gusto o costumbre cuál prefiera cada uno.

Para configurar el KDiff (o cualquier otra herramienta de merge) dentro del Visual Studio, se procede de la siguiente manera:

1. Dentro de VS2010, menú Tools, Options. Navegar hasta la opción Source Control, Visual Studio TFS. Click en el botón Configure User Tools.

2. En Configure User Tools, agregar un nuevo comando con el botón Add, para asociar el comando de
Compare.

3. Ingresar los siguientes valores del comando de compare y darle OK:
Extension: *
Operation: Compare
Command: Ruta del ejecutable kdiff3
Arguments: %1 --fname %6 %2 --fname %7

4. Agregar otra nueva operación con el botón Add, esta vez para asociar el comando Merge, e ingresar los siguientes valores.
Extension: *
Operation: Merge
Command: Ruta del ejecutable kdiff3
Arguments: %3 --fname %8 %2 --fname %7 %1 --fname %6 -o %4


Listo, con esta configuración las comparaciones y merges que el TFS necesite hacer, se harán a través de la herramienta KDiff3.


Para configurar el WinMerge se procede de la misma forma, lo único que cambia es el comando y los argumentos de los últimos dos pasos, quedando así:

Extension: *
Operation: Compare
Command: winmerge.exe
Arguments: /ub /dl %6 /dr %7 %1 %2
Extension: *
Operation: Merge
Command: winmerge.exe
Arguments: /ub /dl %6 /dr %7 %1 %2 %4

Aquí transcribo una lista de herramientas con los argumentos que deben utilizarse para integrarlas con Visual Studio:
Compare
HerramientaCommandArguments
TFS defaultdiffmerge.exe%1 %2 %6 %7 %5 /ignorespace
WinDiffwindiff.exe%1 %2
DiffDoc (for Word files)DiffDoc.exe/M%1 /S%2
WinMergewinmerge.exe/ub /dl %6 /dr %7 %1 %2
Beyond Comparebc2.exe%1 %2 /title1=%6 /title2=%7
KDiff3kdiff3.exe%1 --fname %6 %2 --fname %7
Araxiscompare.exe/wait /2 /title1:%6 /title2:%7 %1 %2
Compare It!Wincmp3.exe%1 /=%6 %2 /=%7
SourceGear DiffMergeDiffMerge.exe/title1=%6 /title2=%7 %1 %2
Beyond Compare 3BComp.exe%1 %2 /title1=%6 /title2=%7
TortoiseMergeTortoiseMerge.exe/base:%1 /mine:%2 /basename:%6 /minename:%7
Visual SlickEditwin\vsdiff.exe%1 %2

Merge
HerramientaCommandArguments
TFS defaultdiffmerge.exe/merge %1 %2 %3 %4 %6 %7
KDiff3kdiff3.exe%3 --fname %8 %2 --fname %7 %1 --fname %6 -o %4
Visual SourceSafessexp.exe/merge %1 %2 %3 %4 %6 %7
Araxiscompare.exe/wait /swap /a3 /3 /title1:%6 /title2:%7 /title3:%8 %1 %2 %3 %4
Beyond Compare (2-way merge)bc2.exe%1 %2 /savetarget=%4 /title1=%6 /title2=%7
WinMerge (2-way merge)winmerge.exe/ub /dl %6 /dr %7 %1 %2 %4
Guiffyguiffy.exe-s -h1%6 -h2%7 -hm%9 %1 %2 %3 %4
Ellie Computingguimerge.exe--mode=merge3 %3 %1 %2 --to=%4 --title0=%8 --title1=%6 --title2=%7 --to-title=%9
SourceGear DiffMergeDiffMerge.exe/title1=%6 /title2=%8 /title3=%7 /result=%4 %1 %3 %2
Beyond Compare 3BComp.exe%1 %2 %3 %4 /title1=%6 /title2=%7 /title3=%8 /title4=%9
TortoiseMergeTortoiseMerge.exe/base:%3 /mine:%2 /theirs:%1 /basename:%8 /minename:%7 /theirsname:%6 /merged:%4 /mergedname:%9
Visual SlickEditwin\vsmerge.exe%3 %1 %2 %4



martes, 1 de febrero de 2011

Visual Studio Addin para operaciones con TFS

Microsoft TFS (Team Foundation Server) es un producto de Microsoft para el control de código fuente, elementos de trabajo y administración de proyectos.
A pesar de que es una herramienta bastante completa y que está totalmente integrada al IDE de Visual Studio, en mi opinión, esta integración carece de accesos rápidos a operaciones básicas que a veces hacen perder un poco el tiempo.

Por ejemplo, si queremos ubicar a un archivo dentro del control de código fuente, debemos navegar "manualmente" el árbol de archivos del servidor en la ventana Source Control Explorer.


Sería muy práctico poder acceder a un archivo del servidor directamente desde el Solution Explorer.
Ésta es una de las dos cosas que permite este Addin. Agrega menúes contextuales para poder acceder rápidamente a un archivo dentro del Source Control Explorer así como a la historia del mismo.





Actualmente existe un Addin mucho más completo (TFSPlus) que permite estas dos cosas (y algunas más), pero hasta el momento no existe una versión que funcione en Visual Studio 2010.

Para crear un Addin en Visual Studio 2010, podemos crear un nuevo proyecto de tipo Visual Studio Addin y se generará automáticamente la clase Connect, necesaria para la implementación de cualquier Addin.
Aquí hay un tutorial al respecto que está muy bien explicado, así que me limitaré sólo al código para manejar los objetos de TFS.
Para poder acceder a los objetos de TFS, necesitamos algunas referencias a librerías que están en los namespaces Microsoft.VisualStudio.TeamFoundation, y Microsoft.TeamFoundation. Normalmente se instalan en la GAC al instalar Visual Studio 2010. Pero también se pueden encontrar en C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0.

Aquí hay un ejemplo (un poco viejo pero vigente) de cómo crear un addin para comunicarse con TFS en VS2005.
La clase principal para acceder a la funcionalidad de Version Control de TFS se llama VersionControlExt. Para obtener una referencia a esta clase, podemos utilizar el objeto application que se recibe en el método OnConnect de la clase Connect de nuestro addin:

public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
{
 DTE2 applicationObject = (DTE2)application;
 VersionControlExt vc = applicationObject.GetObject("Microsoft.VisualStudio.TeamFoundation.VersionControl.VersionControlExt") as VersionControlExt;
...

Para ubicar y mostrar un archivo en el Source Control Explorer de TFS, se puede proceder de la siguiente forma:

string localPath = applicationObject.SelectedItems.Item(1).ProjectItem.FileNames[0];
string serverPath = vc.Explorer.Workspace.GetServerItemForLocalItem(localPath);
vc.Explorer.Navigate(serverPath);
applicationObject.ExecuteCommand("View.TfsSourceControlExplorer");
En la primera línea se obtiene la ruta local del primer archivo seleccionado en el Solution Explorer.

Luego se llama al método GetServerItemForLocalItem que obtene la ruta del archivo en el servidor a partir de su ruta local.
La tercera línea provoca que se seleccione el archivo en el Source Control Explorer de TFS.
La cuarta línea es sólo para asegurar que la ventana del explorador esté abierta y enfocada.

Adicionalmente se muestra el código necesario para mostrar la historia de un archivo (aunque esta opción ya existe en VS2010 en el menú contextual view history):

VersionControlHistoryExt history = vc.History;
string localPath = applicationObject.SelectedItems.Item(1).ProjectItem.FileNames[0];
history.Show(localPath, VersionSpec.Latest, 0, RecursionType.Full);

En la primera línea, se obtiene una referencia a la clase VersionControlHistoryExt que nos permite manipular el History de los archivos en el repositorio.
La tercerá línea provoca que se muestre la historia del archivo seleccionado.


La versión completa del Addin se puede descargar desde Aquí.

 

domingo, 9 de enero de 2011

Clipboard To Speech. Sintetizar el texto del portapapeles en C#

Clipboard 2 Speech es una pequeña aplicación en C# que observa el contenido del clipboard (o portapapeles) y cuando detecta cualquier texto en él, lo "sintetiza vocalmente" (Text-To-Speech).

Utiliza la clase SpeechSynthesizer del namespace System.Speech.Synthesis de .NET.
No es mucha la documentación que se puede encontrar de esta clase en MSDN, pero su uso es extremadamente sencillo; con sólo dos líneas de código, el sintetizador estará hablando:

SpeechSynthesizer ss = new SpeechSynthesizer();
ss.Speak("Hello, this is a test");
Para el monitoreo del contenido del clipboard, se creó la clase ClipboardWatcher (basada en un ejemplo de Tom Archer) que utiliza la función SetClipboardViewer de la API de windows, con el fin de suscribirnos al sistema operativo para que nos envíe un mensaje cada vez que el contenido de clipboard se modifique.

Esta es la forma correcta de enlazarnos a la cadena del clipboard:
private IntPtr nextClipboardViewer;
const int WM_DRAWCLIPBOARD = 0x308;
const int WM_CHANGECBCHAIN = 0x030D;
[DllImport("User32.dll")]
protected static extern int SetClipboardViewer(int hWndNewViewer);
[DllImport("User32.dll")]
public static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);
public ClipboardWatcher() // Constructor
{
    nextClipboardViewer = (IntPtr)SetClipboardViewer((int)this.Handle);
}
protected override void WndProc(ref Message m)
{
    switch (m.Msg)
    {
        case WM_DRAWCLIPBOARD:
            OnClipboardData();
            SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
            break;
        case WM_CHANGECBCHAIN:
            if (m.WParam == nextClipboardViewer)
                nextClipboardViewer = m.LParam;
            else
                SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
            break;
        default:
            base.WndProc(ref m);
            break;
    }
}
protected override void Dispose(bool disposing)
{
    ChangeClipboardChain(this.Handle, nextClipboardViewer);
}
Este código debe estar dentro de un control de windows forms que implemente la función WndProc, (por ejemplo un Form o un UserControl).

Hasta aquí sólo obtenemos un aviso cada vez que el contenido del clipboard se modifica, por eso en el método OnClipboardData debemos obtener el nuevo contenido mediante una llamada al método estático GetDataObject de la clase Clipboard (de System.Windows.Form), y a partir de esto se dispara un evento con algunos datos del contenido del clipboard:

private void OnClipboardData()
{
    ClipboardDataArgs args = new ClipboardDataArgs();
    try
    {
        args.Data = Clipboard.GetDataObject();
        if (args.Data.GetDataPresent(DataFormats.Text))
        {
            args.Text = (string)args.Data.GetData(DataFormats.Text);
        }
        else if (args.Data.GetDataPresent(DataFormats.Bitmap))
        {
            args.Image = (Bitmap)args.Data.GetData(DataFormats.Bitmap);
        }
        OnRaiseClipboardData(args);
    }
    catch (Exception e)
    {
        MessageBox.Show(e.ToString());
    }
}
public class ClipboardDataArgs : EventArgs
{
    public string Text { get; set; }
    public Bitmap Image { get; set; }
    public IDataObject Data { get; set; }
}

Simple...

Puedes descargar el código completo desde aquí.

Nota:
La aplicación acepta ciertos "comandos" desde el clipboard. Por ejemplo, puedes copiar la cadena "/pause" o "/stop" para que el sintetizador se detenga, o la cadena "/start" para que reanude la síntesis.

viernes, 24 de diciembre de 2010

Monitorear las ventanas que se abren y cierran en windows mediante un system hook

Aquí se presenta una forma de monitorear las ventanas de Windows a medida que se crean y destruyen, en C#.

Si no te interesa seguir leyendo, aquí puedes bajar el código completo de la aplicación.

Introducción

Dentro de Windows, toda interacción entre ventanas y con el usuario (clicks, movimiento de cursor, etc) se hace a través de mensajes.

Las aplicaciones tienen la capacidad de escuchar y procesar cada uno de los mensajes, por ejemplo, para minimizarse, maximizarse o cerrarse cuando el usuario hace click en el botón correspondiente de la parte superior derecha de la ventana.

En general, una aplicación Windows Forms en .NET, no tiene la necesidad de procesar explícitamente los mensajes, ya que la mayoría de las interacciones se produce automáticamente o por medio de eventos comunes de cada control (Click, Load, etc).

Pero para procesar los mensajes explícitamente, se utiliza una técnica denominada hooking que consiste en hacer que nuestra aplicación implemente un método y lo informe al sistema operativo. Este método será en realidad una función de callback (callback function) y funcionará como un "gancho" (hook) para interceptar los mensajes y poder procesarlos.

Así, cuando Windows procese un evento "enganchable", como el movimiento del cursor o la creación de una ventana, llamará inmediatamente a la función de callback que nuestra aplicación defina.
En el caso de Windows Forms, el método (la función de callback) que intercepta los mensajes, se denomina WndProc y tiene la siguiente firma:
void WndProc(ref System.Windows.Forms.Message m)

Ejemplo

Se presenta una aplicación simple que mostrará en tiempo real una lista con las ventanas, a medida que se van creando o destruyendo.
Para esto, se implementará un hook a nivel shell, para que cada vez que se cree o destruya una ventana, el sistema operativo pase el control a una subrutina de nuestra aplicación y así poder informar al usuario del evento.

A continuación se muestra el código necesario para registrar nuestra aplicación como gancho (o hook) de los mensajes del shell de windows en un Window Form en C#.
uMsgNotify = Win32API.RegisterWindowMessage("SHELLHOOK");
Win32API.RegisterShellHookWindow(this.Handle);  

La llamada a RegisterWindowMessage se hace para obtener un identificador único de los mensajes. Este identificador lo necesitaremos dentro de la función de callback para identificar a los mensajes que nos interesa escuchar.
La llamada a RegisterShellHookWindow se hace para registrar nuestro WinForm como gancho de los eventos del shell de windows.

Una vez hecho esto, procedemos a sobreescribir la función de callback en nuestro WinForm, para interceptar los mensajes de WindowCreated y WindowDestroyed, como se muestra a continuación:
protected override void WndProc(ref System.Windows.Forms.Message m)
{
    IntPtr hWnd; 
    if (m.Msg == uMsgNotify)
    {
        switch (m.WParam.ToInt32())
        {
            case (int)Win32API.ShellEvents.HSHELL_WINDOWCREATED:
                hWnd = m.LParam;
                // La ventana cuyo handler es hWnd, fue creada
                ...
                break;
            case (int)Win32API.ShellEvents.HSHELL_WINDOWDESTROYED:
                hWnd = m.LParam;
                // La ventana cuyo handler es hWnd, fue cerrada
                ...
                break;
        }
    }
    base.WndProc(ref m);
}

Lo único que resta por hacer, es obtener el nombre de la ventana que fue creada/destruida, así como el nombre del proceso (ejecutable) al que pertenece, todo a partir del identificador de la ventana (hWnd).

Para obtener el nombre de la ventana a partir de su identificador, utilizamos la función GetWindowTextLength y GetWindowText como se muestra a continuación:
private string GetWindowName(IntPtr hwnd)
{
    StringBuilder sb = new StringBuilder();
    int longi = Win32API.GetWindowTextLength(hwnd) + 1;
    sb.Capacity = longi;
    Win32API.GetWindowText(hwnd, sb, sb.Capacity);
    return sb.ToString();
}

Obtener el nombre del ejecutable al que pertenece la ventana es un poco más tedioso, ya que se necesitan 4 llamadas a la API:

private string ExePathFromHwnd(IntPtr hWnd)
{
    StringBuilder sb = new StringBuilder(Win32API.MAX_PATH);
    int pid = 0;
    Win32API.GetWindowThreadProcessId(hWnd, ref pid);
    IntPtr hProc = Win32API.OpenProcess(Win32API.ProcessAccess.AllAccess, false, pid);
    if (hProc != IntPtr.Zero)
    {
        uint lRet = Win32API.GetModuleFileNameEx(hProc, IntPtr.Zero, sb, Win32API.MAX_PATH);
        Win32API.CloseHandle(hProc);
    }
    return sb.ToString();
}

Juntando todo esto en una aplicación, podemos generar algo así:


Aquí puedes bajar el código completo de la aplicación.

Feliz navidad !

lunes, 29 de noviembre de 2010

Orden lexicográfico de combinaciones matemáticas en C#.

Aquí se presenta un algoritmo en C# para obtener el índice lexicográfico de una combinación de elementos y vice-versa (una combinación a partir de su índice lexicográfico).

"Los coeficientes binomiales o combinaciones indican el número de formas en que se pueden extraer subconjuntos a partir de un conjunto dado." (wikipedia)

Ejemplo:
Se tiene un conjunto con 6 objetos diferentes {1,2,3,4,5,6}, de los cuales se desea escoger 2 (sin importar el orden de elección). Existen 15 formas de efectuar tal elección.
C(n,k) = n! / k! (n - k)!   =>   C(6,2) = 15


A continuación se listan estas 15 formas, en orden lexicográfico:
(1,2) (1,3) (1,4) (1,5) (1,6)
(2,3) (2,4) (2,5) (2,6)
(3,4) (3,5) (3,6)
(4,5) (4,6)
(5,6)

Así, por ejemplo, la séptima combinación en orden lexicográfico es la (2,4).

Podría decirse que el orden lexicográfico está dado por la tasa de cambio entre los elementos. Por ejemplo el elemento (1,3) difiere en sólo una unidad con respecto a (1,2), y es lexicográficamente el número 2. Así, el número de cambios y la posición del elemento cambiado definen de alguna manera el orden lexicográfico.

Sea n la cantidad de objetos de los que se puede elegir y k la cantidad de objetos que se eligen, el algoritmo que se presenta a continuación, generará un arreglo de elementos (una combinación) a partir del valor del índice lexicográfico i.

O sea, el método retornará el vector (2,4), con las entradas n=6, k=2, i=7.

public static int[] GetOrderedSetByIndex(int n, int k, int i)
{
    if (k == 1) return new int[] { i };
    int[] arr = new int[k];
    int r, m = 0;
    for (int j = 0; j < k - 1; j++)
    {
        arr[j] = (j != 0) ? arr[j - 1] : 0;
        do
        {
            arr[j]++;
            r = choose(n - arr[j], k - (j + 1));
            m = m + r;
        } while (m < i);
        m = m - r;
    }
    arr[k - 1] = arr[k - 2] + i - m;
    return arr;
}
NOTA: El método choose no se lista pero se puede descargar el código completo desde aquí.

Para el ejemplo anterior, la llamada al método que obtiene la combinación (2,4) sería: GetOrderedSetByIndex(6, 2, 7)



De igual forma, se presenta el método inverso, para obtener el índice lexicográfico a partir de una combinación dada:

public static int GetIndexByOrderedSet(int n, int k, int[] comb)
{
    int[] C = new int[k];
    long LI = 0, R;
    for (int i = 1; i <= k - 1; i++)
    {
        C[i - 1] = 0;
        if (i != 1)
            C[i - 1] = C[i - 2];
        do
        {
            C[i - 1] = C[i - 1] + 1;
            R = combine(n - C[i - 1], k - i);
            LI = LI + R;
        } while ((C[i - 1] < comb[i - 1]));
        LI = LI - R;
    }
    return (int)LI + comb[k - 1] - comb[k - 2];
}
 
NOTA: El método combine no se lista pero sólamente calcula el coeficiente binomial. El código completo se puede descargar desde aquí.

Para el ejemplo anterior, la llamada al método que obtiene el índice lexicográfico sería: GetIndexByOrderedSet(6, 2, new int[] { 2, 4 }); y retornaría 7.



Estos métodos son útiles también para listar lexicográficamente todas las combinaciones dados un valor de n y k, como se muestra a continuación:

for (int i = 1; i <= combine(6, 2); i++)
{
    int[] comb = GetOrderedSetByIndex(6, 2, i);
    Console.WriteLine("({0},{1})", comb[0], comb[1]);
}


El código completo se puede bajar desde aquí.
Espero que alguien le sea útil.

Federico D. Colombo NOTA:
Los algoritmos presentados aquí están basados en el Algoritmo 515 de Buckles.


Vínculos:

http://msdn.microsoft.com/en-us/library/aa289166.aspx
http://saliu.com/lexicographic.html
http://www.calculatorsoup.com/calculators/discretemathematics/combinations.php

domingo, 19 de septiembre de 2010

Visor de Procesos y Ventanas de Windows en vb6

Aquí comparto una aplicación en vb6 que hice hace unos años pero que aún se sigue ganando un acceso directo en mi escritorio:

"Procesos y Ventanas" no es más que otro (más) visor de procesos y ventanas de windows.
Funciona en casi cualquier versión del Windows. (Al menos en todas las que lo probé: XP, Vista, 2003, 2008, 7).

Así se ve:


Tiene algunas funcionalidades que lo hacen útil como la posibilidad de arrastrar el puntero del mouse hasta cualquier ventana para poder seleccionarla en el grid.
El botón TopMost permite colocar la ventana siempre en primer plano (útil cuando se necesita copiar y pegar desde múltiples fuentes, etc).
El botón Mostrar permite mostrar una ventana que por defecto permanezca oculta.
El botón MATAR permite terminar un proceso cualquiera.
Permite enviar mensajes típicos (maximize, minimize, hide, show) a cualquier ventana.
Otra opción interesante es la posibilidad de cambiar el padre (contenedor) de una ventana para lograr algo como esto (la ventana de Google Earth contenida dentro de la ventana del Explorer) :


A mi siempre me fue útil esta herramienta y espero que alguien por ahi también.

Puedes bajar el código en vb6 desde Aquí.

necesitarás msvbvm60.dll y msflxgrid.dll (Microsoft FlexGrid Control 6.0 (SP3))

Suerte.

viernes, 3 de septiembre de 2010

Presentación de curso "Cubos OLAP"

Aquí adjunto el material del mini-curso "Cubos OLAP".

El paquete incluye la presentación en PDF, los scripts de datos del ejemplo, un examen con sus respectivas respuestas y un documento extra con información para migrar un cubo de Microsoft AS2000 a AS2005.

Contenido de la presentación:
  • Definición
  • Ejemplos
  • Jerarquías
  • Ventajas y desventajas
  • Diseño (star y snowflake)
  • Arquitectura ROLAP, MOLAP y HOLAP

Screenshot:



Descárgalo aquí.


Espero que a alguien le sea de utilidad.

Presentación de curso "Novedades en Transact-SQL 2005"

Aquí adjunto el material del mini-curso "Novedades en T-SQL 2005".

El paquete incluye la presentación de Powerpoint, y el código con los scripts demos.

Contenido de la presentación:
  • Manejo de errores. TRY/CATCH.
  • Instrucciones INTERSECT y EXCEPT.
  • Instrucción TOP basada en expresión.
  • Instrucción OUTPUT y OUTPUT INTO.
  • ON DELETE y ON UPDATE en llaves foráneas.
  • CTE (Common table expressions) reutilización de querys, recursividad.
  • Muestreo de tablas. Instrucción TABLESAMPLE.
  • Pivoteo de tablas. PIVOT y UNPIVOT.
  • Funciones de Ranking y Partitioning.
  • Integración con CLR (.NET)
  
Este curso está orientado a las nuevas características que ofrece el lenguaje de script Transact-SQL de Microsoft a partir de la versión SQL 2005.


Screenshots:


Descárgalo aquí.


Espero que a alguien le sea de utilidad.

jueves, 2 de septiembre de 2010

Presentación de curso "Introducción a LINQ"

Aquí adjunto el material del mini-curso "Introducción a LINQ" (Language INtegrated Queries).

El paquete incluye la presentación de Powerpoint, y bastante código con ejemplos y cosas interesantes en VB.

Contenido de la presentación:
  • Proyecciones (select)
  • Filtros
  • Ordenamiento
  • Joins
  • Agrupamiento
  • Operadores de elemento (first, last, single)
  • Métodos de agregación (sum, min, max)
  • Cuantificadores (any, all, contains)
  • LINQ to SQL
  • DataContext
  • Transacciones

Este curso está orientado al uso de LINQ en Visual Basic.


Screenshots:




Descárgalo aquí.


Espero que a alguien le sea de utilidad.

Presentación de curso "Novedades en .NET Framework 3.5 (VB9)"

Aquí adjunto el material del mini-curso "Novedades en .NET Framework 3.5".

El paquete incluye la presentación de Powerpoint, el examen con sus respectivas respuestas, el código con los ejemplos en VB, un póster en formato .PDF con los tipos más importantes del .NET framework 3.5 y una nota de El Guille (Guillermo Som) acerca de los Generics en VB9.

Contenido de la presentación:
  • Inferencia de tipos
  • Tipos anónimos (new with)
  • Inicialización de objetos
  • Iteradores
  • Colecciones genéricas
  • Tipos genéricos
  • Clases parciales
  • Expresiones lambda
  • Métodos extensores
  • Sobrecarga de operadores
  • Tipos por valor anulables
  • Operador ternario If
  • Relajación de delegados
  • Comentarios XML


Screenshots:



Descárgalo aquí.


Espero que a alguien le sea de utilidad.

Presentación de curso "Aplicaciones multicapas"

Aquí adjunto el material de un mini-curso de "Aplicaciones Multicapas".

El paquete incluye la presentación de Powerpoint y el examen con sus respectivas respuestas.

Contenido de la presentación:
  • Definición de Aplicación Multicapas
  • Capa de Presentación
  • Capa de Negocio
  • Capa de Datos o Persistencia


Screenshot:



Descárgalo aquí.


Espero que a alguien le sea de utilidad.

Presentación de Curso "Programación Orientada a Objetos en .NET"

Aquí adjunto el material de un mini-curso de "Programación Orientada a Objetos en .NET".

El paquete incluye la presentación de Powerpoint, el examen con sus respectivas respuestas y el código de los ejemplos en VB y C#.


Contenido de la presentación:
  • Definición de la POO
  • Conceptos fundamentales de la POO
  • Clase
  • Objeto
  • Variables y métodos de clase
  • Herencia
  • Clases abstractas
  • Interfaces
  • Polimorfismo
  • Sobrecarga de funciones
  • Sobrecarga de operadores


Screenshots:



Descárgalo aquí.


Espero que a alguien le sea de utilidad.

martes, 20 de julio de 2010

LINQ2Sql: Modificar dinámicamente el nombre de una tabla en un DataContext de LINQ.

Ya van varias veces que veo preguntas de cómo hacer para cambiar dinámicamente el nombre de una tabla de un mapeo de LINQ.

Algunas aplicaciones crean nuevas tablas dinámicamente a medida que, por algún motivo, las van necesitando. Estas nuevas tablas se crean a partir de una tabla molde o "base".
Dicho de otra manera: Se tiene una base de datos en la que n tablas tienen el mismo esquema y sólo difieren en su nombre y, se desea poder mapear dichas tablas con un único DataContext que pueda ser instanciado dinámicamente según la tabla que se quiera consultar.

La misma idea se puede aplicar para el nombre de una base de datos o cualquier otro objeto de SQL.

NOTA: Los ejemplos de esta entrada están en inglés porque inicialmente fue la respuesta de este thread de MS

EL PROBLEMA:

Por defecto, el mapeo de LINQ se lleva a cabo mediante atributos y, como tales, no pueden ser modificados en tiempo de ejecución.
Pero por suerte el constructor de la clase DataContext de LINQ tiene una sobrecarga con el parámetro mappingSource, que nos permite obtener el DataContext a partir de un mapeo externo (que puede ser un archivo .xml).

CASO DE EJEMPLO:

Se tiene la tabla base Person, y otras dos tablas más llamadas Person_1 y Person_2, todas con idéntica estructura.

A continuación se lista el script que crea estas tablas:


Use [DB_Test]
GO
Create Table dbo.Person
(
ID int PRIMARY KEY,
Name nvarchar(MAX)
)
Create Table dbo.Person_1
(
ID int PRIMARY KEY,
Name nvarchar(MAX)
)
Create Table dbo.Person_2
(
ID int PRIMARY KEY,
Name nvarchar(MAX)
)
Insert Into dbo.Person Values (1, 'Base Table')
Insert Into dbo.Person_1 Values (1, 'Some data in Table_1')
Insert Into dbo.Person_2 Values (1, 'Some data in Table_2')

SOLUCIÓN:

La solución propuesta es mapear una única vez el esquema de la tabla y al momento de obtener el DataContext, especificar el nombre de la tabla que se quiere consultar.

Lo primero que necesitamos es generar un archivo .dbml con el mapeo de la tabla "base" de la forma habitual (Add New Item -> LINQ to SQL classes).
Como nombre le pondremos Person.dbml, por lo cual la clase generada se llamará PersonDataContext.
El diagrama quedará así:
dbml

Una vez generado el mapeo de la tabla base, procedemos a generar a partir de éste, un archivo .xml que también contendrá el mapeo.
Para esto utilizaremos la herramienta sqlmetal.
En línea de comandos de Visual Studio (Visual Studio Tools -> Visual Studio 2008 Command Prompt), ejecutar desde la carpeta donde se encuentra el archivo person.dbml:
SqlMetal /map:person.xml /code person.dbml
Esto generará el archivo person.xml cuyo contenido será algo como:


<?xml version="1.0" encoding="utf-8"?>
<Database Name="DB_Test" xmlns="http://schemas.microsoft.com/linqtosql/mapping/2007">
<Table Name="dbo.Person" Member="Persons">
<Type Name="Person">
<Column Name="ID" Member="ID" Storage="_ID" DbType="Int NOT NULL" IsPrimaryKey="true" />
<Column Name="Name" Member="Name" Storage="_Name" DbType="NVarChar(MAX)" />
</Type>
</Table>
</Database>


A continuación, es recomendable incluir el archivo person.xml en nuestro proyecto como recurso embebido, con las propiedades Build Action=Enbedded Resource y Copy to Output Directory=Do not copy, como se muestra a continuación:
add

Ahora necesitamos generar un método que retorne el DataContext apuntando a una tabla en específico.
Lo más cómodo es codificarlo en la misma clase (PersonDataContext).
La forma más directa es parándonos sobre Person.dbml en el solution explorer y haciendo click en el botón View Code. Esto generará el archivo Person.cs con la clase PersonDataContext a la que le agregamos el método y queda así:


namespace DynamicDataContext
{
 using System.Linq;
 using System.Xml;
 using System.Xml.Linq;
 using System.Data.Linq.Mapping;
 using System.IO;
 using System.Reflection;
 partial class PersonDataContext
 {
  private const string CNN_STRING = "Data Source=.;Initial Catalog=DB_Test;Integrated Security=True";
  public static PersonDataContext GetDataContext(string tableName)
  {
   // Get the .xml file into memory 
   Stream ioSt = Assembly.GetExecutingAssembly().GetManifestResourceStream("DynamicDataContext.person.xml");
   XElement xe = XElement.Load(XmlReader.Create(ioSt));
   // Replace the table name value in memory
   var tableElements = xe.Elements().AsQueryable().Where(e => e.Name.LocalName.Equals("Table"));
   foreach (var t in tableElements)
   {
    var nameAttribute = t.Attributes().Where(a => a.Name.LocalName.Equals("Name"));
    foreach (var a in nameAttribute)
    {
     if (a.Value.Equals("dbo.Person"))
     {
      a.Value = a.Value.Replace("Person", tableName);
     }
    }
   }
   // Obtain and return the dynamic DataContext
   XmlMappingSource source = XmlMappingSource.FromXml(xe.ToString());
   return new PersonDataContext(CNN_STRING, source);
  }
 }
}
Y eso es todo…
Cada vez que necesitemos el datacontext, llamaremos al método GetDataContext recién creado pasándole el nombre de la tabla que nos interesa en ese momento:


static void Main()
{
 // Query table Person_2 
 using (PersonDataContext dc = PersonDataContext.GetDataContext("Person_2"))
 {
  Console.WriteLine(dc.Persons.First().Name);
 }
 // Query table Person_1
 using (PersonDataContext dc = PersonDataContext.GetDataContext("Person_1"))
 {
  Console.WriteLine(dc.Persons.First().Name);
 }
 // Query table Person
 using (PersonDataContext dc = PersonDataContext.GetDataContext("Person"))
 {
  Console.WriteLine(dc.Persons.First().Name);
 }
 // Query default table (Person in this case)
 using (PersonDataContext dc = new PersonDataContext())
 {
  Console.WriteLine(dc.Persons.First().Name);
 }
 Console.ReadKey();
}


-- Puedes bajar este ejemplo aquí --


Suerte !

Federico.

viernes, 9 de julio de 2010

Project Euler #144 solución en VB.NET

Resolución de ejercicio #144 de Project Euler en VB.NET.



Este es un interesante ejercicio que simula un sistema de espejos que reflejan un laser.

El ejercicio consiste en averiguar cuántas veces el haz de un laser rebota dentro de una elipse antes de salir por un pequeño orificio de entrada/salida ubicado en la parte superior.

Una forma de resolverlo es con un método (algoritmo, función) que, a partir del punto de colisión (sobre el que incide el laser en la elipse), calcule el próximo punto de colisión del haz siguiendo las leyes de la reflexión.
El proceso continúa hasta que el punto de colisión obtenido pertenezca al orificio de entrada.










Para resolverlo, se utilizaron dos clases simples: RectaR2 y PuntoD.
La primera representa a una recta en el plano y la segunda representa a un punto en el plano:

'Clase para representar a una recta en el plano
Public Class RectaR2
 Public P As PuntoD
 Public m As Double
 'A partir de la pendiente y un punto incluido en la recta
 Sub New(ByVal m As Double, ByVal P As PuntoD)
  Me.m = m
  Me.P = P
 End Sub
 'A partir de dos puntos de la recta
 Sub New(ByVal P1 As PuntoD, ByVal P2 As PuntoD)
  Dim m As Double = (P2.Y - P1.Y) / (P2.X - P1.X)
  Me.m = m
  Me.P = P2
 End Sub
 'Ecuacion Explicita
 Public Overrides Function ToString() As String
  Return String.Format("y = {0}x + {1}", Me.m, Me.P.Y - Me.m * Me.P.X)
 End Function
End Class
'Clase para representar un punto en el plano
Public Class PuntoD
 Public X As Double, Y As Double
 Sub New()
 End Sub
 Sub New(ByVal x As Double, ByVal y As Double)
  Me.X = x
  Me.Y = y
 End Sub
End Class
También se utilizó un método que denominé Paso, que calcula el siguiente punto de colisión del laser a partir del punto de colisión actual.

Este método es el que contiene los cálculos trigonométricos necesarios para obtener la reflexión del laser.


'A partir de un punto de inicio y fin de un rayo laser (ambos en la elipse)
'retorna el proximo punto de contacto del laser (tambien en la elipse)
Function Paso(ByVal Pini As PuntoD, ByVal Pfin As PuntoD) As PuntoD
 Dim SgtePunto As New PuntoD()
 'Calculo la pendiente de la recta tangente a la elipse en el Punto de Fin (m = 4x/y)     (m1)
 Dim m1 As Double = -4 * Pfin.X / Pfin.Y
 'Obtengo la pendiente de la recta reflejada (reflejo sobre la recta tangente)... Y = m2*X + b
 'tmp = (m0-m1)/(1+m0*m1)         m2 = (m1-X)/(1+X*m1)
 Dim m0 As Double = (Pfin.Y - Pini.Y) / (Pfin.X - Pini.X)
 Dim tmp As Double = (m0 - m1) / (1 + m0 * m1)
 Dim m2 As Double = (m1 - tmp) / (1 + tmp * m1)
 'Obtengo los 2 puntos de interesección entre la recta reflejada y la elipse
 Dim b As Double = Pfin.Y - Pfin.X * m2
 Dim CoordsX As PuntoD = Cuadratica(4 + (m2 ^ 2), 2 * m2 * b, (b ^ 2) - 100)
 'Descartar el punto fin (Pfin)
 SgtePunto.X = If(Math.Abs(CoordsX.Y - Pfin.X) < 0.001, CoordsX.X, CoordsX.Y)
 SgtePunto.Y = m2 * SgtePunto.X + b
 Return SgtePunto
End Function
También se utilizó una forma para poder graficar el recorrido del laser en la pantalla:


Public Class Form1
 Private bitmap As Bitmap = New Bitmap(500, 1000)
 Sub New()
  ' This call is required by the Windows Form Designer.
  InitializeComponent()
  'Dibujar la elipse
  Using g As Graphics = Graphics.FromImage(bitmap)
   g.DrawEllipse(Pens.Blue, g.VisibleClipBounds)
  End Using
 End Sub
 'Convertir un punto del plano en un punto de la forma
 Public Function ConvertirPunto(ByVal P0 As PuntoD) As PointF
  Return New PointF(CSng(250 + P0.X * 50), CSng(500 - P0.Y * 50))
 End Function
 'Dibujar un segmento de recta dado
 Public Sub DibujarRecta(ByVal P0 As PuntoD, ByVal P1 As PuntoD)
  Using g = Graphics.FromImage(bitmap)
   g.DrawLine(Pens.Red, ConvertirPunto(P0), ConvertirPunto(P1))
   Me.PictureBox1.Image = bitmap
  End Using
 End Sub
 'Dibujar un número dado en la parte inferior
 Public Sub DibujarNum(ByVal num As Integer)
  Dim pt1 As New PointF(450, 970)
  Using g = Graphics.FromImage(bitmap)
   g.FillRectangle(Brushes.LightGray, pt1.X, pt1.Y, 50, 30)
   g.DrawString(num.ToString, New Font("Verdana", 14.0!), Brushes.Black, pt1)
   Me.PictureBox1.Image = bitmap
  End Using
 End Sub
End Class
Y por último, la entrada principal de la aplicación, donde está el ciclo que efectúa la búsqueda de puntos de incidencia, el conteo y la orden de dibujar en pantalla:


Sub Main()
 Dim PIni As New PuntoD(0, 10.1)
 Dim PFin As New PuntoD(1.4, -9.6)
 Dim frm As New Form1
 Dim temp As PuntoD
 Dim steps As Integer = 0
 frm.Show()
 While PFin.Y < 0 OrElse Math.Abs(PFin.X) > 0.01
  frm.DibujarRecta(PIni, PFin)
  frm.DibujarNum(steps)
  Application.DoEvents()
  temp = PIni
  PIni = PFin
  PFin = Paso(temp, PFin)
  steps += 1
 End While
 MessageBox.Show("Euler144=" & steps)
End Sub
Espero a alguien le sea útil... Y sino, no importa...



-- Puedes bajar este ejemplo aquí --

Datos personales