Acerca de:

Este blog contiene los códigos, ejemplos y bases de datos que he usado cuando aprendía acerca de algún tema específico. En lugar de borrarlos (una vez dominado ya el tema), he decidido publicarlos :)
Mostrando entradas con la etiqueta Visual Studio. Mostrar todas las entradas
Mostrando entradas con la etiqueta Visual Studio. Mostrar todas las entradas

jueves, 9 de junio de 2022

Error "Clase no registrada" al usar Microsoft.Speech en Visual Studio 2019 y Windows 10

Un día quise jugar con las librerías de Microsoft Speech para hacer hablar a mi laptop. Las descargas fueron las siguientes:

Microsoft Speech Platform Runtime. Descargué el instalador de 64 y 32 bits, bastan los instaladores de la plataforma en la que se compila la aplicación, pero por el error que explicaré más abajo tuve que probar ambos:

https://www.microsoft.com/en-us/download/details.aspx?id=27225

Microsoft Speech Platform Runtime Languages:

https://www.microsoft.com/en-us/download/details.aspx?id=27224

Los paquetes para reconocimiento de audio son los que dicen TELE, los paquetes para convertir texto a voz son los que tienen nombres de personas. Yo descargué los paquetes de español México y español España. En total fueron 4 paquetes de idioma.

Lo siguiente que hice fue crear un proyecto de C# con .Net Framework. Referencié el archivo Microsoft.Speech.dll en mi proyecto:

Para 64 bits, la dll está en C:\Program Files\Microsoft SDKs\Speech\v11.0\Assembly

Para 32 bits, está en C:\Program Files (x86)\Microsoft SDKs\Speech\v11.0\Assembly

Finalmente copié y pequé un poco del código de esta web: https://docs.microsoft.com/en-us/archive/msdn-magazine/2014/december/voice-recognition-speech-recognition-with-net-desktop-applications

        static void Main(string[] args)
        {
            try
            {
                ss.SetOutputToDefaultAudioDevice();
                Console.WriteLine("\n(Speaking: I am awake)");
                ss.Speak("He despertado");
                CultureInfo ci = new CultureInfo("es-PE");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.ReadLine();
            }
        }

Y apenas empezar el debugueo me saltó este error:

Retrieving the COM class factory for component with CLSID {D941651C-44E6-4C17-BADF-C36826FC3424} failed due to the following error: 80040154 Class not registered (Exception from HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG)).

Luego de intentar varias soluciones: cambiar a 32 bits, cambiar a .Net Framework 4, iniciar Visual Studio como administrador, lo único que funcionó fue lo propuesto en este foro


En 64 bits el instalador está en C:\Program Files\Microsoft SDKs\Speech\v11.0\Redist

En 32 bits está en C:\Program Files (x86)\Microsoft SDKs\Speech\v11.0\Redist

Al ejecutar los instaladores se pueden ver los mensajes de que se están registrando las dlls.

Lugo volví a referenciar la dll de 64 bits, cambié a .Net Framework 4.5, puse que se trata de una aplicación de 64 bits, y probé.

Funcionó, la aplicación puede decir "He despertado" con la voz de una mujer (apodada Hilda).

Ya puedo ponerle voz a mis aplicaciones de C# :)

miércoles, 24 de febrero de 2021

Llamando a una dll en C++ desde Java mediante JNI

Ya había escuchado antes acerca de JNI (Java Native Interface) que permite acceder a código en C o C++ desde java, así que ya era hora de probarlo:

Primero, abro mi Visual Studio 2019, elijo Crear un Proyecto->C++->Biblioteca de Vínculos Dinámicos:

Mi proyecto se llama JNISample y está ubicado en D:. Lo que suelo hacer con mis dlls es crear un nuevo archivo de encabezado, en este caso se llamará jniSample.h:


Luego se hace click derecho al nombre del proyeccto, nos vamos a General->C++->Directorios de Inclusión Adicionales, e incluímos las carpetas Include de nuestra instalación de JDK tal y como indica esta web:


En mi caso las rutas son C:\Program Files\Java\jdk1.8.0_231\include y C:\Program Files\Java\jdk1.8.0_231\include\win32

