Aquí tienes numerosos artículos de Delphi, espero que te gusten y sean de tu agrado. Selecciona el articulo que quieres leer.
| Ficheros INI |
| Introducción |
Voy a contar como Delphi gestiona los ficheros ini. Por fichero ini se entiende todo fichero que tiene extensión ini, está en formato Ascii, y tiene una estructura interna dividida en secciones. Un claro ejemplo es el famoso Win.ini, que lo podéis encontrar en el directorio Windows. Se puede abrir con el Bloc de Notas de Windows, aunque Windows, incluye un programa visor para ver los ficheros del sistema, que se llama Sysedit, si ejecutáis este programa podréis ver el contenido de los ficheros de sistema, entre ellos los de extensión ini.
Los ficheros ini, normalmente, tienen una estructura. Están divididos en bloques o secciones, y dentro de cada sección hay valores que se usan en la configuración del programa que gestiona ese fichero o esa sección. Digo esa sección porque el fichero Win.ini almacena datos sobre Windows, y algunos programas añaden secciones a él. Aquí hay que hacer una aclaración ya que esto solo ocurre en Windows 3.x, y Windows 95 tiene este archivo aunque esta en desuso (por compatibilidad).
Los nombres de las secciones están indicados entre corchetes, e inmediatamente van los variables que haya puesto el programa con sus valores. Este es un ejemplo de una entrada de mi fichero Win.ini:
[Ports]
LPT1:=
LPT2:=
LPT3:=
COM1:=9600,n,8,1,x
COM2:=9600,n,8,1,x
COM3:=9600,n,8,1,x
COM4:=9600,n,8,1,x
FILE:=
Como podéis ver es todo Ascii, así que alguien puede pensar que con lo que
sabe de ficheros, se puede sentar delante del ordenador y hacerse unas rutinas
para leerlos, a lo cual yo respondo que tu mismo, pero que Delphi ya tiene un
sistema para leerlos, y muy bueno.
Delphi tiene una unidad donde tiene todos los procedimientos y funciones definidos. Así que lo único que tienes que hacer para poder empezar a trabajar con estos ficheros es añadir la palabra IniFiles a la cláusula uses de tu unidad. Esta es la lista de funciones y procedimientos para leer y escribir en estos ficheros.
|
Create(Filename) |
Para acceder a un fichero |
|
Free |
Cierra el fichero |
|
ReadSecctionValues(Seccion,TString) |
Para leer todas la variables |
|
ReadSections(TString) |
Lee las secciones |
|
ReadSection(Seccion,TString) |
Lee una Seccion entera |
|
ReadString(Seccion,Variable, Defecto) |
Lee una variable tipo String |
|
ReadInteger(Seccion,Variable,Defecto) |
Lee una variable tipo integer |
|
ReadBool(Seccion,Variable,Defecto) |
Lee una variable tipo boleano |
|
WriteString(Seccion,Variable,Valor) |
Escribe un valor en una Variable. |
|
WriteInteger(Seccion,Variable,Valor) |
Escribe un valor tipo Integer |
|
WriteBool(Seccion,Variable,Valor) |
Escribe un valor boleano |
Quizás ante tanto nombre os asustéis, pero en cuanto explique un par de detalles el resto será coser un cantar. Para acceder a un fichero ini, lo primero es indicar que fichero es, y eso se hace cuando creamos el objeto. He dicho objeto, y lo he soltado así de refilón, resulta que como Delphi es un lenguaje orientado al objeto, y el sistema de lectura/escritura de ficheros ini, es una clase pues hay que inicializarlo. Seguro que hay alguno de esta pensando que se ha metido en un lió, pero Delphi no nos abandona en los momentos difíciles, y el sistema es muy fácil. Un procedimiento genérico (cuando digo genérico es que se puede poner dentro de cualquier procedimiento) seria como sigue:
Var
MiFicheroIni : TiniFile;
Begin
MiFicheroIni := TIniFile.Create ('pepe.ini');
MiFicheroIni.Free;
En este mini programa lo que he hecho crear una variable tipo IniFile, la cual
inicializo en la primera línea indicando que el fichero con el cual vamos a
trabajar se llama Pepe.ini, después podría hacer lo que me plazca, y al final
libero la variable que he creado, para que no ocupe memoria. Atención porque
sino se indica el nombre del fichero con la ruta completa se asume que este está
en el directorio Windows, y NO donde se esta ejecutando tu programa. Si quieres
acceder al fichero dentro de otro directorio, debes ponerlo así:
MificheroIni := TiniFile.Create ('c:\mi
directorio\pepe.ini');
Os comento que los ejemplo que voy a poner trabajarán en el directorio donde se
ejecuta la aplicación. Antes de que se me pase, cuando el fichero no se
encuentra este es creado.
Vamos hacer un ejemplo donde se usen las principales funciones. Para lo cual construye un formulario como este, con dos botones, dos campos edit, un CheckBox, y un par de etiquetas. Como os dije, el fichero se creará en el directorio donde se ejecuta este programa, así que para ello debemos saber donde se ejecuta, la manera que yo he usado es declarar un variable en la sección privada de la unidad, la cual contendrá el directorio y el nombre del fichero, y estos datos le serán asignados en el momento de la creación del formulario, así que este procedimiento será como sigue:
procedure TForm1.FormCreate(Sender: TObject);
begin
Fichero := ExtractFileDir (ParamStr(0))+'\Fichero.ini';
end;
El truco para saber el directorio donde está ejecutandose el programa, está
en ParamStr, el cual contiene en su elemento 0 (es un array), el nombre con la
ruta completa del programa. Con la función ExtractFileDir obtengo solo la ruta.
El LeerDatos, que se llama
Button1, tiene las siguientes líneas de código:
procedure
TForm1.Button1Click(Sender: TObject);
Var
MiFichero : TIniFile;
Edad : Integer;
begin
MiFichero := TiniFile.Create (Fichero);
Edit1.Text := MiFichero.ReadString ('Usuario','Nombre','Desconocido');
Edad := MiFichero.ReadInteger ('Usuario','Edad',99);
CheckBox1.Checked := MiFichero.ReadBool ('Usuario','Español',True);
MiFichero.Free;
Edit2.Text := IntToStr (Edad);
end;
Las funciones de lectura de datos devuelven los valores en el formato que los leen. Así cuando usamos ReadString la variable que recoge los datos debe ser un String, cae de cajón, pero por si las moscas. Además tienen tres parametros, el primero es el nombre de la sección, el segundo el nombre de la variable, y el tercero el valor por defecto, en el caso que no exista tal variable, sección, o incluso si el fichero no existiese y fuera creado en el momento de su apertura. Como la edad he decido almacenarla como un valor numérico (integer), para poderla mostrarla en el campo Edit2 he de convertirla a texto, que es lo que hace la última línea.
El procedimiento de escritura es similar:
procedure TForm1.Button2Click(Sender: TObject);
Var
MiFichero : TIniFile;
Edad : Integer;
begin
Edad := StrToInt (Edit2.Text);
MiFichero := TiniFile.Create (Fichero);
MiFichero.WriteString ('Usuario','Nombre',Edit1.Text);
MiFichero.WriteInteger ('Usuario','Edad',Edad);
MiFichero.WriteBool ('Usuario','Español',CheckBox1.Checked);
MiFichero.Free;
end;
Fijaros que el procedimiento es casi indentico al anterior, pero esta vez se
usan las ordenes de escritura. Aqui ocurre lo mismo, si el fichero, la seccion,
o la variable no existen son creadas. Como regla general se puede decir que si
al leer o escribir algo no existe, este es creado.
He dejado atrás funciones que son: ReadSectionValues, ReaSections y ReadSection, las cuales tienen como parametros variables de tipo TStrings, las cuales más que ser una variable es un objeto, el cual no esta de más que vallas tratando porque es muy potente. Básicamente es una lista de cadenas, algo así como un Array o Matriz, pero se pueden hacer muchas cosas con el, añadir elementos, borrarlos, acceder por el indice, ordenarlos, etc. Y lo mejor es que los componentes que usan esten objeto lo hacen practicamente todo ellos. Un componente que usa este objeto son los TListBox, es el séptimo componente empezando por la derecha en la paleta Standar.
Estas funciones leen partes de un fichero ini. Así ReadSectionValues, lee los
valores de las variables contenidas en una seccion. ReadSections, lee el nombre
de las secciones de un fichero ini, y ReadSection lee el nombre de las variables
de la sección. He hecho un pequeño ejemplo que lee de nuestro fichero ini.
He puesto en un formulario tres botones que invocan a estos tres procedimientos y un TListBox, el cual su propiedad items, es del tipo TStrings. Esta es la imagen del formulario que preparé y los tres procedimientos.
procedure TForm1.Button1Click(Sender: TObject);
Var
MiFichero : TiniFile;
begin
MiFichero := TIniFile.Create (Fichero);
MiFichero.ReadSection ('Usuario',ListBox1.Items);
MiFichero.Free;
end;
procedure TForm1.Button2Click(Sender: TObject);
Var
MiFichero : TiniFile;
begin
MiFichero := TIniFile.Create (Fichero);
MiFichero.ReadSections (ListBox1.Items);
MiFichero.Free;
end;
procedure TForm1.Button3Click(Sender: TObject);
Var
MiFichero : TiniFile;
begin
MiFichero := TIniFile.Create (Fichero);
MiFichero.ReadSectionValues ('Usuario',ListBox1.Items);
MiFichero.Free;
end;
Bueno pues los ficheros ini no tienen más secretos, solo comentar que yo personalmente prefiero trabajar sobre un fichero ini propio que tocar en el win.ini. El motivo es que así el fichero ini lo creo en el directorio donde esta el programa ejecutable, con lo que obtengo una ventaja, y es que es que si el usuario borra el programa, borrando el directorio donde está el programa ya borra el fichero ini, y no se queda en el directorio Windows y si hubiera añadido entradas al fichero win.ini este no quedaria engordado inultilmente.
| Introducción |
Las aplicaciones que implementan capacidades de lenguajes macro o lenguajes interpretados en tiempo de ejecución, suministran una funcionalidad extraordinaria a los usuarios. Un ejemplo muy conocido es el editor de documentos Microsoft Word.
Este artículo muestra una forma de incorporar lenguajes interpretados en tiempo de ejecución a las aplicaciones, mediante la tecnología ActiveX Script de Microsoft, utilizando como plataforma de construcción a Delphi versión 3 o posterior.
ActiveX Script es una especificación de interfaces de objetos COM (Common Object Model), que posibilitan a los desarrolladores, incorporar en sus aplicaciones los motores de ejecución de lenguajes interpretados de una manera fácil.
Por desarrolladores en este trabajo, entenderemos las empresas o personas cuyo producto es un programa o paquete especifico, por ejemplo un editor de texto, un sistema financiero contable, un navegador de Internet, etc, para distinguirlo de aquel que se especializa en desarrollar motores o maquinas interpretación de guiones de ejecución, que llamaremos proveedor.
La definición del lenguaje del guión de ejecución (el script en si mismo), la sintaxis, el formato de almacenamiento, el modelo de ejecución y otras temas relacionadas, son responsabilidad de los proveedores de motores ActiveX Script. El hospedar o soportar un motor de interprete de guiones de ejecución, es responsabilidad del desarrollador de la aplicacion.
El guión de ejecución (el script) en general es un texto, escrito con las reglas del lenguaje que soporta el motor en el cual se ejecuta.
| Los pasos básicos |
Las componentes de ActiveX Script caen en dos categorías: Los hospederos (HOST) de guiones de ejecución y los motores de interpretación (SCRIPT ENGINE).
Los hospederos son las aplicaciones que crean los guiones y llaman al motor de interpretación adecuado para ejecutar el guión. Un ejemplo de aplicación hospedera es el Microsoft Internet Explorer, tan utilizado para navegar por las páginas WEB.
Los motores de interpretación se pueden desarrollar para cualquier lenguaje y ambiente de ejecución, por ejemplo el Microsoft Visual Basic Scripting Edition (VBScript), utilizado en el Microsoft Internet Explorer.
Los pasos involucrados en la secuencia básica para la ejecución de un guión es la siguiente (algunos elementos utilizados de momento, serán explicados mas adelante):
| El hospedero |
La aplicación (hospedero) que soporte guiones de ejecución ActiveX Script tiene que contener al menos una instancia de un objeto que exponga la interfaz IActiveScriptSite. Este objeto, es el punto de interacción del hospedero con el motor de interpretación. Usualmente este objeto es el contenedor de todos los otros objetos que son visibles para el guión que ejecuta el hospedero. La figura 1 muestra el código pascal de definición de dicha interfaz.
A continuación veamos una breve descripción de cada uno de los miembros de la interfaz IActiveScriptSite
| GetLCID | Esta función permite al hospedero indicar las constantes de localización para la interacción del motor de interpretación y el usuario de la aplicación. |
| GetItemInfo | Esta función es llamada por el motor de interpretación para buscar los objetos nominalizados dentro de la aplicación. |
| GetDocVersionString | Esta función es llamada por el motor de interpretación para obtener una el número de versión textualizado del documento vigente. Esta cadena puede ser usada para validar que cualquier estado congelado en el motor de ejecución pueda ser salvado consistentemente en el documento vigente. |
| OnScriptTerminate | Esta función es llamada cuando el motor de interpretación términa. En muchos motores, esta función no es llamada y es posible utilizar el guión interpretado para generar eventos en la aplicación hospedera |
| OnStateChange | Esta función es llamada cuando el motor de intérprete cambia de estado tanto explicitamente mediante la función SetScriptState o implícitamente por los eventos que se generan en el guión de ejecución. |
| OnScriptError | Esta función es llamada cuando durante el análisis sintáctico del guión o durante la ejecución del mismo, se encuentra un error. El motor de interpretación suministra una implementación de la interfaz IActiveScriptError que describe el error en tiempo de ejecución en términos de una estructura EXCEPINFO, en adición a la indicación de la localización del error en el texto original del guión. |
| OnEnterScript | Esta función es llamada por el motor de ejecución para indicar el comienzo de una unidad de trabajo. |
| OnLeaveScript | Esta función es llamada por el motor de ejecución para indicar la terminacion de una unidad de trabajo. |
|
||
|
||
|
end; |
figura 1. Definición de la interfaz IActiveScriptSite
| El motor de interpretación |
El motor de interpretación ActiveX Script, tiene que implementar la interfaz IActiveScript. Cuando el hospedero crea una instancia del motor de interpretación, llama a la función SetScriptSite de esta interfaz, para establecer el puente de interacción hospedero-motor de interpretación.
A continuación veamos una breve descripción de cada uno de los miembros de la interfaz IActiveScript
| SetScriptSite | Informa al motor de lenguaje del objeto establecido en el hospedero que expone la interfaz IActiveScriptSite |
| GetScriptSite | Puede ser llamada para obtener el hospedero del motor de interpretación |
| SetScriptState | Pone el motor de interpretación en un estado dado |
| GetScriptState | Obtiene el estado del motor de interpretación |
| Close | Causa que el motor de interpretación abandone cualquier guión cargado, pierda el estado en que se encuentra, librere los objetos internos y punteros a las interfaces de otros objetos y entre en el estado closed |
| AddNamedItem | Adiciona un nombre en el nivel primario del espacio nominal del motor de interpretación |
| AddTypedLib | Adiciona una librería de tipo en el espacio nominal del motor de interpretación |
| GetScriptDispath | Obtiene un puntero a la interfaz IDispatch para los métodos y propiedades asociadas con el guión que se está ejecutando |
| GetCurrentScriptThread | Obtiene el identificador definido del motor de interpretación para el hilo de ejecución (thread) vigente |
| GetScriptThreadID | Obtiene el identificador de hilo de ejecución (thread) asociado en el motor de interpretación asociado con el hilo de ejecución dado en Microsoft WIN32 |
| GetScriptThreadState | Obtiene el estado vigente en el hilo de ejecución (thread) del guión |
| InterrupScriptThread | Interrumpe la ejecución del guión que se esta ejecutando |
| Clone | Sintetiza una copia gemela del motor de interpretación (excepto cualquier estado de ejecución), retornando una nueva instancia del motor de interpretación cargado sin asociación al hospedero en el hilo de ejecución vigente (thread) |
El motor de interpretación permite controlar la funcionalidad básica de la ejecucion del guion; pero si soporta guiones textuales y evaluación de expresiones textuales compatibles con el lenguaje, entonces tiene que implementar la interfaz IActiveScriptParse.
La interfaz IActiveScriptParse constituye el analizador sintáctico del lenguaje interpretado y el ejecutor de las instrucciones del guión del motor de interpretación. El puntero a esta interfaz se obtiene llamando el metodo QueryInterface de IActiveScript. Los miembros fundamentales de la misma son:
| InitNew | Inicializa el motor de interpretacion |
| AddScriptlet | Adiciona un fragmento de codigo a un guion |
| ParseScriptText | Efectúa el analisis sintactico de un guion, adicionando las declaraciones dentro del espacion nominal del motor y evaluando apropiadamente el codigo |
La función ParseScriptText ejecuta el analisis sintáctico de acuerdo a las banderas de control que se establezcan en su llamada. Esta función tiene la siguiente sinopsis:
| HRESULT ParseScriptText ( |
| LPCOLESTR pstrCode, // Buffer con el texto del guion | |
| LPCOLESTR pstrItemName, // Nombre de item que suministra el contexto | |
| IUnknown* punkContext, // Contexto de depuracion | |
| LPCOLESTR pstrEndDelimiter, // Delimitador de fin del guion | |
| DWORD dwFlags, // Banderas de control | |
| VARIANT* pvarResult, // Retorno de los resultados de la ejecucion | |
| EXCEPINFO* pexcepinfo); // Buffer para retornar los errores |
El parámetro dwFlags, determina el procesamiento y puede ser cualquiera o una combinacion de las siguientes constantes:
| SCRIPTTEXT_ISEXPRESSION Si la distinción entre una expresion computacional y una sentencia es importante pero sintacticamente ambigua en el lenguaje, esta bandera especifica si el texto debe ser interpretado como una expresion o como una lista de sentencias. Implicitamente se asume que son sentencias |
| SCRIPTTEXT_ISPERSISTENT Indica que el codigo adicionado durante la llamada a esta funcion debe ser salvado en el motor de interpretacion o si éste debe retornar a su condicion en el estado de inicializado |
| SCRIPTTEXT_ISVISIBLE Indica si el texto del guion debe ser visible (y por tanto, accesable por nombre) como un metodo global del espacio nominal del guion |
El parámetro pexcepinfo apunta a una estructura para recibir la informacion de excepcion, que llenada si la funcion ParseScriptText retorna el valor DISP_E_EXCEPTION.
| Aplicacion de ejemplo |
Se puede construir una aplicación rudimentaria que actúe de hospedero de los motores de interpretación. El código que acompaña este artículo, tienen las fuentes completas del ejemplo que explicamos a continuación. Para crear el hospedero, creemos una nueva aplicacion en Delphi. Incorporemos un componente Memo1 del tipo TMemo, para la edición de los guiones. Adicionemos un componente TMenu con al menos un elemento TMenuItem para ejecutar el guión editado asociado al siguiente codigo:
El código ha sido abundantemente comentado para permitir identificar claramente los pasos explicados para la implementación de la tecnología ActiveX Script en una aplicación.
Microsoft(r) Windows(r) Scripting Host es un hospedero de guiones de ejecución independiente del lenguaje para motores de interpretación ActiveX™ en plataformas Windows de 32 bits.
Las plataformas de Microsoft Windows(r) 98, Windows NT(r) Workstation versión 5.0 y Windows NT Server versión 5.0 soportan este hospedero de guiones de ejecución. La propia compañía ya ha incluído los motores Microsoft(r) Visual Basic(r) Scripting Edition (VBScript) y Microsoft(r) JScript™. Otras compañías de proporcionarán otros motores ActiveX™ para lenguajes como Perl, TCL, REXX, Python y otros.
Este hospedero presenta baja ocupación de memoria durante la ejecución directa de los guiones, las secuencias de comandos no necesitan estar incrustadas en un documento HTML y es ideal para implementar comandos no interactivos que realicen tareas administrativas y de inicio de sesiones.
Windows Scripting Host utiliza la extensión del archivo de comandos para determinar qué motor de secuencias de comandos debe utilizar. Como resultado, quien escribe secuencias de comandos no necesita obtener el ID de motor de secuencias de comandos. El hospedero mantiene por sí solo, una asignación de extensiones de secuencias de comandos con ID de los motores y utiliza el modelo de asociación de Windows para iniciar el motor apropiado para la secuencia de comandos dada.
Windows Scripting Host expone nueve objetos globales de los cuales sólo tres están disponibles para los guiones de ejecución. Estos son WScript, WshArguments y WshShell. Las propiedades y metodos de los mismos quedan fuera del alcance de este articulo. El lector interesado, puede encontrar la documentacion de referencia en la ayuda del Personal Web Server de Windows 98.
En Windows 98 puede correrse desde la consola un guión de ejecución con el utilitario CSCRIPT.EXE. En la carpeta SAMPLES\WHS dentro del directorio de instalación de Windows 98, encontrará el archivo SHOWVAR.VBS, que es un guión de ejecucion en VBScript. Revise su contenido con el utilitario NOTEPAD.EXE. Para correrlo, haga doble CLICK sobre el mismo o ejecute desde la opcion EJECUTAR del menú de inicio la siguiente linea de comando,
CSCRIPT SHOWVAR.VBS
Aplicaciones de Consola |
El ambiente de Delphi, está concebido fundamentalmente para desarrollar aplicaciones que soportan el ambiente gráfico de Windows de forma rápida, sin embargo, existe un conjunto de aplicaciones que no requieren de una interfaz gráfica que Delphi construye muy eficientemente también. En este artículo, vamos a examinar las aplicaciones de tipo consola, que son programas que se caracterizan por ser rápidos y el tamaño del ejecutable es pequeño.
Las aplicaciones de consola, son programas escritos sin hacer uso de una interfaz gráfica de usuario.
En Windows, las aplicaciones de consola se ejecutan en una ventana especial basada en texto, conocida como la ventana de consola, a través de la cual se realiza la interacción con la aplicación. Los dispositivos estandares de entrada y salida de texto, están automáticamente asociados a esta ventana de consola.
Delphi no crea una nueva forma cuando crea una aplicación de tipo consola. Los controles visuales de la VCL no son generalmente empleados en una aplicacion de tipo consola, sin embargo, pueden ser usados.
El progama más simple de una aplicación de tipo consola que usted puede compilar en Delphi y correr desde la línea de comando es el siguiente:
Program Consola
{$APPTYPE CONSOLE}
Begin
Write( 'Hola a todos' );
End.
|
La primera línea, declara el nombre del programa, que tiene que ser igual nombre del fichero en que se guarda la aplicación con extensión PAS. La directiva {$APPTYPE CONSOLE} instruye al compilador que construya una aplicación del tipo consola. Esta directiva, tiene sólo sentido para un programa y no debe se usada en una librería, package o unit. Debemos resaltar, que las aplicaciones de consola, son programas de 32 bits dentro del ambiente de Delphi.
El contenido de lo que hay que ejecutar dentro del programa, se enmarca entre el begin y end. En este ejemplo, el programa simplemente escribe una cadena al dispositivo estandard de salida (ie. el monitor de la computadora).
El procedimiento Write, está definido en la unidad SYSTEM y es implícitamente importada en todos los programas. En Delphi 4, el ejecutable de este programa compilado tendrá un tamaño de fichero de 15.5 Kb. Compárelo contra el tamaño del programa más simple que puede construirse, usando una interfaz gráfica.
Las aplicaciones de consola, pueden dividirse en varios ficheros. En este caso, utilizaremos la claúsula Uses para indicar los ficheros que se incluyen en la aplicación. También, podemos incorporar recursos, en particular, es útil adicionar recursos de versión. Esto se realiza adicionando la directiva {$R *.RES}.
Una forma alternativa y equivalente de indicar, dentro del ambiente de Delphi, que estamos compilando una aplicación de tipo consola, es con la opción Generate Console Application del LINKER. Personalmente preferimos, hacerlo explícitamente con la directiva antes señalada.
En la unidad SYSTEM, está declarada una variable lógica, IsConsole, que puede ser usada para examinar en tiempo de ejecución, si el programa que está corriendo es una consola o tiene interfaz gráfica y tomar las acciones correspondientes.
El tamaño pequeño de las aplicaciones consola, está vinculado a no usar la unidad Forms. Si en el ejemplo inicial, adicionaramos la línea,
Uses Forms;
el tamaño del ejecutable generado, cambiaría a 271 Kb. O sea, la aplicación incrementa el tamaño del ejecutable en más de 17 veces. El único argumento, por el cual desearíamos adicionar la unit Forms a una aplicación de consola, sería para proporcionar acceso a la variable Application, que es una instancia del objeto TApplication. Así que, no incluya la unit Forms en sus aplicaciones de tipo consola.
Para acceder a la cola del comando, cuando se invoca una aplicación, podemos hacer uso de las funciones ParamCount y ParamStr.
La ParamCount, retorna el número de parámetros pasados a la aplicación en la cola del comando. Por su parte, ParamStr(n) retorna la n-ésima cadena de la cola del comando. ParamStr(0) siempre retorna el nombre de la aplicación con el camino completo desde la carpeta en que reside. Si el valor de n que se suministra es mayor que el valor retornado por ParamCount, entonces tendremos una cadena vacía.
Adicionalmente, la unidad System, suministra un conjunto de variables públicas muy útiles, que son inicializadas cuando se carga la misma y el conjunto de funciones básicas requeridas en cualquier aplicación: manipulación de cadenas, acceso a ficheros, operaciones con variants y manejo de memoria. Recomendamos que eche un vistazo a esta unidad.
Vamos a ver ahora, a través de un ejemplo sensillo, cómo una aplicación con interfaz grafica de windows interactúa con una aplicación de consola.
Esta aplicación muestra en su interfaz un botón para lanzar la aplicación de consola, una caja de edición para establecer los parámetros del comando de consola que se va a invocar y un control MEMO para mostrar el resultado.
La aplicación de consola es muy sencilla. Simplemente realiza la suma de dos números suministrados en la cola de comando y escribe el resultado.
El esquema funcional de interacción de ambas aplicaciones es el siguiente:
Asociado al botón de lanzar de la aplicación MiGUI se tiene el siguiente código, que ha sido abundantemente comentado para facilitar su comprensión:
procedure TForm2.Button1Click(Sender: TObject);
const
BufSize = $4000;
var
si : TStartupInfo;
pi : TProcessInformation;
ec, attr, BytesRead : DWORD;
WriteHandle, ReadHandle : THandle;
ConsoleOut : string;
procedure TerminarConsola;
begin
Button1.Enabled := True;
CloseHandle( ReadHandle ); // Cerrar los handles del pipe
CloseHandle( WriteHandle );
end;
begin
// Creamos un pipe anonimo cuyo extremo de escritura vamos a
// utilizar como dispositivo de salida del proceso de consola
// que se va a lanzar. El buffer del pipe tiene que ser suficientemente
// grande como contener la salida del proceso de consola.
if not CreatePipe(ReadHandle, WriteHandle, nil, BufSize) then Exit;
// Inicializar la estructura de informacion de arranque del proceso
FillChar(si, SizeOf( TStartupInfo ), 0);
si.cb := SizeOf( TStartupInfo );
// Establecemos los dispositivos de salida y error de proceso de consola
si.hStdOutput := WriteHandle;
si.hStdError := WriteHandle;
// Establecer la prioridad del hilo de ejecucion de la aplicacion de consola
// Variantes: IDLE_PRIORITY_CLASS, HIGH_PRIORITY_CLASS, REALTIME_PRIORITY_CLASS
attr := DETACHED_PROCESS or NORMAL_PRIORITY_CLASS;
// Indicar que se atienda los valores pasados en el miembro wShowWindow y
// los handles suministrados en la estructura
si.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
// Indicar la forma en que se muestra la aplicacion lanzada
// Variantes: SW_SHOWNORMAL, SW_MAXIMIZE, SW_MINIMIZE
si.wShowWindow := SW_HIDE;
// La funcion CreateProcess, crea un nuevo proceso donde ejecuta el fichero
// ejecutable especificado.
ConsoleOut := Edit1.Text; // Ejecutable a lanzar
try
if not CreateProcess(nil, // lpApplicationName (nil para consolas)
PChar(ConsoleOut), // Ejecutable de consola y cola de comando
nil, // LPSECURITY_ATTRIBUTES
nil, // LPSECURITY_ATTRIBUTES
FALSE, // bInheritHandles
attr, // dwCreationFlags
nil, // lpEnvironment
nil, // lpCurrentDirectory
si, // lpStartupInfo
pi ) // lpProcessInformation
then // Si la aplicacion de consola no es lanzada, retornar
begin
TerminarConsola;
Exit;
end;
except
TerminarConsola;
Exit;
end;
// Evitar recurrencia al lanzar la aplicacion de consola
Button1.Enabled := False;
// Ciclo para esperar que la aplicacion de consola termine su trabajo
Repeat
if not GetExitCodeProcess(pi.hProcess, ec) then
begin
TerminarConsola;
Exit;
end;
Application.ProcessMessages;
Until (ec <> STILL_ACTIVE);
try
// Leer del pipe, la informacion escrita por la aplicacion de consola
SetLength(ConsoleOut, BufSize);
ReadFile( ReadHandle, ConsoleOut[1], BufSize, BytesRead, nil );
SetLength(ConsoleOut, BytesRead);
// Copiar al memo, el texto retornado por la aplicacion de consola
Memo1.Lines.Text := ConsoleOut;
finally
TerminarConsola;
end;
end;
|
El ejemplo es muy sencillo; pero permite imaginar su alcance. En primer lugar, la aplicación que sostiene la interfaz gráfica y la aplicación de consola, se ejecutan automáticamente en dos hilos de ejecución diferentes. En un ambiente multitarea y multihilo como Win32, se pueden establecer prioridades diferentes para cada aplicación. La aplicación de consola se ejecuta sin ser mostrada. Si ésta cae en un ciclo de ejecución prolongado, desde la aplicación con interfaz puede cancelarse la misma o inclusive ejecutar otras cosas.
Construya la aplicación MiGUI (las fuentes están construidas con Delphi 4) suministrada con este artículo y ejecute a través de ella, el siguiente ejemplo de aplicación de consola, que es parte del sistema operativo:
Interesante, ¿ Verdad ?
Asociación de ficheros a las aplicaciones que tu creas |
En el Explorador de Windows, cuando pinchamos con el botón derecho del ratón sobre un fichero con extensión BMP, automáticamente emerge un menú, en una de cuyas opciones encontraremos Abrir. Si seleccionamos esta opción, se abre la aplicación Paint mostrando la imagen contenida en el fichero para ser editada. Esta funcionalidad, se logra con la asociación de tipos de ficheros a las aplicaciones que son capaces de cargarlos para ejecutar algún trabajo con él.
La asociación de ficheros a una aplicación es conocida desde Windows 3.1, donde bastaba adicionar en la sección Extensions del fichero del sistema WIN.INI, la siguiente línea:
BMP=C:\WINDOWS\PAINT.EXE ^.BMP
Pero, en la plataforma Win32, el soporte de WIN.INI solamente es mantenido por compatibilidad con las versiones anteriores. En Windows 95, Windows 98, Windows 2000 y Windows NT, el registro de Windows es el repositorio donde se almacena la información de asociación de ficheros con una aplicación, ahora extendida con un modificador llamado verbo (verb), que califica la acción a ejecutar sobre el mismo.
El verbo indica la acción que la aplicación asociada debe realizar sobre el documento contenido en un fichero. Existen tres verbos clásicos: Open, utilizado para abrir y visualizar el documento, Edit utilizado para abrir el documento en modo de edición y Print, utilizada para mandar el documento a la impresora predeterminada en el sistema.
El procedimiento de asociar un tipo de fichero a una aplicación se realiza en dos pasos:
En lo adelante, supondremos que las operaciones con el registro de Windows, se realizan bajo al llave HKEY_CLASSES_ROOT
Para realizar el primer punto, debemos añadir una llave con el nombre de la extensión del fichero (incluyendo el punto precedente de la extensión), bajo la cual estableceremos una llave con el nombre default a la que asociaremos como valor el nombre de la clase de la aplicación. Usualmente, se utiliza como nombre de clase de una aplicación, el nombre de la misma, seguida de un punto y la palabra Document. Así, en el editor del registro de Windows, se vería:
Para registrar la clase de la aplicación, hay que crear una llave con MiApp.Document. Bajo esta llave, se especifican las acciones que se ejecutan desde el Shell de Windows, donde cada acción visible es una clave cuyo valor es la cadena del comando para ejecutar dicha acción. En el registro de Windows, debe quedar algo como esto,
En el ejemplo a continuación se muestra el código completo de una unit, que contiene el procedimiento RegisterAssociation, que le permite asociar un tipo de fichero a su aplicación, que adicionalmente incorpora el icono principal de la aplicación a las metáforas gráficas que son mostradas en el Explorador. Simplemente, incorpore la llamada a este procedimiento con cuanto tipo de fichero usted quiera asociar a su aplicación dentro del evento de CreateForm de la forma principal de su aplicación.
| Unit Associat; {******************************************************************************} Interface Uses Windows, Forms, Registry, SysUtils, Dialogs; procedure RegisterAssociation(const ext, Desc: string); {******************************************************************************} Implementation Const OPEN_CMD = '\Shell\Open\Command'; EDIT_CMD = '\Shell\Edit\Command'; ICON_OBJ = '\DefaultIcon'; {------------------------------------------------------------------------------- Registra la asociacion de ficheros de la aplicacion en WINDOWS. ej: Si los ficheros asociados a la aplicacion desde donde se llama esta funcion son de extension TIF, entonces se registran estos ficheros mediante la siguiente llamada RegisterAssociation( '.TIF', 'Archivo de imagen TIF' ); Importante: No olvidar el punto de las extensiones. -------------------------------------------------------------------------------} procedure RegisterAssociation(const ext, Desc: string); var Obj, pth : string; lng : Integer; begin with TRegistry.Create do try RootKey := HKEY_CLASSES_ROOT; with Application do begin lng := Length(ExtractFileName( ExeName )) - Length(ExtractFileExt( ExeName )); Obj := Copy(ExtractFileName( ExeName ), 0, lng) + '.Document'; end; pth := ext; if ext[1] <> '\' then begin if ext[1] <> '.' then pth := '\.' + ext else pth := '\' + ext; end else if ext[2] <> '.' then pth := '\.' + Copy(ext, 2, Length(ext) - 1) else pth := '\' + ext; if not KeyExists(pth) then begin if OpenKey(pth, True) then WriteString('', Obj); CloseKey; end; if not KeyExists(Obj) then begin if OpenKey(Obj, True) then begin WriteString('', Desc); CloseKey; end; if OpenKey(Obj + OPEN_CMD, True) then begin WriteString('', Application.ExeName + ' %1'); CloseKey; end; if OpenKey(Obj + ICON_OBJ, True) then begin WriteString('', Application.ExeName + ',1'); CloseKey; end; end; finally Free; end; end; End. |
EXE generado con Delphi ¿demasiado GRANDE ? |
Muchas veces puede suceder que a varios nos parezca demasiado grande el .EXE generado por Delphi, y realmente lo es. ¿Por qué ? ¿Cómo evitarlo ? Estas son algunas de las cosas que debemos tener en cuenta al desarrollar una aplicacion hecha en Delphi y queremos que funcionen con el máximo de optimización y eficiencia posibles.
Desde los antiguos programas de MS-DOS generados en Turbo Pascal ó C, a muchos de nosotros nos gustaban usar las famosas librerías TVision ó Turbo Power para darle belleza y colorido a nuestras aplicaciones. Esto por supuesto tenía el inconveniente de mientras más unidades (units) usábamos, mas grande se nos hacia el .EXE resultante.
Con la llegada de Windows al mercado, la programacion tradicional de MS-DOs quedó obsoleta y entró un nuevo modo de programar el cual abstraía mucho más a los usuarios de sus aplicaciones en general, se trataba del Sistema de manipulación de Mesjaes de Windows, en el que Windows es el que manda un mensaje a la aplicacion, la aplicación espera por ese mensaje y si lo conoce y tiene un manipulador de este mensaje, sencillamente le da respuesta. Con esta gran ventaja surgió adjunto el desarrollo de la Programación visual Orientado a Objetos que ya venía desde el Ms-DOS y surgieron las librerias de Windows llamadas API. Pero la API no era POO y tenía muchas dificultades al expresar cosas evidentes y muy sencillas, además del tiempo que el usuario gastaba en realizar una sencilla aplicación. Surgieron las MFC (Microsoft Fundation Class) que no son más que las mismas funciones de la API creadas por Microsoft pero ahora con POO y de Borland la VCL (Visual Component Library).
Por supuesto que a partir de ese momento todos los productos de Microsoft soportaban la API que era la librería que ya venía implicita en Windows. Por eso si se desarrolla una aplicacion con un producto de Microsoft, el EXE generado es relativamente más pequeño que si se hace con un producto Borland con la VCL, porque ya las DLLs de MFC están en Windows, mientras que la VCL no y hay que distribuirlas.
Como todos conocemos, Dephi es un compilador de código nativo, o sea, no nesesita ninguna DLL acompañada del .EXE para ejecutarse en una PC sacada de la caja.
Cuando instalamos Delphi, la primera vez que lo corremos el introduce dentro del .EXE las DLLs según las vaya usando. Usted toma ese .EXE y se va para cualquier lugar, lo corre y listo. Pero esto tiene el inconveniente que según se usen mas BPLs (Borland Package Library - Las DLLs de Borland) asi será mas grande el EXE resultante. La solución está en ir al menú Projects/Options/Packages, y poner el Check Box Build whot runtime Packages en TRUE. Esto hará que dentro del .EXE no se metan las BPLs, solo el código nesesario de nuestra aplicación. Los BPLs se distribuyen mediante una utilidad llamada Install shield que viene con Delphi y donde se le dice que BPL usará. Para saber las PBLs que usa nuestro proyecto basta con ir al menú Project/Information y allí veremos todas las BPLs que hay que poner en el Install Shield. Esto es una muy buena opción ya que si Ud. desarrolla varias aplicaciones en una misma PC, todas las aplicaciones usan una misma copia de las BPLs, ahorrando memoria, tiempo de instalación de Install Shield, porque el no sobreescribe la copia del BPL a menos que Ud diga lo contrario. De esta forma es más efectivo y beneficioso porque Build Whit runtime pachkages, como lo trae Delphi por defecto mete los BPLs dentro de nuestro EXE, cosa que no nos satisface.
Pero hay algo que quizás puede pasar inadvertido para algunos usuarios, sobre todo principiantes (a mi me pasó). Como todos sabemos, los componentes de la paleta de compoenetes de Delphi se agrupan en Páginas, c/u de estas páginas está asociada a un BPL en específico, por Ej: Standard - VCL40.BPL, adicional - VCLX40.BPL, Data Access y DataControls VCLDB40 y VCLDBX40.BPL respectivamente, QReport a QRP40.BPL y asi sucesivamente. Que quiere decir esto ?? Sencillo. Si usted usa un componente en Delphi, el le adciona a la clausula uses de la forma la unit a que pertenece el componente, por tanto si agrega un TTable agregará al uses DBTables si agrega un Navigator agregará un DB y usted estrá usando el VCLDB40 y VCLDBX40.BPL en su programa, porque el compilador se guia en as BPLs que uses por la unit en la cláusula uses. Pero cuando eliminamos un componete de nuestra forma, Delphi no le quita la unit de la cláusula uses, y entonces, aunque no tengamos una sola Tabla ó navigator en nuestra forma, si sus respectivas units están reflejadas en la forma, entonces el seguirá pidiendole las BPLs asociadas a estos compoenetes. Por tanto, es recomendable, cuando borremos algún componente si estamos seguros de que no usamos más esa unit para nada (Por eso Dephi no la borra del uses cuando borras un componente) que la ELIMINEMOS de la cláusula uses de nuestra forma. De cualquier manera, existe un componente en la Forma y usted borra su unit, el vuelve a agregarla al compilar. (Cada vez que compila chequea los componentes y las units de c/u de ellos).
Concluyendo:
Este es una de las posibles soluciones, hay para tratar de hacer nuestras aplicaciones eficientes y optimas, minimizando el tiempo de carga ejecucion y usando los recursos del sistema de forma más racional, ahorrando memoria (recuerden que al ejecutar un .EXE todo está en memoria), etc. También debemos optimizar internamente nuestro código y usar las facilidades que nos da el lenguaje Object - Pascal internamente y la POO.
Suerte...
La huella de los programadores |
(Nota: Los textos e ideas originales de esta exposición no son míos. En cada caso, se cita la fuente de donde extraje la información, que por curiosa, me pareció interesante hacerselas llegar)
Cuando se ejecuta un gran proyecto de software en un equipo, los programadores, gustan de dejar en el paquete alguna huella que revele su participación. Después de mostrar algunos ejemplos, vamos a relatar una técnica para lograr esto en nuestros proyectos en Delphi.
En el sitio www.ethek.com, podemos encontrar un reseña debida a Jesús Manuel Rodríguez, que nos explica la forma de ver los créditos del equipo de Windows 98.
Entonces, se abre la ventana que mientras carga otros recursos, muestra unos números en azul y luego los nombres y fotos del equipo de programación de Windows 98.
No es fácil lograr que se muestren los créditos del equipo de programación de Windows 98. Tendrá que intertarlo varias veces. Yo generalmente lo consigo a la tercera oportunidad. Bueno, lo que se muestra es una página WEB, que se abre temporalmente en el siguiente camino:
En el directorio SYSTEM, se encuentra una librería, MEMBG.DLL, que contiene los recursos mostrados en la página WEB, dinámicamente construida.
Otra forma alternativa de ver los nombres de los participantes en el proyecto Windows 98 es la siguiente.
Veamos ahora una propuesta de hacer algo como esto. Bajo el título "Implementing an Easter Egg", por colaboracion de Michael Burton, en el número 38 (Abril de 1999) de la páginas de UNDU, se suministra un código que al ocurrir una combinación de teclas poco usuales, se activa un diálogo que puede servir para mostrar los créditos de los participantes en la construcción de un proyecto en Delphi.
Aquí reproducimos el código suministrado en el artículo (traducción mediante).
1. En la forma en que se desee activar los créditos del equipo, establezca la propiedad KeyPreview en True. Esto permite a la forma tener la entrada de teclado antes que el control activo en la misma.
2. Crear dos variables privadas en la forma:
eeCount: integer;
sEgg: string;
La variable eeCount, cuenta los golpes de tecla para procesar la activación de los creditos de equipo. La variable sEgg contiene la secuencia de teclas entradas.
3. Crear dos constantes en la forma:
const
EE_CONTROL: TShiftState = [ssCtrl, ssAlt];
EASTER_EGG = 'RIMROCK';
EE_CONTROL contiene las teclas de control que deben estar oprimidas cuando el usuario quiere activar los créditos del equipo de programación. Pueden ser cualquier combinacion de ssCtrl, ssShift y ssALt, pero se debe usar cualquier combinacion que no interfiera con los controles en la forma.
4. En el evento OnCreate de la forma, hacer la siguiente inicialización:
eeCount := 1;
sEgg := EASTER_EGG;
5. En el evento OnKeyDown de la forma implemente el siguiente código:
procedure TForm.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
{are the proper control keys down?}
if Shift = EE_CONTROL then begin
{was the proper key pressed?}
if Key = Ord(sEGG[eeCount]) then begin
{was this the last keystroke in the sequence?}
if eeCount = Length(sEGG) then begin
{Easter egg activation code goes here, e.g.,}
ShowMessage('This is an easter egg');
eeCount := 1; {failure - reset the count}
end else begin
Inc(eeCount); {success - increment the count}
end;
end else begin
eeCount := 1; {failure - reset the count}
end;
end;
end;
Puede reemplazar la llamada a ShowMessage con lo que usted desee. Compile y pruebe.
Los programadores de Delphi, también han dejado sus huellas en los programas. Por ejemplo, en Delphi 1, si usted muestra la ventana de créditos (About box) y sosteniendo oprimidas las teclas Shift y Alt, teclea la palabra TEAM, veremos entonces los créditos de los programadores.
¿ Estará implementada esta curiosidad en las versiones posteriores, digamos en Delphi 3 o 4 ? Si usted lo conoce, hágamelo saber y muchas gracias por anticipado.
Aplicaciones con ayuda HTML compilada.Parte 1 |
Microsoft ha incorporado en su plataforma Windows, un nuevo tipo de ayuda, más en correspondencia con los desarrollos de Internet y nuevas formas de presentación y búsqueda de la información, que es la ayuda HTML compilada (HTML Help compiled).
Hay 2 razones por la que los desarrolladores tenemos que prestar atención a la ayuda HTML compilada.
Para ver los ficheros de ayuda HTML compilada, se requiere tener instalado los siguientes componentes:
| hh.exe | Visor de ficheros de ayuda compilada, que se instala en el directorio de WINDOWS. |
| hhCtrl.ocx | Motor de ejecución de la ayuda compilada, que se instala en el directorio SYSTEM. |
| itircl.dll | Librería utilizada en la visualización de la ayuda compilada instalada en el directorio SYSTEM. |
| itss.dll | Librería utilizada en la visualización de la ayuda compilada instalada en el directorio SYSTEM. |
Si ha instalado Microsoft Internet Explorer 4 o superior, automáticamente
estos componentes se habrán instalados. En Windows 98 y NT 5, ya se suministran
como parte del sistema operativo.
En esta parte, queremos mostrar como se accede a los ficheros de ayuda
compilada, desde una aplicación de Delphi. Primeramente abordaremos, de una
forma muy general, el API de la ayuda compilada, explicaremos la forma en que se
especifica una URL en un fichero de ayuda compilada y mediante ejemplos,
mostraremos como desde un programa de Delphi se accede a la tabla de contenido,
el índice, las búsquedas, y obtener ayuda sensible al contexto. Usted puede
apoyarse, durante la lectura de este artículo, descargando
la fuentes del programa de ejemplo suministrado.
Para construir la ayuda compilada, debemos usar el paquete MS HTML Help
Workshop, que puede ser obtenido gratuitamente, descargandolo en Internet
desde el sitio de Microsoft.
El API de HTML Help, permite a los programas de Windows crear ventanas
de ayuda y mostrar los tópicos de la ayuda, con un control completo sobre el
tipo, estilo y posición de la ventana de ayuda.
También, la ventana de ayuda, puede emerger en un programa Windows sin uso de
la tecnología OLE. Además, está implementado la ayuda sensible al contexto,
búsqueda por palabras claves, interacción con los programas de Windows y
control del panel de navegación en el visor de ayuda.
El API de HTMP Help tiene una sola función que muestra la ventana de la
ayuda. A través de esta función usted puede especificar que tópico mostrar en
la ventana de la ayuda, si es mostrado en una ventana emergente (popup),
si el tópico es accesado a través de su ID, una palabra clave, un salto URL,
etc.
|
HWND HtmlHelp(HWND hwndCaller, LPCSTR pszFile, UINT uCommand, DWORD dwData) ; |
| hwndCaller |
|
| pszFile |
|
| uCommand |
|
| dwData |
|
Dependiendo del valor de uCommand especificado, esta funcion retorna:
Un listado de los comandos disponibles (parámetro uCommand de la función HtmlHelp) por categorías, es el siguiente:
| Categoría | Comando |
| Tipo de Ventana | HH_CLOSE_ALL HH_GET_WIN_HANDLE HH_GET_WIN_TYPE HH_SET_WIN_TYPE |
| Ayuda sensible al contexto | HH_DISPLAY_TEXT_POPUP HH_DISPLAY_TOPIC HH_HELP_CONTEXT HH_TP_HELP_CONTEXTMENU HH_TP_HELP_WM_HELP |
| Búsqueda por palabras claves | HH_ALINK_LOOKUP HH_KEYWORD_LOOKUP |
| Panel de Navegación | HH_DISPLAY_INDEX HH_DISPLAY_SEARCH HH_DISPLAY_TOC |
| Mensajes de error | HH_GET_LAST_ERROR |
| Sincronizar con el contenido | HH_SYNC |
| Hilo de ejecución simple | HH_INITIALIZE HH_PRETRANSLATEMESSAGE HH_UNINITIALIZE |
El comando más importante es HH_DISPLAY_TOPIC, que permite abrir un fichero
de ayuda compilada (CHM) en una ventana de ayuda y mostrar el tópico
especificado dentro de este fichero.
Para acceder al API de la ayuda compilada, hemos traducido al PASCAL el fichero HtmlHelp.h
suministrado con el paquete de Microsoft. Usted encontrará este fichero
con el nombre HHelp.pas en el archivo compactado
que acompaña este artículo. En cada unidad en que haga acceso a la ayuda
compilada, deberá incluir el mismo en la claúsula uses.
En un fichero de ayuda HTML compilada, una URL especifica un fichero o un
tópico y opcionalmente el tipo de ventana para mostrar la parte referenciada
por la URL.
Para especificar una URL a un fichero de ayuda compilada, se hace como sigue:
FicheroAyuda.chm[>nombre de Window]
donde FicheroAyuda.chm es el nombre del fichero de la
ayuda HTML compilada y nombre de Window, es el nombre de la ventana de
ayuda donde se desea que aparezcan los tópicos.
Para especificar un tópico dentro de un fichero de ayuda compilada, se escribe:
FicheroAyuda.chm::Topico.htm[>nombre de Window]
donde Topico.htm, es el nombre del fichero HTML que se
quiere mostrar en la ventana de la ayuda.
Si la ayuda compilada ha sido construida, preservando el camino de acceso a los
ficheros HTML, entonces una URL a un fichero con estas características, se
escribe:
FicheroAyuda.chm::/Camino/Topico.htm[>nombre de Window]
donde Camino, es la cadena de carpetas anidadas por la
que se llega al fichero.
También es usual, anteceder estas URL con la partícula "ms-its:".
Esta partícula, identifica un protocolo, registrado en Windows, similar a
cuando en un navegador de internet escribimos "http://".
Así que en general, desde una página HTML, al referirnos a otra página HTML almacenada en un fichero de ayuda compilada, debemos escribir:
ms-it:FicheroAyuda.chm::/Camino/Topico.htm[>nombre de Window]
La forma más inmediata y sencilla de ver un fichero de ayuda HTML compilada, es hacer doble CLICK sobre el nombre del mismo (extensión CHM) en el Explorador de Windows.
Desde nuestras aplicaciones, podemos ejecutar la siguiente línea de código, para obtener el mismo resultado:
| { Cuando se instala el
visualizador de ficheros de ayuda HTML compilada, los ficheros con
extension CHM, se asocian a la utilidad HH.EXE, que los muestra. La
funcion ShellExecute, retorna el handle a la aplicación asociada que
abre el fichero de ayuda compilada, Esto puede ser utilizado para
realizar algún procesamiento adicional al hecho de visualizar la ayuda
} ShellExecute(Handle, 'open', PChar(Application.HelpFile), nil, nil, SW_SHOWNORMAL); |
El visor de la ayuda HTML compilada, es una ventana de tres paneles, como usted puede ver mientras lee los artículos del Taller de Delphi.
Cada panel del visor, puede ser manipulado a través de la estructura HH_WINTYPE y el API de la ayuda HTML compilada; pero esto no presenta interés en esta exposición.
En lo adelante, supondremos que en la propiedad HelpFile de nuestra aplicación, hemos establecido el nombre del fichero de ayuda HTML compilada.
Para obtener la tabla de contenido de la ayuda, ejecutamos el siguiente comando:
| {Muestra el visor de
ayuda con la pestaña de Contenido
activada, mostrando la página principal} HtmlHelp(Handle, PChar(Application.HelpFile), HH_DISPLAY_TOC, 0); |
De la misma manera, para obtener el índice de la ayuda, ejecutamos el siguiente comando:
| var ss : string; {Muestra el visor de ayuda con la
pestaña de Indice activada} |
Para comenzar una búsqueda podemos usar el siguiente procedimiento:
| {Muestra el visor de ayuda
con la pestaña de Buscar activada y realiza una busqueda por proximidad
de la cadena suministrada} procedure HHelpBuscar(ss: string); var q : HH_FTS_QUERY; begin q.cbStruct := SizeOf(HH_FTS_QUERY); q.fUniCodeStrings := FALSE; q.pszSearchQuery := PChar(ss); q.iProximity := HH_FTS_DEFAULT_PROXIMITY; q.fStemmedSearch := FALSE; q.fTitleOnly := FALSE; q.fExecute := FALSE; q.pszWindow := nil; HtmlHelp(Handle, PChar(Application.HelpFile), HH_DISPLAY_SEARCH, DWORD(@q)); end; |
Si en la estructura HH_FTS_QUERY, establecemos el miembro fExecute en True, entonces al invocar la función HtmlHelp, se realiza la búsqueda solicitada. Si el miembro fTitleOnly se establece en True, la búsqueda se realiza solamente sobre los títulos de los tópicos de ayuda.
| {Procedimiento para
activar la ayuda contenida en una página determinada.} procedure MostrarTopico(Topico : string); begin HtmlHelp(Handle, PChar(Application.HelpFile + '::/' + Topico), HH_DISPLAY_TOPIC, 0); end; |
| { Al invocar la
ayuda contextual, es requisito que el fichero de ayuda HTML compilada,
haya sido construido llenando en la seccion MAP la asociacion de las
cadenas contextuales con las páginas de la ayuda. En el fichero de
cabecera tienen estar referidas igualmente las cadenas contextuales
con los valores numericos de la ayuda contextual que usamos en el
campo HelpContext de los controles.} HtmlHelp(Handle, PChar(Application.HelpFile), HH_HELP_CONTEXT, HelpContext); |
| // Constantes para los tópicos
de ayuda contextual #define IDH_MAIN 10000 #define IDH_PAGINA1 11000 #define IDH_PAGINA2 12000 #define IDH_POPUP 20000 |
Para adicionar en la sección MAP, el nombre de fichero de inclusión, abrir con un editor de texto, ie. NOTEPAD.EXE, buscar la sección MAP y si no existe crear y poner el nombre del fichero. Esto quedará como se muestra a continuación:
| [MAP] #include CTXHelp.h |
El nombre del fichero de inclusión debe estar contenido, además, en el listado de ficheros de la ayuda HTML compilada, que se encuentra en la sección FILES del proyecto de ayuda.
Finalmente, la sección ALIAS debe ser constuída o de existir ya, adicionar una línea para cada constante simbólica asociada a una página de ayuda contextual, como se muestra en el siguiente ejemplo:
| [ALIAS] IDH_PAGINA1=Pagina1.htm IDH_PAGINA2=Pagina2.htm |
Dedicaremos otro artículo a la construcción de la ayuda HTML compilada y abundaremos más sobre en contenido del proyecto de ayuda. Por el momento, aceptemos esto como necesario para lograr el funcionamiento de la ayuda HTML en nuestros programas.