Recomendaciones

De ClarionWiki

Recomendaciones y Trucos que nos pueden evitar dolores de cabeza

Tabla de contenidos

Version Demo (basica)

Poner este embed global en un par de tablas importantes

Global Embeds
   Abc Objects
       File Managers
           File Manager for YourFile
               Insert - Before Parent Call
IF RECORDS(SELF.FILE)> 10
 MESSAGE('Demo Version')
 RETURN LEVEL:FATAL
END

Fernando Cerini (Evolution)

Obtener un total general (al final) en un Reporte

Lo mas facil es armar un break group sobre una variable que no cambie nunca,
(puede ser cualquier variable global, por ejemplo)
Luego pones los totales en un group footer de este break y listo.
Como la variable nunca cambia (puede ser una global por ejemplo) solo se
imprime el group footer al final del reporte.
Tambien podria usarse el Group Header de ese break como "caratula" del reporte

Fernando Cerini (Evolution)

Usar DLLs no creadas en Clarion

Para Usar DLLs no creadas en Clarion, hay que seguir los siguientes pasos:

- Crear los prototipos equivalentes en Clarion
para esto hay que averiguar cuales son los prototipos originales (en c, por ej.)
y ver la equivalencia de tipos entre Clarion, C y  o C++
- Usar el Libmaker para la creacion de una Clarion Library (.LIB File) para la DLL
- Incluir el .LIB File al proyecto

Para mas detalles, ver .\docs\FAQsTips&Tricks.pdf el tema "How to Use Windows DLLs NOT Created in Clarion".

Si no tiene ese archivo, lo puede bajar desde nuestra pagina: Clarion6 FAQs

Fernando Cerini (Evolution)

Modificar codigo en multiples embeds, o varias tablas del DCT

Se puede exportar la aplicacion o el DCT a Texto (app.TXA) modificar el texto con un buen editor (yo recomiendo el textpad) y luego importar de nuevo.

Obviamente, hacer un backup primero porque esto es una opracion "peligrosa"

En nuestra seccion de Downloads el documento de migracion de TPS a SQL se basa en esta tecnica para modificar el DCT.

Fernando Cerini (Evolution)

Deshabilitar el PopUp en un control TEXT

Simplemente asignar la Key MouseRight al control TEXT

Desplegar una opcion de menu desde un boton

Ponle un hotkey al menu, por ejemplo

Menu Text: &Browse

Luego en el boton

PRESSKEY(AltB)

Fernando Cerini (Evolution)

Obtener los diferentes elementos del path

Global Embeds - Inside Global Map

Include('clib.clw')

En el embed:

X# = FnSplit(LOC:Path,LOC:Drive,LOC:Dir,LOC:File,LOC:Ext)
DISPLAY

Las variables locales son todas CSTRING(256) Por ejemplo para saber solo el nombre del archivo se usaria LOC:File & LOC:Ext

Fernando Cerini (Evolution)

Conversion de Archivos

1) Tenés que tener un diccionario aparte, en principio vacio. Yo lo llamo conversiones.dct.

2) Abrís ambos DCT. Te parás en la definición que querés convertir y apretás "copiar". Te parás en el conversiones.dct y apretás "pegar". A este archivo pegado lo renombrás con la fecha (por ejemplo, si mi archivo a convertir se llama CLIENTES, en conversiones lo pego como CLIENTES_ 050328).

3) Hacés todos los cambios que necesites en la definición de tu archivos CLIENTES. Acá ya podés recompilar todo tu sistema.

4) Cerrá tu diccionario, dejá abierto Conversiones.dct. Seleccioná "convert" el archivo, te pide el path al archivo y primero te hace un "browse" sobre el mismo, de ahí seleccionás el menú "File", "Convert File" y te abre una ventanita.

5) Acá, en target dictionary elegís tu DCT, el que tiene la definición ahora modificada (Acordate que estás en el conversiones.dct).

6) En target structure, buscás en tu DCT el nombre del archivo convertido.

7) En Generated source, tipeá algo que tenga sentido: yo voy numerando mis programas conversores, así que voy poniendo algo como CONV0001, CONV0002, etc. Fijate bien el path donde lo metés.

8) Si no salió solo, salí del browser, cerrá todos los DCT.