En el archivo dllmain.cpp añadimos la siguiente función que simplemente toma dos cadenas de caracteres y suma sus longitudes:

La explicación del uso de la variable env está en esta web. En resumen es para indicar que se desea copiar la cadena de caracteres enviada por java a la memoria del código nativo en C++, y al final liberar esta memoria.

En el archivo .h se copia la declaración de la función:

Y se compila. El código dentro de los #ifdef es para que el compilador no decore el nombre de la función.

Ahora hay que crear la aplicación java. Yo estoy usando Netbeans 11.1. La aplicación de ejemplo es de tipo Ant y se llama JNISample1; la voy a ubicar dentro de la carpeta del proyecto de C++, JNISample.

Luego copio la dll compilada a la carpeta donde está el proyecto en Netbeans, en mi caso es D:\JNISample\JNISample1:

 

Siguiendo las instrucciones de esta web y esta otra, se añade el código necesario para cargar la dll y usarla desde java, debe quedar así:

 

Si arroja algún error, puede deberse a que no se ha escrito correctamente el nombre de la librería, éste es el nombre del archivo dll sin la extensión. Más información en este enlace.

Es preferible que la función que llama a la dll sea pública, así podremos usar este jar desde otro. Yo prefiero tener un jar intermedio entre la aplicación principal y la dll debido a los pasos que siguen a continuación:

Para enlazar la dll a la aplicación de java se debe crear el verdadero archivo .h con el que se debe recompilar la dll. Esto se hace invocando al ejecutable javah que existe dentro de la instalación del JDK (no he probado con el JRE). Para este paso hay que seguir las instrucciones de esta web, que se resumen en abrir la consola en la ubicación de la dll e ingresar el siguiente comando:

"C:\Program Files\Java\jdk1.8.0_231\bin\javah" -o jniSample.h -jni -classpath "D:\JNISample\JNISample1\build\classes" "jnisample1.JNISample1"

De forma más genérica tiene la siguiente forma:

"ruta a mi instalacion de java donde está javah" -o nombre_de_la_dll.h -jni -classpath "ruta de mi proyecto\build\classes" "paquete.clase"

Al presionar Enter, y si todo sale bien no debe decirnos nada, sólo debe mostrarnos mensajes en caso de un error.

Y con esto ya tenemos nuestro archivo de cabecera .h el cual se debe reemplazar en el proyecto de Visual Studio. En mi caso javah me generó esto:

 

Simplemente copio todo este contenido y lo reemplazo en mi archivo jniSample.h de mi proyecto de Visual Studio.

A continuación se le cambia el nombre a la función original en dllmain.cpp.

Inicialmente estaba así:

Y ahora debo modificarla cambiándole el nombre que aparece en el archivo .h:

Luego compilo todo y reemplazo la dll resultante por la que está en la carpeta del proyecto de Netbeans.

Y eso es todo:


Los dos proyectos se pueden descargar de este enlace. El proyecto de Visual Studio es para la versión 2019.

martes, 22 de diciembre de 2020

Compilando las librerías Opencv 4.2 y Opencv_contrib con CMake y Visual Studio 2019

Opencv viene de dos formas: la librería ya compilada que contiene funciones libres y probadas de visión por computadora, y aparte las funciones de opencv_contrib, las cuales no tienen licencias 100% libres o aún son experimentales. Por ello opencv_contrib sólo se distribuye en código fuente que debe compilarse para poder usarlas.

El mejor tutorial que he encontrado para generar los binarios de opencv_contrib es este.

Primero nos vamos a https://opencv.org/releases/ y bajamos las fuentes "sources" de la versión que queremos, yo escogí la 4.2 por ninguna razón en especial.

Luego nos vamos a https://github.com/opencv/opencv_contrib/releases/tag/4.2.0 y descargamos las fuentes de opencv_contrib (las versiones de ambos deben ser las mismas). La lista de versiones de opencv_contrib está aquí.

Luego descomprimimos ambos archivos en la misma carpeta, yo escogí D:

