Monthly Archives: February 2010

Automated Import and Export of Applications and Dictionaries

Clarion 7.1 added the ability to automatically import and export .App and .Dct files to/from their text representations.  This was primarily added for use with version control systems like Subversion, but developers may also find it useful for automated backup purposes.

With this system any time a dictionary or application is saved it is automatically exported to text.  If you load a dictionary or application and the text file has a newer time-stamp then the binary file, then the text file will be loaded into the binary file.  With this system you can then check in and check out the text representation of your files into your version control system, and the IDE will automate updating the binary files.   Further, if you are using Subversion as your version control system you can see the history of your file via the History tab (shown in the image below) appears at the bottom of the DCT Explorer or Application View.

The History tab displays the version history pulled from your SVN repository.

dcthistory

ClarionCl.exe is also auto import/export enabled.  So if you use another new feature of Clarion 7.1 (Enterprise Edition) to generate an application, the .App and .Dct files will be updated if the timestamp of the text file is newer then the binary file.  This allows you to use automated build tools like CruiseControl.NET to build your Clarion applications.

To enable automated import/export of files go to Tools/Options/General/Binary File auto-export/import.  You will then have a screen similar to the image below.

importexportconfig

The import/export automation does its work on a background thread, so you should not see any impact on your normal work flow.

Update for 7.1

A new update for 7.1 is now available.  One often requested feature was added; FEATURE:  You can now set (via Tools/Options/General/Projects and Solutions dialog) if new projects should default to release or debug mode.  Several good bug fixes, including a fix for a regression that popped up in build 6813. You can check the complete change log here.

And look for a new Clarion.Net release on this coming Monday!

Template Writing Tips

This is one of many posts to come with advice and tips about things you should do, and things to avoid, when writing Templates. It is intended to help developers who write templates to validate their templates, and to implement some best practices to ensure the templates they deliver work as expected.

The template language is very strict in its syntax, and blank spaces/lines can have a big impact. Spaces where they are not expected are evil. A blank line in the templates will generate a blank line in the generated code, but where that blank line lands in the generated code depends upon where that blank line is within the template code.

Some areas of a template are not meant to generate code, for example #PROMPTs representing the UI. Some templates, like an Extension template, are not supposed to contain any generated code except within #ATs where the code is inserted into an #EMBED.

If a blank line is found in a template, but in a place that is not correct, like between #PROMPTs, or outside a #AT in an Extension template, the code generator will push that line into the generated code, but because the blank line was in an incorrect location there is no explicit place to insert that blank line, and it will add it at the beginning of the block of generated code. To summarize, blank lines in a template are good, except when they are somewhere they are not supposed to be.

Blank lines intended to make the template code easier to read should be always be replaced with #! in column 1 (or just removed). There isn’t a blank line “statement” in the template language, and the reason for that is so that you don’t not mix template language code, with generated output text. Using something like #!———- is much better than a blank line, better in that it is safer and it is more visual.

Some places where a blank line should not be placed:

In any template between a #PROMPT or any other UI code (#SHEET,#TAB,etc.).
In #EXTENSION templates any blank line outside an #AT/#ENDAT block is incorrect.
In a #UTILITY template any blank line outside the scope of an #OPEN or #CREATE is incorrect.
In any template, any blank line used as a separator between #DECLARE statements or as a separator between any other statement is incorrect.

As a golden rule, if the blank line is not intended to be output to the generated code, then the blank line should be replaced by a #! in column 1, or just removed.

Update for 7.1

Latest update for 7.1 has just been made available. This build works around a problem Clarion developers found on Windows 7 when the Alt Key was pressed. The problem reported was an apparent conflict with Windows 7 “Live Mail” or Outlook 2007. Both of these apps default to hiding the main menu and activating it upon pressing the Alt Key. The problem wasn’t unique to Clarion 7, the same conflict happens under Windows 7 with version 6 Clarion apps (and most likely prior versions too). We are testing a backport of the workaround for C6.3.x.

In the prior release we implemented code completion within the regular Embed Editor. In this release we have optimized the process so when working within the Embed Editor code generation of the procedure only occurs when something has changed that requires it, and the generated code is reused in the same edit session if possible.

We also tweaked a few things to make working with App based solutions and various version control systems a lot smoother. These changes mainly deal with detecting read-only files (Apps and Projects), and then shifting into a mode such that no merging occurs from the App generation process. Speaking of version control, we introduced a nice feature several builds ago; “Binary File auto-export/import”. What’s that? Well if you open Tools-Options-General you’ll see a node aptly named “Binary File auto-export/import”. On that tab you can specify individual Apps and DCTs (or entire folders if you have multiple Apps or DCTs), and whenever you are working with the named Apps or DCTs, an automatic export/import to TXA or DCTX format is executed in the background. This means when you open the App (or DCT) for editing the system looks for the TXA or DCTX format file and automatically imports it, and when you save the App or DCT the system exports your latest changes. Pretty slick and very useful.

The other notable change in this release is a change in how deleted controls affect embedded code attached to those controls. In this release whether you delete a control from within the Designer, or even from within the text editor when working with the window or report structure as text, any attached embed code will become orphaned (leaving it up to you to delete or preserve).

There are also several other changes and fixes, to see the entire change log click here

LastChanceHook

Geoff Thomson from Capesoft asked me about an example on how to override the RTL’s internal exception handler.   I think this is a topic that is likely of interest to many Clarion developers and warrants an example, so here we go.