9) Andá por "File", "Change directory" y cambiate al directorio donde grabaste el fuente del conversor. Yo uso un subdirectorio "pasa".

10) Andá a "File", "Open", elegí "Clarion source", y abrí el programa conversor.

11) Andá a "Project", "Set" y seleccioná el archivo de proyecto que tiene el mismo nombre que el fuente del conversor.

12) Editale lo que quieras al programa conversor. Acá por ejemplo a veces cambio el directorio de salida, o ajusto la ventana de display, le pongo mensajes o hago cualquier asignación que sea necesaria.

13) Compilá, correlo y listo. Te queda un ejecutable autónomo que podés correr en el cliente llamándolo a mano, desde un instalador o desde tu propia aplicación.

14) Ventaja adicional: Si tu cliente guarda backups de los archivos, y por la circunstancia que sea tiene que reprocesar información de un archivo viejo, se pueden correr todos los programas de conversión que corresponden a ese archivo, en secuencia, para llevar su formato al actual.

15) Otra ventaja: este método sirve para cualquier base ISAM, para SQL hay que hacer algunos pasos más pero básicamente se puede hacer lo mismo.

Finalmente, te digo que esto lleva muchísimo más tiempo explicarlo y aprenderlo que hacerlo. Cuando te digo que todo esto lleva 1 minuto, es en serio, es lo que lleva cuando ya sabés cómo hacerlo de memoria.

Una acotación, con este método te van quedando en el conversiones.dct todas las definiciones históricas de tus archivos, algo que puede llegar a ser muy últil, mientras que en tu dct de "trabajo" sólo está la definición "actual" y no hay nada que haga ruido.

Saludos, Jorge A. Lavera

Encriptacion de TPS

Sobre el Owner Name y su seguridad o capacidad de encriptacion depende mas que nada del planeamiento que a la herramienta en si misma

Caso 1 : Owner Name : " Tu palabra clave "

Este caso es el mas vulnerable de todos no se demora mas de una hora en buscarlo y encontrarlo a simple vista , con la tecnologia adecuada son solo minutos.


Caso 2 : Owner Name : " ©}êô?Ñé? " ( Carcateres ALT + xxxx)

Este caso ya comienza a complicar el nivel de busqueda dentro del exe por que no se encuentra relacion y lleva a la confusion con los otros caracteres dentro del exe y todos los hexadecimales , pero es vulnerable.


Caso 3 : Owner Name : " VGLO:xxxxxxxxxxxxxxx"

Aca el valor del Owler Name esta dentro de una variable global , esa variable global puede traer la informacion desde otro lado , archivo , otra variable,etc. Este metodo es el mas complicado de todos para aquel que quiera romper el TPS.

Para mi el mejor caso de seguridad en TPS's es el 3 , por el nivel de dificultad que presenta y ante un intento de vulnerabilidad por fuerza bruta siempre devuelve un valor 0. Es muy importante tener bien documentado lo realizado utilizando el caso 3 porque de perder la informacion , el diseño, etc. el mismo desarrollador puede quedar preso y victima de su propia seguridad

Estos son lo niveles que se pueden manejar desde el IDE de desarrollo de Clarion , pero tambien se le pueden agregar elementos externos.

Por ejemplo utilizando el Caso 3 + algun compactador de exes ( ASPACK ) realmente se hace casi imposible encontrar las cabeceras de definicion de las tablas , etc.etc. .

Remarco de lo CASI , porque se puede vulnerar ,pero ahi ya comienzan a medir otros parametros como ser el costo/beneficio de invertirle horas y horas o dias y dias a ese intento de poder vulnerar el archivo , etc, etc, etc. el cual tambien esta relacionado al hardware y su capacidad de procesamiento , etc.

Espero que les sirva.

Ing. Fabian Coria

Consultor Seguridad Informatica, Capital Soft

Diferir la carga de un browse ABC

Los browse ABC se cargan automáticamente al abrir la ventana. Pero muchas veces se desea controlar el momento de la carga porque se utilizan filtros que deben ser ingresados por el usuario (por ejemplo, un rango de fechas). Es un tema particularmente importante cuando se trata de browses “file loaded”, o cuando se trabaja sobre MySQL (al utilizar este motor todos los browse son “file loaded”).

Para diferir la carga de un browse ABC hay dos posiblidades.