Además hay que crear una carpeta a dónde irán nuestras librerías ya compiladas, yo la llamé opencv.


Luego descargamos e instalamos la última versión de CMake. Yo escogí el instalador msi para Windows.

Ejecutamos CMake, ingresamos la carpeta donde están los códigos fuente opencv (en mi caso es opencv-4.2.0) y la carpeta de destino a donde irán los binarios, luego presionamos el botón Configure:

Aquí podemos escoger si quremos que se genere la solución para Visual Studio. Yo escogí la versión 2019, a continuación se presiona Finish. Yo suelo presionar una vez más Configure después de este paso, pero puede que no sea necesario. Una vez configurado, Cmake nos mostrará las opciones de configuración:


Para compilar con opencv_contrib buscamos las siguientes opciones:

 

OPENCV_ENABLE_NONFREE debe estar seleccionado, y OPENCV_EXTRA_MODULES_PATH debe tener la ruta de la carpeta modules dentro de la carpeta donde hemos descomprimido opencv_contrib.

A continuación presionamos Generate. Este paso puede tomar algunos minutos. En la carpeta definida como el destino de los binarios aparecerá un archivo llamado OpenCV.sln que debemos abrir con la versión de Visual Studio elegida:


En Visual Studio elegimos Release, la plataforma a la que queremos compilar (yo puse x64), y tal y como dice el tutorial, compilar primero el proyecto donde dice BUILD y luego INSTALL:

Esta parte puede demorar un buen rato.

En mi caso los binarios se fueron a las carpetas D:\opencv\install\x64\vc16\bin para las dlls y D:\opencv\install\x64\vc16\lib para las librerías estáticas. Antes de poder usarlas en nuestros proyectos de Visual Studio hay que setearlas en la variable de entorno Path e INCLUDE.

En Path van las ubicaciones de las librerías:


INCLUDE debe crearse en caso de no existir, contiene la ruta a donde están los archivos de cabecera .h y .hpp. En mi caso se fueron a D:\opencv\install\include:


En Windows 10 no estoy segura si es necesario reiniciar el equipo, pero por precaución es mejor reiniciar.

Y ahora a configurar el proyecto de Visual Studio. El mejor tutorial que encontré es éste, pero no incluye las librerías opencv_contrib, pero los pasos son muy parecidos:

Ponemos el proyecto en Release y en la misma plataforma para la que fue compilada opencv (x64 en mi caso).

Configuramos lo siguiente en las propiedades del proyecto (en lugar de elegir Debug o Release, yo escogí Todas las Configuraciones):

General->Versión del SDK de Windows Última instalada (en mi caso, estoy en Windows 10 con Visual Studio 2019, mi versión es la 10.0)

En la opción Directorios de VC++ ponemos las siguientes rutas:

Directorios de archivos de inclusión: Donde se ubican los archivos de cabecera, es la misma ruta que la variable de entorno INCLUDE

Directorios de archivos de bibliotecas: Donde se ubican los archivos de librerías estáticas. Es la misma que la ingresada en la variable de entorno Path. 


Luego en la opción VC++ -> General ingresamos en Directorios de Inclusión Adicionales la ruta de la variable INCLUDE:


En Vinculador -> General ponemos en Directorios de Bibliotecas Adicionales la ruta de la variable Path donde están las librerías estáticas:

 

Y finalmente en la opción Vinculador -> Entrada, en donde dice Dependencias Adicionales, en lugar de la librería opencv_worldxxx.lib, se deben ingresar la lista de TODAS las librerías en la carpeta de la variable Path donde están las librerías estáticas:


Lo bueno, tengo este script, sólo hay que reemplazar la ruta de las librerías y escribirá en un archivo de texto la lista de todos los archivos que se hallan en esa carpeta:

@echo off
REM Next command creates a list of program files
dir "D:\opencv\install\x64\vc16\lib" > D:\list_of_libs.txt

Luego abrimos el archivo creado con notepad++ y con alt+selección se puede seleccionar sólo los nombres de los archivos para luego pegarlos:


Y eso es todo!

Y ahora la pregunta:

¿cómo distribuyo mi aplicación que usa opencv_contrib?

