IV – Instalador para PreviewHandler de imágenes/texto (Inno Setup)
Continuando con las entradas anteriores, en esta última vamos a crear una extensión para visualizar los tipos de imágenes más habituales y usados en Windows. Además vamos a «redistribuir» un poco nuestro esqueleto inicial para reorganizar las clases (tal y como comentamos en entradas anteriores); Y finalmente vamos a crear un instalador para poder ofrecer esta extensión de una forma más profesional.
Os adjunto los links de todas las entradas de esta serie, como he hecho en las anteriores:
- Crear una Previsualización de ficheros en Windows
- «Registros» de una DLL de previsualización
- Generando previsualización funcional (PreviewHandler)
- Instalador para PreviewHandler de imágenes/texto (Inno Setup)
.
Contenido
INTRODUCCION
Con todo los visto hasta ahora en las entradas anteriores, vamos a crear una DLL para imágenes de diferentes formatos, modificando un poco el esqueleto del proyecto que teníamos hasta ahora.
Vamos a tratar las extensiones más comunes con las que trabajamos: bmp, jpg, jpeg, png, gif, ico, wmf, emf, tif, tiff
Además vamos a generar un instalador con Inno Setup que instale (y desinstale cuando sea necesario) nuestra DLL de previsualización. Inno Setup, para los que no lo conozcáis, es un generador de instalaciones para Windows muy potente y totalmente gratuito. En otras ocasiones ya he hablado de él, y a día de hoy es un estándar en generar programas de instalación.
Además de ser sencillo de utilizar, hay multitud de scripts predefinidos y de ejemplo por la web, que podéis utilizar, modificar y adaptar a vuestras necesidades. Para lo que necesitamos nosotros veréis que es sumamente sencillo y fácil.
.
MODIFICACIONES A NUESTRO ESQUELETO
Lo primero que vamos a hacer con nuestra DLL, es reestructurar nuestra clases para organizarlas de una manera más lógica (utilizando herencia).
Vamos a dejar tanto la clase TBaseShellExt como el formulario TFormPreviewBase, como clases abstractas a partir de las cuales vamos a derivar otras para generar clases funcionales.
De esta forma, la herencia para el Handler y para el formulario de visualización quedan como se ve en la imagen de la derecha.
La interfaz del handler ahora queda de esta forma (con la herencia vista anteriormente):
TBaseShellExt = class abstract(TComObject, IPreviewHandler) private // Permite cargar datos desde el origen especificado en una llamada de método Initialize // anterior y para comenzar la representación en la ventana del controlador de vista previa function DoPreview: HRESULT; stdcall; // Permite devolver el HWND desde una llamada a la función GetFocus. function QueryFocus(var phwnd: HWND): HRESULT; stdcall; // Permite establecer el foco en sí mismo. function SetFocus: HRESULT; stdcall; // Permite cambiar el área dentro del hwnd primario en el que se dibuja. function SetRect(var prc: TRect): HRESULT; stdcall; // Establece la ventana primaria de la ventana del previsualizador, así como el área // dentro del elemento primario que se va a usar para la ventana del previsualizador. function SetWindow(hwnd: HWND; var prc: TRect): HRESULT; stdcall; // Permite controlar una pulsación de tecla pasada desde la bomba de mensajes del proceso // en el que se ejecuta el controlador de vista previa function TranslateAccelerator(var pmsg: tagMSG): HRESULT; stdcall; // Permite dejar de representar una vista previa y liberar todos los recursos asignados // en función del elemento pasado durante la inicialización function Unload: HRESULT; stdcall; private FParent: HWND; // Handle de la ventana de previsualizacion FBounds: TRect; // Define el area de la previsualizacion protected FormPreview: TFormPreviewBase; // formuario de previsualizacion // Procedimiento que realmente realiza la previsualizacion procedure InternalDoPreview; virtual; procedure AfterDoPreview; virtual; // testear la ventana de previsualizacion procedure TestPreviewWindows; // Devuelve la clase contructora del formulario de visualización (a redefinir en los derivados) class function FormPreviewClass:TFormPreviewClass; virtual; abstract; public destructor Destroy; override; end; TFileShellExt = class(TBaseShellExt, IInitializeWithFile) // clase con inicializacion por fichero strict private function IInitializeWithFile.Initialize = IInitializeWithFile_Init; private FFilePath: string; // Inicialización para ficheros function IInitializeWithFile_Init(pszFilePath: LPCWSTR; grfMode: DWORD): HRESULT; stdcall; protected // Procedimiento que realmente realiza la previsualizacion procedure InternalDoPreview; override; public property FilePath:string read FFilePath write FFilePath; end; TStreamShellExt = class(TBaseShellExt, IInitializeWithStream) // clase con inicilizacion por stream strict private function IInitializeWithStream.Initialize = IInitializeWithStream_Init; private FStream:IStream; // Inicilización para stream function IInitializeWithStream_Init(const pstream: IStream; grfMode: DWORD): HRESULT; stdcall; protected // Procedimiento que realmente realiza la previsualizacion procedure InternalDoPreview; override; end; TImageShellExt = class(TFileShellExt) protected // Procedimiento que realmente realiza la previsualizacion para imagenes procedure InternalDoPreview; override; class function FormPreviewClass:TFormPreviewClass; override; end; |
Al final de la entrada os pongo todo el proyecto para descargar.
.
VISUALIZACION DE IMAGENES
Si nos centramos ahora en el formulario de visualización, vamos a utilizar en este caso la inicialización por fichero (a partir del path), ya que si necesitamos conocer el tipo del fichero, será más sencillo hacerlo a partir de su extensión (y dado que diferentes tipos de imagen pueden requerir diferente código para cargarse).
En Delphi es bastante sencillo el código, en realidad basta con unas pocas líneas:
procedure TFormPreviewImage.DoPreviewEXT(const AFileName: TFileName); begin inherited; Extension := AnsiReplaceText(AnsiString(ExtractFileExt(AFileName)), '.', string.Empty); // cargar la imagen de disco img.Picture.LoadFromFile(AFileName); end; |
// Refrescar la información de la imagen en pantalla procedure TFormPreviewImage.RefreshInfo; begin inherited; pnlTamaño.Caption := img.Picture.Width.ToString + 'x' + img.Picture.Height.ToString; pnlTamaño.Invalidate; end; |
Además extraemos la extensión y las dimensiones de la imagen para mostrarlas en la pantalla.
Una posible ampliación puede ser la de cargar imágenes que por defecto no carga la VCL, como pueden ser SVG, WBMP, Webp,… A ver si alguien se anima y ampliamos la DLL.
.
INSTALADOR CON «INNO SETUP»
Por último vamos a crear una instalación para nuestra librería. Para ello vamos a utilizar Inno Setup.
Para los que no lo hayáis utilizado, Inno es un generador de instalaciones gratuito y muy potente, que nos ofrece todo los necesario para generar un instalador.
Se basa en un Script de texto, y aunque hay utilidades de terceros muy interesantes como «Inno Script Studio» , también gratuito, que nos permite de forma visual configurar la infinidad de opciones del instalador, veréis que para algo básico como lo que necesitamos nosotros no son necesarias.
Un script básico que ya funciona para generar el instalador de nuestra DLL es el siguiente:
; Script generated by the Inno Script Studio Wizard. ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! ; SECCION-1 --------------------------------------------------------------- #define MyAppName "Controlador de vista previa para ficheros de Imagen" #define MyAppVersion "1.5" #define MyAppPublisher "Germán Estévez -Neftalí-" #define MyAppURL "https://neftali.clubdelphi.com" ; SECCION-2 --------------------------------------------------------------- [Setup] ; NOTE: The value of AppId uniquely identifies this application. ; Do not use the same AppId value in installers for other applications. ; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) AppId={{87E9F1B0-A979-4DB1-B63B-AB50AA5FE290} AppName={#MyAppName} AppVersion={#MyAppVersion} ;AppVerName={#MyAppName} {#MyAppVersion} AppPublisher={#MyAppPublisher} AppPublisherURL={#MyAppURL} AppSupportURL={#MyAppURL} AppUpdatesURL={#MyAppURL} DefaultDirName={pf}\ShellPreviewExtFiles DisableDirPage=yes DefaultGroupName=ShellPreviewExtFiles DisableProgramGroupPage=yes LicenseFile=..\Install\License.txt OutputBaseFilename=Instalar Compression=lzma SolidCompression=yes ; SECCICON-3 --------------------------------------------------------------- [Languages] Name: "spanish"; MessagesFile: "compiler:Languages\Spanish.isl" Name: "catalan"; MessagesFile: "compiler:Languages\Catalan.isl" Name: "english"; MessagesFile: "compiler:Default.isl" ; SECCION-4 --------------------------------------------------------------- [Files] Source: "..\ShellPreviewImagesFiles.dll"; DestDir: "{app}"; Flags: ignoreversion 32bit regserver; Languages: catalan english spanish ; Fichero de licencia Source: ".\License.txt"; DestDir: "{app}"; Flags: ignoreversion; Source: ".\Readme.txt"; DestDir: "{app}"; Flags: ignoreversion;
Os he marcado con comentarios (;————-…) las diferentes secciones del script, para poder identificarlas, aunque los nombres son bastante descriptivos.
- SECCION-1: Constantes básicas para el instalador, que se usan más adelante en el script.
- SECCION-2: Variables necesarias para el asistente de instalación (nombre, descripción, versión, directorio de instalación,…)
- SECCION-3: Lenguajes en los que deseamos mostrar el instalador; El primero será el de la pantalla inicial que permitirá al usuario cambiarlo.
- SECCION-4: Lista de ficheros a instalar con sus diferentes opciones. Importante en nuestro caso indicar el flag regserver, para nuestra DLL. Eso hará que el instalador de forma automática la registre (regsvr32) y la desregistre cuando hagamos la desinstalación.
Tal vez lo veáis muy complejo, pero no os preocupéis no debéis escribir este script «a mano». Este script ya lo genera «Inno Script Studio» que mediante un asistente nos va solicitando los datos básicos. Lo podéis ver en las imágenes siguientes.
NOTA: Tengo el asistente en inglés (en las imágenes), pero podéis ponerlo en varios idiomas.
Os adjunto al final de la entrada los diferentes ZIPs para que podáis probar.
- Código fuente del proyecto (incluye fuentes, script inno, imágenes de ejemplo,…)
- Fichero [instalar.exe] ya compilado, listo para instalar.
Si lo instaláis (ya sea compilando la DLL y generando el proyecto de Inno, o utilizando el instalador) veréis que se genera una carpeta con todo lo necesario en:
c:\Program Files (x86)\ShellPreviewExtFiles\
Os adjunto ficheros para descarga:
Aquí tenéis el enlace a Github donde he subido todos los ficheros de las diferentes entradas, organizados por las diferentes versiones por si en algún momento no están accesibles aquí
Os dejo también un video corto donde podáis ver cómo funciona esta última versión programada y ver en funcionamiento el instalador de Inno Setup.
Y hasta aquí lo que tengo previsto de esta serie, aunque no descarto ampliarla con algunas cosas más que me rondan por la cabeza.
.
LINKS DE INTERÉS…
Algunos links ya los he puesto en las entradas anteriores, pero no las referencias a otras webs o blogs donde podéis encontrar información al respecto a modo de bibliografía. Sí he puesto enlaces a la documentación de la MSDN, pero me he dejado algunos. A provecho esta sección para recopilarlos:
- En el blog de Rodrigo Ruz podéis encontrar código al respecto de los «Preview handlers» y una fantástica extensión para visualizar ficheros de código fuente. Diferentes lenguajes de programación. En GitHub tenéis código fuente si queréis revisar y aprender.
- En el blog de «The Art of delphi programming» de Uwe Raabe, podéis encontrar una entrada sobre Previews para Windows 7, con código fuente disponible muy interesante.
- En este blog de Brad Smith también podéis encontrar sobre el tema.
- El resto de información está en la MSDN y podéis encontrarla a partir de este link.
Como siempre espero vuestros comentarios, preguntas, sugerencias, críticas,…
Embarcadero MVP.
Analista y Programador de Sistemas Informáticos.
Estudios de Informática (Ingeniería Técnica Superior) en la UPC (Universidad Politécnica de Barcelona).
Llevo utilizando Delphi desde su versión 3. Especialista en diseño de componentes, Bases de Datos, Frameworks de Persistencia, Integración Continua, Desarrollo móvil,…