Overview

PROP:LastChanceHook is a write-only SYSTEM property, which allows you to specify your own function that will be invoked if an exception occurs. The hook function allows you to display information about the exception and choose one of the following actions:

  • Continue execution of the thread where the exception occurred (unless the exception is fatal)
  • Stop the thread (or the entire process if the exception occurred in the main process thread) without invoking the RTL’s internal exception handler
  • Invoke the RTL’s internal exception handler

    This allows you to catch an exception, and if it is non-fatal you can allow your end users to continue executing your program even when an exception has occurred in one of its threads.


    How It Works

    Your function, which you assign to the SYSTEM{PROP:LastChanceHook} property has to have a prototype of:

    HookProc (*ICWExceptionInfo),LONG

    The ICWExceptionInfo parameter is an interface declared in CWEXCPT.INT which you’ll find in your .Libsrc folder.

    The result returned by the hooked function is evaluated as follows:

    • If the result is equal to Zero, the RTL executes its own internal exception handler dialog to show information about the exception and subsequently perform the action chosen by the end user.
    • If a Positive number is returned, the RTL stops the thread (or the entire process if the exception occurred in the main process thread) without invoking the RTL exception handler.
    • If a Negative number is returned, the program will try to continue from the point of the exception. Note, if the exception is non-continuable, this result is ignored and treated as equal to Zero.

    So in our example we start with this code:


    PROGRAM

    INCLUDE(‘CWEXCPT.INT’),ONCE

    MAP
    Test (LONG,LONG)
    Hook (*ICWExceptionInfo),LONG
    HEX (LONG),STRING,PRIVATE
    MODULE(”)
    MessageBox (UNSIGNED, CONST *CSTRING, CONST *CSTRING, UNSIGNED),SIGNED,PROC,PASCAL,NAME(‘MessageBoxA’)
    END

    END

    MB_ICONHAND EQUATE(00000010h)

    CODE
    SYSTEM{PROP:LastChanceHook} = ADDRESS (Hook)
    Test (10, 0)  ! causes an exception
    RETURN

    In this example the Procedure named “Hook” is assigned as our exception handler. That’s the only Procedure we are concerned with, the others are just there to help make the example work by 1) causing an exception and 2) informing the user about the exception. Next we have:


    ! ------------------------------------------------------------------------------

    Hook PROCEDURE (*ICWExceptionInfo info)

    S CSTRING(1024)
    Caption CSTRING(256)

    CODE
    IF info &= NULL
    RETURN 0
    END

    Caption = ‘Exception ‘ & HEX (info.ExceptionCode()) & ‘ at ‘ & HEX (info.ExceptionAddress())
    S = ‘Registers’ & |
    ‘<13,10>EAX=’ & HEX (info.Register (i386_Register:Reg32_EAX)) & |
    ‘ EBX=’ & HEX (info.Register (i386_Register:Reg32_EBX)) & |
    ‘ ECX=’ & HEX (info.Register (i386_Register:Reg32_ECX)) & |
    ‘ EDX=’ & HEX (info.Register (i386_Register:Reg32_EDX)) & |
    ‘<13,10>ESI=’ & HEX (info.Register (i386_Register:Reg32_ESI)) & |
    ‘ EDI=’ & HEX (info.Register (i386_Register:Reg32_EDI)) & |
    ‘ ESP=’ & HEX (info.Register (i386_Register:Reg32_ESP)) & |
    ‘ EBP=’ & HEX (info.Register (i386_Register:Reg32_EBP)) & |
    ‘<13,10,13,10>Current thread is being terminated’

    MessageBox (0, S, Caption, MB_ICONHAND)
    RETURN 1      ! a positive value signals the RTL to kill the thread

    ! ——————————————————————————

    Test PROCEDURE (LONG a, LONG b)

    CODE
    a %= b

    ! ——————————————————————————

    HEX PROCEDURE (LONG A)

    i UNSIGNED,AUTO
    S STRING(8),AUTO
    DIGITS STRING(‘0123456789ABCDEF’),STATIC

    CODE
    i = SIZE(S)

    LOOP WHILE i <> 0
    S [i] = DIGITS [BAND (A, 0Fh) + 1]
    A = BSHIFT (A, -4)
    i -= 1
    END

    RETURN S

    ! ——————————————————————————



    These first two lines of code assign our exception handler function and then call the Test procedure that raises an exception:

    SYSTEM{PROP:LastChanceHook} = ADDRESS (Hook)
    Test (10, 0)  ! causes an exception

    The exception is trapped and we show the result in a MessageBox which looks like this:

    customexception

    our Hook PROCEDURE (*ICWExceptionInfo info) uses the methods in the interface to show the exception code, its address, and the values of the registers at the time of the exception. And remember we said that:

    “If a Positive number is returned, the RTL stops the thread (or the entire process if the exception occurred in the main process thread) without invoking the RTL exception handler.”

    in our example our Hook PROCEDURE does a “RETURN 1” and since we are running on the main thread then immediately after the MessageBox is displayed and the user presses the OK button the program itself is terminated.

    In a future article we’ll show you how to easily display the callstack so that your end-user can tell you exactly which procedure caused the exception. And we’ll be adding an option to the templates so that you can do the same with a couple of mouse clicks. You can download the source code for this example from this link