para distribuir esta... cosa se deben copiar los directorios apuntados por las variables INCLUDE y Path, y pegarse en rutas específicas de la pc destino. En esta pc se deben configurar las respectivas variables INCLUDE y Path para que apunten a las respectivas rutas de los archivos de cabecera h, hpp y los archivos de librerías lib y dll. A pesar de que en Visual Studio sólo se referencian los archivos lib también son necesarias las dlls.

Es probable que también sea necesario instalar los redistributables de Visual Studio 2019 para C++, se pueden descargar de aquí de forma directa. Descripción y descarga aquí.


jueves, 20 de febrero de 2020

Ecualización del Histograma de una Imagen a Color

Otra entrada migrada de la vieja web:

Revisando mi programa para ecualizar el histograma de una imagen en blanco y negro, pensé que ya era hora de aplicar el mismo algoritmo pero para imágenes a color. El procedimiento es el mismo que el que explico aquí, pero la ecualización se aplica sobre las tres componentes de cada píxel (R,G,B). Aparte, le hice una mejora al código fuente: todo lo que es el procesamiento de la imagen está en una clase separada del código del formulario (la ventana del programa). La clase de llama "Imagen" y tiene un solo método: "EcuHistograma" que devuelve un mapa de bits con la imagen ya procesada. A continuación está el código que ecualiza el histograma para los tres planos R, G y B:


La imagen con el histograma ecualizado es:




Añadiendo Ruido Tipo Perlin


En Internet, ya no recuerdo cómo, me topé con esto:  https://flafla2.github.io/2014/08/09/perlinnoise.html. Debo admitir que en un principio fue difícil de entender la lógica detrás del Ruido de Perlin, mas después de mucho leer y revisar los seudocódigos, entendí de qué trataba todo:
1. Se tiene un píxel de una imagen con sus dos coordenadas: X e Y.

2. Se ingresan las coordenadas X e Y. A partir de esos dos valores, la función que genera el ruido de Perlin devolverá un solo valor, el cual se sumará o restará al píxel correspondientes a dichas coordenadas.

3. Es importante que para unos valores dados de X e Y, la función generadora del ruido de Perlin siempre dé como resultado el mismo valor, por ello se dice que es seudoaleatoria: inicia con ciertos valores aleatorios al inicio del algoritmo y que no vuelven a variar a menos que se vuelva a correr el algoritmo desde cero. Los números aleatorios se crean al inicio solamente. La función generadora sería totalmente aleatoria si generada un número aleatorio para cada píxel, mas siempre utiliza los mismos números.

Esto es más fácil de comprender en esta web, donde está el algoritmo del que basé mi código: http://www.sepcot.com/blog/2006/08/PDN-PerlinNoise2d. Este código está hecho para el programa Freeware escrito en C#: Paint.Net. Yo lo adapté para que funcionara de forma independiente, además le añadí una segunda función para generar ruido, basada en funciones trigonométricas. Al combinar mi función con la original, y jugar con algunas constantes, obtuve un interesante efecto de cuadraditos:



El código completo para ecualizar histogramas de imágenes a color y añadir ruido Perlin puede bajarse de aquí (para Visual Studio Express 2008).

miércoles, 11 de septiembre de 2019

Error de Visual C++ 2017: C3078 se debe especificar el tamaño de la matriz en nuevas expresiones

Este error no me pasaba en Visual Studio 2013. El error C3078 surgió de repente luego de actualizar mi proyecto en Visual C++ a Visual Studio 2017 y al SDK de Windows versión 10.0.17763.0 (para actualizar el SDK al que apunta nuestra solución se hace clic derecho en Solución->Redestinar Solución):



La línea que generaba el error en mi código fuente es la segunda en el siguiente ejemplo:

unsigned char* tempPointer;
tempPointer = new unsigned char[]{'H', 'i', '\0'};

El error no podría ser más fácil de resolver, sólo hay que indicar el tamaño del array:

unsigned char* tempPointer;
tempPointer = new unsigned char[3]{'H', 'i', '\0'};

Algo debe haber cambiado en el estándar de C++.