A. Mediante BrowseClass.ActiveInvisible

Esta técnica consiste en “esconder” el ListBox mediante HIDE y apagar la propiedad BrowseClass.ActiveInvisible. Cuando se quiere cargar el browse se quita la propiedad HIDE al ListBox.

Los pasos a seguir son los siguientes:

1. En el Window Formatter encender la propiedad HIDE (o utilizar el comando HIDE en el código del procedimiento) para el control correspondiente al ListBox del browse.

2. En WindowManager.Init, con prioridad 8150, agregar el siguiente código:

BRW1.ActiveInvisible = False	!BRW1 es el nombre del objeto Browse

3. Cuando se quiera cargar y mostrar el browse, agregar el siguiente código:

?Browse:1{PROP:Hide} = False	!?Browse:1 es el control del ListBox
ThisWindow.Reset(True)


B. Derivando la BrowseClass

Esta técnica tiene la ventaja de que no es necesario que el ListBox esté oculto. Consiste en agregar una nueva propiedad a la clase BrowseClass que controle cuándo se desea cargar el browse. Según el estado de esta propiedad se omite o se ejecuta el método BrowseClass.ResetQueue.

Los pasos a seguir son los siguientes:

1. En BrowseBoxBehavior, en la solapa Classes, encender la opción “Derive?”

2. En New Class Properties agregar una propiedad de tipo BYTE. Para seguir con la nomenclatura en inglés del resto de la clase, la llamaremos “WaitToFill”

Property Name: 	WaitToFill
Property Type: 	BYTE

3. En WindowManager.Init, con prioridad 8150, agregar el siguiente código:

BRW1.WaitToFill = True	!BRW1 es el nombre del objeto Browse

4. En BrowseClass.ResetQueue, con prioridad 2500 (antes del ParentCall), agregar el siguiente código:

IF SELF.WaitToFill
   RETURN
END

5. Cuando se quiera cargar y mostrar el browse, agregar el siguiente código:

BRW1.WaitToFill = False	!BRW1 es el nombre del objeto browse
ThisWindow.Reset(True)

Si bien esto mismo se podría lograr con una variable, con una nueva propiedad se puede administrar más de un browse en el mismo procedimiento, aunque tengan diferente comportamiento.


Otras posibilidades

Como solución elemental esta técnica es suficiente. Una solución más completa sería derivar directamente la clase BrowseClass y utilizar la clase derivada en lugar de la clase original. El método ResetQueue de la nueva clase haría su propia omisión en base al valor de la propiedad WaitToFill. También se podría agregar un método para encender y apagar la propiedad WaitToFill.

La solución final consistiría en escribir un template que se encargue de implementar la técnica.



Daniel Ruzo

Miembro de GCU (Grupo Clarion Uruguay)

Identificacion UNICA

En ocaciones el campo de identificacion de nuestros archivos no son suficiente con que este sea autonumerado de forma secuencial. Por ejemplo tener un pedido en un archivo y los productos del pedido en otro archivo, podria ocurrir que ambos archivos sean reemplazados por backups de diferentes fechas (ej. pedidos mas viejo que item) asi cuando abrimos un nuevo pedido este ya poseera productos. Otro ejemplo es que tengamos varias bases distribuidas en diferentes maquinas (no en red) y estas se vuelcan sobre una solo grupo de archivos via internet (o cualquier otro medio) si son autonumeradas existiran mas de una ID con el mismo numero. Para solucionar esto pruebe lo siguiente:

En el Campo del archivo que sirve de Identificacion Ej. ClienteNumero
colocar en INITIAL VALUE colocar la funcion GeneraID()

Crear la funcion GeneraID

 loc:IDU   STRING(20)
 CODE
 !Identificacion Unica
 loc:IDU = FORMAT(TODAY(),@d11) & FORMAT(CLOCK(),@t5) & FORMAT(RANDOM(0,999),@n03)
 RETURN loc:IDU

un saludo DIPS

Parámetros en procedimientos llamados en threads nuevos

Si quiero mandar parámetros a un procedimiento llamado con START (es decir, en un thread nuevo), puedo mandar solo hasta 3 parametros y todos deben estar definidos como string en el prototipo del procedimiento. Internamente puedo convertir esos parámetros al tipo que necesito en variables locales al procedimiento.

Herramientas personales