Recomendaciones
De ClarionWiki
Recomendaciones y Trucos que nos pueden evitar dolores de cabeza
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.