viernes, 2 de septiembre de 2016

Cómo evitar que C++ decore los nombres de las funciones de una dll

Agradezco la ayuda a:
http://stackoverflow.com/q/2804893
http://stackoverflow.com/q/1467144

Mi caso era que estaba compilando una dll en c++ con Visual Studio Express 2013 y encontré que, al intentar invocarla desde otra aplicación, el compilador decoraba los nombres de las funciones.
Para evitarlo, se deben declarar las funciones con extern "C":

En el archivo  .h:

extern "C" __declspec (dllexport) long SomeFunction(int param);

Y en el archivo .cpp respectivo:

extern "C" 
__declspec (dllexport) long SomeFunction(int param)
{
    return _somethingIwantToDo(param);
}


si se está depurando, es mejor dejar la opción de "Generar Información de Depuración" en "Si" o el depurador empezará a protestar:

Esto es mejor dejarlo en "Si".

Al colocar  extern "C" el compilador ya no decora los nombres de las funciones aunque la convención de llamada sea stdcall o cdecl:

 
Eso sí, la convención de llamada de la dll y la aplicación que la invoca debe ser la misma, o el compilador arrojará el error LNK2019 y de paso el LNK1120:


viernes, 22 de julio de 2016

Cambiando la codificación de un archivo de Python en Python Tools for Visual Studio 2013 Express

Como siempre olvido cómo ponerle la codificación UTF-8 a mis archivos de python he hecho este tutorial. Por defecto el IDE les pone codificación Ansi, sucede que a veces mis comentarios tienen acentos y el intérprete me tira error al ejecutarlos.

1. En la primera línea le ponemos la codificación deseada, en este caso es "# coding=utf-8". La codificación debe ir con el símbolo de numeral para que el intérprete la reconozca:



2. Vamor a Archivo->Guardar como...



3. Elegimos "Guardar con codificación..."



4. Elegimos la codificación "Unicode UTF-8":


De esta forma el intérprete no tirará error al poner comentarios con caracteres internacionales.

sábado, 23 de abril de 2016

Gráfica del Movimiento Browniano unidimensional en Python

El Movimiento Browniano puede considerarse la suma acumulada de una serie de variables aleatorias con distribución normal y media cero. Para aproximar a un Movimiento Browniano continuo, se pueden utilizar "segmentos" (o mejor dicho: sus raíces cuadradas) de un intervalo multiplicado por las variables aleatorias. Las raíces cuadradas resultan de un teorema de convergencia en probabilidad. Esta convergencia se calcula utilizando la función esperanza o media.

El código para generar la gráfica del Movimiento Browniano fue traducido del Matlab al Python a partir del código del capítulo 2 del libro "Stochastic Diferential Equations: Models and Numerics" de Jesper Carlsson, Kyoung-Sook Moon, Anders Szepessy, Raúl Tempone y  Georgios Zouraris. Además, como ejercicio, quise implementar mi propia función de suma acumulada "cumsum". El código resultante es el siguiente:


import numpy as np
import math
import matplotlib.pyplot as plt

def cumsum(lista):
    lista2 = [lista[0]]
    for i in range(1, len(lista)):
        lista2.append(lista[i] + lista2[-1])

    return lista2


N = 1E6
np.random.seed(1337)
A = np.random.normal(0, 1, N-1)
T = 1
dt = 1/(N-1)
t = [c/(N-1) for c in range(0, int(N-1))]
dW = [c*math.sqrt(dt) for c in A]
W = cumsum(dW)

# Aqui se requiere Numpy y Mathplotlib
plt.plot(W)
plt.ylabel('Brownian Motion')
plt.show()

'''
N = 1E6; % number of timesteps
randn('state',0); % initialize random number generator
T = 1; % final time
dt = T/(N-1); % time step
t = 0:dt:T;
dW = sqrt(dt)*randn(1,N-1); % Wiener increments
W = [0 cumsum(dW)]; % Brownian path
LHS = sum(t(1:N-1).*dW);
RHS = T*W(N) - sum(W(1:N-1))*dt;
'''


