Buenas, os dejo una pequeña introducción muy rapida al tema, c# es un lenguaje muy amigable y sencillo, con una curva de aprendizaje mucho mas corta de lo normal.
http://www.youtube.com/watch?v=oOf40sJyzq4 [Ver en HQ]
Y os dejo material del curso:
-Enlace al template proyecto para crear dlls: http://sites.google.com/site/robertgies ... gedexports
-Codigo a ingresar en un control windows forms (activex):
Este codigo siempre hay que ponerlo como directiva, una vez hecho ya esta, todo funcionara correcto como en el ejemplo
Otra cosilla digna de mencionar, las dll generadas NO SE REGISTRAN CON REGSERV32 y desconozco si se puede hacer con system.registeractivex pero supongo que NO, en su lugar esas dll se registran con un exe llamado REGASM.EXE (si lo compilas con vs re registra solo) si vemos que la cosa se complica en el momento de redistribuir monto una dll para registrar estos controles
Descargar:
Codigo fuente (a insertar un picturebox llamado PbxImagen)
http://www.youtube.com/watch?v=oOf40sJyzq4 [Ver en HQ]
Y os dejo material del curso:
-Enlace al template proyecto para crear dlls: http://sites.google.com/site/robertgies ... gedexports
-Codigo a ingresar en un control windows forms (activex):
namespace ..............
[ProgId("Webcam.PablokoControl")]
[ClassInterface(ClassInterfaceType.AutoDual)]
public partial class ************ : UserControl
...
Para meter en la clase principal
/// <summary>
/// Register the class as a control and set it's CodeBase entry
/// </summary>
/// <param name="key">The registry key of the control</param>
[ComRegisterFunction()]
public static void RegisterClass(string key)
{
// Strip off HKEY_CLASSES_ROOT\ from the passed key as I don't need it
StringBuilder sb = new StringBuilder(key);
sb.Replace(@"HKEY_CLASSES_ROOT\", "");
// Open the CLSID\{guid} key for write access
RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(), true);
// And create the 'Control' key - this allows it to show up in
// the ActiveX control container
RegistryKey ctrl = k.CreateSubKey("Control");
ctrl.Close();
// Next create the CodeBase entry - needed if not string named and GACced.
RegistryKey inprocServer32 = k.OpenSubKey("InprocServer32", true);
inprocServer32.SetValue("CodeBase", Assembly.GetExecutingAssembly().CodeBase);
inprocServer32.Close();
// Finally close the main key
k.Close();
}
/// <summary>
/// Called to unregister the control
/// </summary>
/// <param name="key">Tke registry key</param>
[ComUnregisterFunction()]
public static void UnregisterClass(string key)
{
StringBuilder sb = new StringBuilder(key);
sb.Replace(@"HKEY_CLASSES_ROOT\", "");
// Open HKCR\CLSID\{guid} for write access
RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(), true);
// Delete the 'Control' key, but don't throw an exception if it does not exist
k.DeleteSubKey("Control", false);
// Next open up InprocServer32
RegistryKey inprocServer32 = k.OpenSubKey("InprocServer32", true);
// And delete the CodeBase key, again not throwing if missing
k.DeleteSubKey("CodeBase", false);
// Finally close the main key
k.Close();
}
Propiets/assamblyinfo.cs:
[assembly: ComVisible(true)]
Este codigo siempre hay que ponerlo como directiva, una vez hecho ya esta, todo funcionara correcto como en el ejemplo
Otra cosilla digna de mencionar, las dll generadas NO SE REGISTRAN CON REGSERV32 y desconozco si se puede hacer con system.registeractivex pero supongo que NO, en su lugar esas dll se registran con un exe llamado REGASM.EXE (si lo compilas con vs re registra solo) si vemos que la cosa se complica en el momento de redistribuir monto una dll para registrar estos controles
Aqui os dejo un pequeño ejemplo de la aplicacion para la webcam de demostración recordad registrar la dll antes de debugear el proyectoRegister the DLL again using 'Regasm' as follows.
Open the DOS prompt via
"Start > Programs > Accessories > Command Prompt".
Enter the following command according to the programming language used:
C#:
"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\regasm.exe" "<Path to the DLL>.dll" /codebase
Descargar:
Codigo fuente (a insertar un picturebox llamado PbxImagen)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Imaging; // Para trabajar con imágenes
using System.Drawing.Drawing2D; // Para trabajar con Imágenes
using System.Runtime.InteropServices;
using Microsoft.Win32; // Para usar API
using System.Reflection;
using System.IO;
namespace WindowsFormsControlLibrary1
{
[ProgId("Webcam.PablokoControl")]
[ClassInterface(ClassInterfaceType.AutoDual)]
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
WebCam MiWebcam = new WebCam(10, PbxImagen);
}
private void UserControl1_Load(object sender, EventArgs e)
{
WebCam MiWebcam = new WebCam(10, PbxImagen);
PbxImagen.Width = this.Width;
PbxImagen.Height = this.Height;
}
public void Question()
{
MessageBox.Show("Who is number one?");
}
public string sakatambliki = "sakatambliki!";
public void Capturar(int cp)
{
WebCam MiWebcam = new WebCam(10, PbxImagen);
MiWebcam.Capturar(cp);
}
public void Parar()
{
WebCam MiWebcam = new WebCam(10, PbxImagen);
MiWebcam.StopCaptura();
}
public void Foto()
{
WebCam MiWebcam = new WebCam(10, PbxImagen);
MiWebcam.GuardarImagen();
}
public String GetWebcams()
{
WebCam MiWebcam = new WebCam(10, PbxImagen);
return MiWebcam.Listar2();
}
/// <summary>
/// Register the class as a control and set it's CodeBase entry
/// </summary>
/// <param name="key">The registry key of the control</param>
[ComRegisterFunction()]
public static void RegisterClass(string key)
{
// Strip off HKEY_CLASSES_ROOT\ from the passed key as I don't need it
StringBuilder sb = new StringBuilder(key);
sb.Replace(@"HKEY_CLASSES_ROOT\", "");
// Open the CLSID\{guid} key for write access
RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(), true);
// And create the 'Control' key - this allows it to show up in
// the ActiveX control container
RegistryKey ctrl = k.CreateSubKey("Control");
ctrl.Close();
// Next create the CodeBase entry - needed if not string named and GACced.
RegistryKey inprocServer32 = k.OpenSubKey("InprocServer32", true);
inprocServer32.SetValue("CodeBase", Assembly.GetExecutingAssembly().CodeBase);
inprocServer32.Close();
// Finally close the main key
k.Close();
}
/// <summary>
/// Called to unregister the control
/// </summary>
/// <param name="key">Tke registry key</param>
[ComUnregisterFunction()]
public static void UnregisterClass(string key)
{
StringBuilder sb = new StringBuilder(key);
sb.Replace(@"HKEY_CLASSES_ROOT\", "");
// Open HKCR\CLSID\{guid} for write access
RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(), true);
// Delete the 'Control' key, but don't throw an exception if it does not exist
k.DeleteSubKey("Control", false);
// Next open up InprocServer32
RegistryKey inprocServer32 = k.OpenSubKey("InprocServer32", true);
// And delete the CodeBase key, again not throwing if missing
k.DeleteSubKey("CodeBase", false);
// Finally close the main key
k.Close();
}
public class WebCam
{
// Conserva esta cabecera
// Empeorxdevil 2007
class SaveImage
{
// Conserva esta cabecera
// Emperorxdevil 2007
/// <summary>
/// Imagen que contiene la clase
/// </summary>
public Image Tmp; // referencia a la imagen del Picturebox Asociado
Form Ref; // referencia que necesitare a este formulario
Form Opciones;
GroupBox Gr;
RadioButton R1;
RadioButton R2;
RadioButton R3;
TextBox Porciento;
TextBox Larg; // Objetos necesarios para formar el diálogo
TextBox Anch;
Label L1;
Label L2;
Button Acepta;
Button Cancelar;
SaveFileDialog Sv;
DialogResult rs;
/// <summary>
/// Constructor de clase SaveImage
/// </summary>
/// <param name="imagen">Imagen que se va a guardar</param>
/// <param name="Interfaz"> Si se mostrará Interfaz</param>
public SaveImage(Image imagen, bool Interfaz)
{
Tmp = imagen; // Asigno la imagen...
Opciones = new Form();
Ref = Opciones;
Opciones.Width = 333; // Configuracion
Opciones.Height = 198;
Opciones.Text = "Parámetros de Imagen";
Opciones.ControlBox = false;
Opciones.ShowInTaskbar = false;
Opciones.FormBorderStyle = FormBorderStyle.FixedDialog;
Gr = new GroupBox();
Gr.Width = 288;
Gr.Height = 105;
Gr.Text = "Configuración";
Gr.Location = new Point(18, 15);
Porciento = new TextBox();
Porciento.Enabled = false; // Configuracion
Porciento.Text = "";
Porciento.Width = 37;
Porciento.Height = 20;
Porciento.MaxLength = 3;
Porciento.TextAlign = HorizontalAlignment.Center;
Porciento.Location = new Point(147, 47);
R1 = new RadioButton();
R1.Text = "Guardar con Dimensiones Actuales";
R1.Width = 191;
R1.Height = 17;
Gr.Controls.Add(R1);
R1.Location = new Point(18, 25);
R2 = new RadioButton();
R2.CheckedChanged += new EventHandler(R2_CheckedChanged);
R2.Text = "Reducir tamaño al";
R2.Width = 115; // Configuracion
R2.Height = 17;
R2.Location = new Point(18, 48);
Gr.Controls.Add(R2);
Gr.Controls.Add(Porciento);
L1 = new Label();
L1.Text = "%";
L1.AutoSize = true;
L1.Location = new Point(195, 50);
Gr.Controls.Add(L1);
R3 = new RadioButton();
R3.CheckedChanged += new EventHandler(R3_CheckedChanged);
R3.Text = "Cambiar tamaño a"; // Configuracion
R3.Width = 113;
R3.Height = 17;
R3.Location = new Point(18, 71);
Gr.Controls.Add(R3);
L2 = new Label();
L2.Text = "X";
L2.AutoSize = true;
L2.Location = new Point(195, 75);
Gr.Controls.Add(L2);
Larg = new TextBox();
Larg.Enabled = false;
Larg.Width = 37;
Larg.Height = 20;
Larg.MaxLength = 4;
Larg.TextAlign = HorizontalAlignment.Center;
Larg.Location = new Point(147, 71);
Gr.Controls.Add(Larg);
Anch = new TextBox();
Anch.Enabled = false;
Anch.Width = 37;
Anch.Height = 20;
Anch.MaxLength = 4;
Anch.TextAlign = HorizontalAlignment.Center; // Configuracion
Anch.Location = new Point(218, 70);
Gr.Controls.Add(Anch);
Acepta = new Button();
Acepta.Text = "Aceptar";
Acepta.Width = 59;
Acepta.Height = 26;
Acepta.Location = new Point(247, 133);
Acepta.Click += new EventHandler(Acepta_Click);
Cancelar = new Button();
Cancelar.Text = "Cancelar";
Cancelar.Width = 59;
Cancelar.Height = 26;
Cancelar.Location = new Point(18, 133);
Cancelar.Click += new EventHandler(Cancelar_Click);
Opciones.Controls.Add(Gr);
Opciones.Controls.Add(Acepta);
Opciones.Controls.Add(Cancelar);
Opciones.StartPosition = FormStartPosition.CenterScreen;
Opciones.ShowDialog();
}
/// <summary>
/// Constructor de la clase SaveImage sin Interfaz
/// </summary>
/// <param name="imagen">Imagen a Guardar</param>
public SaveImage(Image imagen)
{
Tmp = imagen; // Asigno la imagen...
}
void R3_CheckedChanged(object sender, EventArgs e)
{
if (this.R3.Checked) { this.Anch.Enabled = true; this.Larg.Enabled = true; }
else { this.Anch.Enabled = false; this.Larg.Enabled = false; }
}
void R2_CheckedChanged(object sender, EventArgs e)
{
if (this.R2.Checked) { this.Porciento.Enabled = true; }
else { this.Porciento.Enabled = false; }
}
void Acepta_Click(object sender, EventArgs e)
{
try
{
if (R1.Checked || R2.Checked || R3.Checked)
{
if (R2.Checked) { Tmp = Resize(Tmp, Convert.ToInt32(Porciento.Text)); }
if (R3.Checked) { Tmp = Resize(Tmp, Convert.ToInt32(Larg.Text), Convert.ToInt32(Anch.Text)); }
Sv = new SaveFileDialog(); // Creo un diálogo para salvar la imagen
Sv.Title = "Guardar imagen como..."; // Lo configuro
Sv.Filter = "Archivo JPG|*.jpg|Archivo PNG|*.png|Archivo GIF|*.gif|Mapa de Bits|*.bmp";
rs = Sv.ShowDialog(); // Lo muestro modal
if (rs == DialogResult.OK)
{
int x = Sv.FilterIndex; // Ontengo la extensión seleccionada
switch (x)
{
// Salvo la imagen en el formato deseado
case 1:
Tmp.Save(Sv.FileName, ImageFormat.Jpeg);
break;
case 2:
Tmp.Save(Sv.FileName, ImageFormat.Png);
break;
case 3:
Tmp.Save(Sv.FileName, ImageFormat.Gif);
break;
case 4:
Tmp.Save(Sv.FileName, ImageFormat.Bmp);
break;
}
Ref.Dispose(); // Cierro el formulario
}
}
else { MessageBox.Show("Al menos debe selecionar una opción", "xdevilWebCapture", MessageBoxButtons.OK, MessageBoxIcon.Warning); }
}
catch
{
MessageBox.Show("Introduzca valores válidos", "xdevilWebCapture", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
}
void Cancelar_Click(object sender, EventArgs e)
{
Ref.Dispose(); // Cierro el formulario
}
/// <summary>
/// Escala la imagen capturada al % especificado
/// </summary>
/// <param name="foto"> Imagen que se quiere escalar </param>
/// <param name="TantoPorCiento"> Porcentaje de reducción</param>
/// <returns>Imagen escalada</returns>
public Image Resize(Image foto, int TantoPorCiento)
{
float Tporciento = ((float)TantoPorCiento / 100); // Obtengo el coeficiente de dimension
int ImgOrAncho = foto.Width;
int ImgOrAlto = foto.Height; // Obtengo las dimensiones originales de la foto
int OrigX = 0;
int OrigY = 0;
int ResX = 0; // Variables referencia para saber donde empiezo a contar px
int ResY = 0;
int ResAncho = (int)(ImgOrAncho * Tporciento);
int ResAlto = (int)(ImgOrAlto * Tporciento); // Obtengo las dimensiones al % especificado
Bitmap RszIm = new Bitmap(ResAncho, ResAlto, PixelFormat.Format24bppRgb); // Creo una imagen con esas dimensiones y bpp
RszIm.SetResolution(foto.HorizontalResolution, foto.VerticalResolution); // Le doy la misma res. que la original
Graphics Gfoto = Graphics.FromImage(RszIm); // Creo una intancia de Graphics para manejar la imagen nueva
Gfoto.InterpolationMode = InterpolationMode.HighQualityBicubic; // Especifico la calidad del algoritmo de sampleo
// De la foto original, obtengo la redimensionada (mediante un rectángulo)
Gfoto.DrawImage(foto, new Rectangle(ResX, ResY, ResAncho, ResAlto), new Rectangle(OrigX, OrigY, ImgOrAncho, ImgOrAlto), GraphicsUnit.Pixel);
Gfoto.Dispose(); // Ya no me hace falta esto, asi que lo descargo
return (RszIm); // Devuelvo la imagen redimensionada
}
/// <summary>
/// Redimensiona la imagen en pixeles
/// </summary>
/// <param name="foto"> Imagen a redimensionar</param>
/// <param name="ancho">Ancho de la imagen</param>
/// <param name="alto">Alto de la imagen</param>
/// <returns>Imagen redimensionada</returns>
public Image Resize(Image foto, int ancho, int alto)
{
int ImgORAncho = foto.Width;
int ImgOrAlto = foto.Height; // Obtengo las dimensiones de la foto
int OrigX = 0;
int OrigY = 0;
int ResX = 0; // Varables referencia para saber donde contar px
int ResY = 0;
float Porciento = 0;
float PorcientoAncho = 0; // Porcentajes de sampleo
float PorcientoAlto = 0;
PorcientoAncho = ((float)ancho / (float)ImgORAncho);
PorcientoAlto = ((float)alto / (float)ImgOrAlto); //Calculo el % que puedo resamplear
if (PorcientoAlto < PorcientoAncho)
{
Porciento = PorcientoAlto;
}
else
{ // Para resamplear bien
Porciento = PorcientoAncho;
}
int AnchuraFinal = (int)(ImgORAncho * Porciento);
int AlturaFinal; // Calculo las nuevas dimensiones
if (ancho > alto)
{
AlturaFinal = (int)(ImgOrAlto * Porciento);
}
else
{
AlturaFinal = AnchuraFinal;
} // Para proporcionar la imagen
Bitmap RszIm = new Bitmap(ancho, alto, PixelFormat.Format24bppRgb);
RszIm.SetResolution(foto.HorizontalResolution, foto.VerticalResolution);
Graphics Gfoto = Graphics.FromImage(RszIm);
Gfoto.InterpolationMode = InterpolationMode.HighQualityBicubic;
Gfoto.DrawImage(foto, new Rectangle(ResX, ResY, AnchuraFinal, AlturaFinal), new Rectangle(OrigX, OrigY, ImgORAncho, ImgOrAlto), GraphicsUnit.Pixel);
Gfoto.Dispose();
return (RszIm);
}
} /// Clase que guarda las imágenes
#region Funciones API
[DllImport("user32.dll", EntryPoint = "SendMessage")]
public static extern int SendMessage(int hWnd, uint Msg, int wParam, int lParam);
[DllImport("avicap32.dll", EntryPoint = "capCreateCaptureWindowA")]
public static extern int capCreateCaptureWindowA(string lpszWindowName, int dwStyle, int X, int Y, int nWidth, int nHeight, int hwndParent, int nID);
[DllImport("user32.dll", EntryPoint = "EmptyClipboard")]
public static extern int EmptyClipboard();
[DllImport("avicap32.dll", EntryPoint = "capGetDriverDescriptionA")]
public static extern bool capGetDriverDescriptionA(int wDriverIndex, [MarshalAs(UnmanagedType.VBByRefStr)]ref String lpszName, int cbName, [MarshalAs(UnmanagedType.VBByRefStr)] ref String lpszVer, int cbVer);
//public static extern bool capGetDriverDescriptionA(int wdriver, string lpszName, int cbName, string lpszVer, int cbVer);
#endregion
#region Constantes API
const int WM_USER = 1024;
const int WM_CAP_CONNECT = 1034;
const int WM_CAP_DISCONNECT = 1035;
const int WM_CAP_GET_FRAME = 1084; // Constantes necesarias
const int WM_CAP_COPY = 1054;
const int WM_CAP_START = WM_USER;
const int WM_CAP_SET_PREVIEW = WM_CAP_START + 50;
const int WM_CAP_SET_PREVIEWRATE = WM_USER + 52;
#endregion
private int Frecuencia = 0; // Frecuencia de captura de imagen
private int CamHandle = 0; // Handle del dispositivo
Timer reloj; // Timer
//ComboBox Cbx; // Para referencia al Combobox
PictureBox Pbx; // Para referencia al Picturebox
/// <summary>
/// Crea una instancia de la clase WebCam de Emperorxdevil
/// </summary>
/// <param name="frecuencia">Intervalo de tiempo en el que se capturarán las imágenes</param>
/// <param name="pct">PictureBox en el cual se mostrará lo capturado por la webcam</param>
/// <param name="cb"> Listbox en el que se mostrarán las Cams detectadas</param>
public WebCam(int frecuencia, PictureBox pct)
{
Frecuencia = frecuencia;
Pbx = pct; // Inicio las variables necesarias
reloj = new Timer(); // Creo el timer
reloj.Tick += new EventHandler(reloj_Tick); // Le asigno el controlador
reloj.Interval = Frecuencia; // Asigno la velocidad de captura
//Cbx = cb; //Configuro la referencia
}
private void reloj_Tick(object sender, EventArgs e)
{
SendMessage(CamHandle, WM_CAP_GET_FRAME, 0, 0); // Capturo la imagen
SendMessage(CamHandle, WM_CAP_COPY, 0, 0); // La copio al portapeles
SaveImage k = new SaveImage(Clipboard.GetImage());
Pbx.Image = k.Resize(Clipboard.GetImage(),Pbx.Width,Pbx.Height); // La mando al Picturebox
EmptyClipboard(); // Vacío el portapapeles
}
/// <summary>
/// Listará las cámaras web encontradas en el Combobox asociado
/// </summary>
/*public void Listar()
{
bool valor;
string nombre;
string version;
int x = 0;
do
{
nombre = "Dispositivo" + x.ToString();
valor = capGetDriverDescriptionA(x, nombre, 100, "v1", 100);
if (valor) Cbx.Items.Add(nombre);
x = x + 1;
} while (!valor == false);
}*/
/*public void Listar()
{
bool valor;
String nombre = "".PadRight(100); ;
String version = "".PadRight(100); ;
int x = 0;
do
{
valor = capGetDriverDescriptionA(x, ref nombre, 100, ref version, 100);
if (valor)
{
Cbx.Items.Add(nombre + " " + version);
}
x = x + 1;
} while (!valor == false);
}*/
public String Listar2()
{
bool valor;
string gg = "";
String nombre = "".PadRight(100); ;
String version = "".PadRight(100); ;
int x = 0;
do
{
valor = capGetDriverDescriptionA(x, ref nombre, 100, ref version, 100);
if (valor)
{
gg = gg + nombre + " " + version + "|";
//Cbx.Items.Add(nombre + " " + version);
}
x = x + 1;
} while (!valor == false);
return gg;
}
/// <summary>
/// La WebCam se Encenderá y mostrará lo capturado en el PictureBox referenciado
/// </summary>
/// <param name="Dispositivo">Nº de dispositivo del Combobox</param>
public void Capturar(int Dispositivo)
{
try
{
StopCaptura(); // Antes de nada "reseteo" el dispositivo
CamHandle = capCreateCaptureWindowA("XdevilCapture" + Dispositivo.ToString(), 0, 0, 0, 0, 0, Pbx.Handle.ToInt32(), Dispositivo); // Obtengo el Handle de la cam
SendMessage(CamHandle, WM_CAP_CONNECT, 0, 0); // Enciendo la cam
SendMessage(CamHandle, WM_CAP_SET_PREVIEWRATE, 30, 0); // Establezco los frames de captura /seg
SendMessage(CamHandle, WM_CAP_SET_PREVIEW, 0, 0); // Empiezo a capturar
reloj.Start(); // Inicio la captura
}
catch (Exception e)
{
MessageBox.Show("No se puede Iniciar la WebCam", "Error");
}
}
/// <summary>
/// Detiene la captura de imágenes y apaga la WebCam
/// </summary>
public void StopCaptura()
{
try
{
reloj.Stop(); // Paro el reloj que captura
SendMessage(CamHandle, WM_CAP_DISCONNECT, 0, 0); // Apago la cam
EmptyClipboard(); // Vacío el portapapeles
}
catch (Exception e) { } // No hago nada.. pa k ?
}
/// <summary>
/// Muestra diferentes parametros configurables de la imagen que se va a guardar
/// </summary>
public void GuardarImagen()
{
SaveImage s = new SaveImage(Pbx.Image, true); // Creo la clase que guarda las fotos
}
}
}
}