Para instalar Numpy y Matplotlib se debe bajar el archivo get-pip.py de este enlace. Y se debe ejecutar en la terminal (para Linux) o en el CMD (para Windows) la siguiente instrucción:

python get-pip.py

Si es Linux es mejor poner:

sudo python get-pip.py

La terminal o el CMD deben apuntar a la carpeta donde está el archivo get-pip.py.

Luego se debe instalar numpy y matplotlib. En Linux se ingresa los comandos:

pip install matplotlib
pip install numpy

Si no recuerdo mal, Matplotlib también instala Numpy.

En Windows, como soy muy floja, me descargué el pip-Win e ingresé los respectivos comandos en la caja de texto donde pide el comando:




Éste es el resultado. Estoy usando Python Tools for Visual Studio:




sábado, 11 de abril de 2015

Listar los archivo en una carpeta y sus subcarpetas de forma recursiva

Un día necesité listar los archivos existentes en una carpeta y sus subcarpetas. Como reto, quise implementar mi propia función y aquí está :D

Los algoritmos que recorrer árboles de directorios son recursivos, no se usan bucles debido a que el algoritmo ignora la profundidad que alcanzarán los subdirectorios en el árbol.

import os
from os import listdir
from os.path import isfile, isdir, join

def listdir_recurd(files_list, root, folder, checked_folders):

    if (folder != root):
        checked_folders.append(folder)

    for f in listdir(folder):

        d = join(folder, f)       

        if isdir(d) and d not in checked_folders:
            listdir_recurd(files_list, root, d, checked_folders)
        else:
            if isfile(d):  # si no hago esto, inserta en la lista el nombre de las carpetas ignoradas
                files_list.append(f)

    return files_list



La forma de usar esta función es:

if __name__ == "__main__":
    filez = listdir_recurd([], 'D:\Sample', 'D:\Sample', ['D:\\Sample\\Uno']) # esto omite la subcarpeta 'D:\\Sample\\Uno'

    filez = listdir_recurd([], 'D:\Sample', 'D:\Sample', ['D:\\Sample\\Uno', 'D:\\Sample\\Dos']) # esto omite la subcarpeta 'D:\\Sample\\Uno' y la subcarpeta 'D:\\Sample\\Dos'

    filez_ = listdir_recurd([], 'D:\Sample3', 'D:\Sample3', []) # esto no omite ninguna subcarpeta

La función recibe los siguientes parámetros:

"files_list": es el acumulador. Siempre es una lista vacía.

"root" y "folder": carpeta raíz y carpeta con los archivos que se va a listar, estas dos rutas deben ser la misma. La carpeta con los archivos a listar es la carpeta actual cuyos archivos se están listando, su valor lo controla el algoritmo y va recorriendo las subcarpetas que se van hallando.

"checked_folders": lista las subcarpetas en la carpeta del parámetro "root" que se desean omitir. Si se desea listar todos los archivos, se ingresa una lista vacía.

Python permite ingresar el separador de rutas como \ ó \\.

Esta función sólo ha sido probada en Windows, y ejecutada con Python Tool for Visual Studio usando Python 2.7

viernes, 12 de septiembre de 2014

Cómo ejecutar Visual Studio 6 en Windows 7 y evitar los errores con referencias y dependencias

Tengo un Visual Basic 6 Enterprise corriendo en Windows 7 de 32 bits. Todo parece funcionar bien: se ha instalado sin problemas, y se ejecuta sin inconveientes.
Pero al abrir un proyecto nuevo del tipo Exe estándar, e intentar cargar librerías y ocx de terceros (no son de Microsoft, o no están firmadas por Microsoft) me salta este error "Error al intentar tener acceso al registro del sistema":


(No lo parece, pero esto es un Windows 7, sólo que con el tema de Windows Clásico. Los colorcitos sólo sirven para consumir memoria, otra razón es que así puedo aluscinar que tengo un Windows Server)


Este fue un error muy feo que me tuvo ocupada durante horas (además de hacerme instalar y desinstalar las ocx varias veces), y al final la solución era muy simple, ejecutar el Visual Studio 6 como Administrador:


Ya con todos los permisos disponibles, el Windows nos deja importar componentes, referencias y dependencias. Y como se muestra en la imagen, el Visual Studio 6 puede convivir perfectamente con el Visual Studio 2013 (yo tengo la versión Express).
Un último consejo: si se tiene un proyecto de Visual Basic 6 con dependencias de terceros, es mejor ejecutar primero el IDE como administrador, y luego abrir nuestro proyecto. Se evitarán así muchos errores.

martes, 15 de enero de 2013

El Control DataGridView lanza una System.ArgumentOutOfRangeException al recorrer sus filas

Tengo un DataGridView llamado dGridVIew al cual le añado datos de la siguiente manera:

DataRow[] dRow = MetodoQueDevuelveUnArrayDeDataRows();
object[] param = new object[3];

for (int i = 0; i < dRow.Count(); i++)
      {
           param[0] = dRow[i]["Campo 1"];
           param[1] = dRow[i]["Campo 2"];
           param[2] = dRow[i]["Campo 3"];

// Evito una excepción al hacer click en las cabeceras y si alguna celda tiene valor nulo
       for (int j = 0; j < param.Length; j++)
             if (param[j] == DBNull.Value)
                 param[j] = String.Empty;

             d
GridView.Rows.Add(param);
      }

Todo bien hasta aquí. Pero sucedía que después de llamar a este código, en el control dGridView no se mostraban todas las filas añadidas, a menos que redimensionada el formulario contenedor. Peor aún, al recorrer las filas con las teclas de las flechas hacia arriba o abajo, me saltaba la siguiente excepción:

No se controló System.ArgumentOutOfRangeException
  Message=El valor de '484' no es válido para 'Value'. 'Value' debería estar entre 'minimum' y 'maximum'.
Nombre del parámetro: Value
  Source=System.Windows.Forms
  ParamName=Value
  StackTrace:
       en System.Windows.Forms.ScrollBar.set_Value(Int32 value)
       en System.Windows.Forms.DataGridView.ScrollRows(Int32 rowCount, Int32 deltaY, ScrollEventType scrollEventType)


Rebuscando en Internet, este blog me dio la solución.
Y era muy simple: Después de llenar el DataGridView se debe llamar al método PerformLayout de la siguiente manera:

dGridView.PerformLayout();

No he podido encontrar porqué esta función evita la excepción, ni siquiera en la web de Microsoft.

Update!!

El código de ejemplo aún tiene un error: el DataGridView dGridView aún puede tirar una excepción si hacemos clic a la cabecera de una columna que espera recibir datos numéricos. El código corregido es:

DataRow[] dRow = MetodoQueDevuelveUnArrayDeDataRows();
object[] param = new object[3];

// Los valores del sgte array deben coincidir con los nombres de las columnas
string[] columnas = { "Campo 1", "Campo 2", "Campo 3" };

for (int i = 0; i < dRow.Count(); i++)
      {
           param[0] = dRow[i]["Campo 1"];
           param[1] = dRow[i]["Campo 2"];
           param[2] = dRow[i]["Campo 3"];

       // Evito una excepción al hacer click en las cabeceras y si alguna celda tiene valor nulo
       for (int j = 0; j < param.Length; j++)
             if (param[j] == DBNull.Value)

             {
       // en el caso de trabajar directamente con un Datatable la sgte línea se reemplaza por: 
      //    if (unDataTable.Columns[columnas[j]].DataType == typeof(string))
                 if (dRow[i].Table.Columns[columnas[j]].DataType == typeof(string))
                      param[j] =
String.Empty;
                 else
                      param[j] = 0;
              }


             d
GridView.Rows.Add(param);
      }

dGridView.PerformLayout();

miércoles, 29 de agosto de 2012

Tutorial: Ejemplo de uso de las apis BitBlt, SetDIBits y GetDIBits

Actualización de Electrónica a Martillazos, Sección Visual Basic 6 y C++:
Ejemplo de Win32 y uso de las apis BitBLT, GetDIBits y SetDIBits. Compilado para Visual C++ Express 2008.
Link Directo
Un Mirror
Enlace para descargar el proyecto

Enjoy!