Recital

Login Register

One of the attractive features of Linux is the impressive 3D desktop that even works on most older hardware.

You can enabled the 3D Desktop on CentOS5 by installing the compiz package:

yum install compiz 

After you have done this, go to the top panel and click System, then select Preferences > and click 'Desktop Effects.

You will get a new dialog. To test and see if your hardware supports the 3D Desktop, press the button Enable Desktop Effects. If everything works fine, you can select Keep Settings.

Then test your 3D Desktop by pressing Ctrl-Alt-Left and Ctrl-Alt-Right, or drag a window around or even out of the screen to the left or right. If you maximize a window, you will see another cool effect. If you move the mouse to the upper-right corner of the screen you see all your opened applications.

Way cool!
Published in Blogs
Read more...
In Linux you can run lsof and pipe it though grep for the files you are interested in, for example;
$ lsof | grep db.exe | grep accounts
db.exe    16897      john    6uw     REG      253,0    20012    3413872 /usr/recital100/qa/accounts.dbf
db.exe    16897      john    7u      REG      253,0     4176    3413885 /usr/recital100/qa/accounts.dbx
If you want to check for locks you can use lslk, for example;
$ lslk | grep db.exe | grep accounts
db.exe    16897 253,0 3413872 20012  w 0  0  0 12319   0 /usr/recital100/qa/accounts.dbf
If you don't have lslk installed you can install it with one of the updaters, for example on redhat linux:
$ yum update lslk

Published in Blogs
Read more...

We are pleased to announce the release of Recital 10.0.2.

Here is a brief list of features and functionality that you will find in the 10.0.2 release. 

  • New commands
    SAVE/RESTORE DATASESSION [TO variable]
    CONNECT "connectString"
    DISCONNECT 
  • New functions (OData compatible)
    startsWith(haystack as character, needle as character)
    endsWith(haystack as character, needle as character)
    indexOf(haystack as character, needle as character)
    substringOf(haystack as character, needle as character)
    concat(expC1, expC2)
  • New system variables
    _LASTINSERTEDSYNCNUM
  • Enhanced commands
    Added CONNSTRING "connectingString" to the USE command to connect to remote servers (Recital, MySQL, PostgreSQL, Oracle, ODBC)
  • Further SQL query optimizer improvements to boost performance
  • Performance improvements in Recital Web
  • Forced all temporary files into temp directory (improves performance when local tmpfs is used as temp directory and reduces network i/o)
  • Fixed cookie and session variable problems in Recital Web
  • Fixed problem with temporary files being left after some server queries involving memos and object data types
  • Improved performance of the Windows ODBC driver
  • Fixed a security flaw in Recital Web
  • Fixed all reported bugs 
Published in Blogs
Read more...
This website runs in a  virtual machine under vmware server. It is clustered between two servers using heartbeat and DRBD.
 
When VMware server starts up a virtual machine it generates a uuid (unique id) based on the machine it is running on and stores this in the .vmx file.
 
When heartbeat switches from slave to master, it will start VMware server (which is setup as a resource in the haresources file).
 
Virtual machines that you want started automatically when you start VMware server will not start because the uuid changes between the master and backup systems. To get around this problem always do the following:
  • edit the .vmx file and add the following line

    uuid.action = "keep"
If this is not done then everytime you try to run the virtual machine on the backup system in your cluster, VMware server will complain that the virtual machine has been copied or moved and it will not start it.
  • set the virtual machine to power off when vmware is stopped. Do not set this to "suspend" or it will not restart on the backup machine.
This will allow the virtual machine to start properly on the backup machine.
 
 
 
Published in Blogs
Read more...

In this article Barry Mavin, CEO and Chief Software Architect for Recital details how to Build C Extension Libraries to use with Recital.

Overview

It is possible to extend the functionaliy of Recital products using "Extension libraries" that can be written in C. These extension libraries, written using the Recital/SDK API, are dynamically loadable from all Recital 9 products. This includes:

  • Recital
  • Recital Server
  • Recital Web

Building C Extension Libraries

You can create C wrappers for virtually any native operating system function and access these from the Recital 4GL. Unlike traditional APIs which only handle the development of C functions that are callable from the 4GL, the Recital/SDK allows you to build Classes that are accessible from all Recital products. e.g. You could create a GUI framework for Linux that handles VFP system classes!

To deploy your C Extension Libraries, copy them to the following location:

Windows:

\Program Files\Recital\extensions

Linux/Unix:

/opt/recital/extensions

Please see the Recital/SDK API Reference documentation for further details.

Sample code

Listed below is the complete example of a C Extension Library.:

////////////////////////////////////////////////////////////////////////////////
#include "mirage_demo.h"  
      
////////////////////////////////////////////////////////////////////////////////
// Declare your functions and classes below as follows:
//
//    Recital Function Name, C Function Name, Type (Function or Class)
//
#define MAX_ELEMENTS    7
static  struct  API_SHARED_FUNCTION_TABLE api_function_table[MAX_ELEMENTS] = {
        {"schar",   "fnSamplesCharacter",   API_FUNCTION},
        {"stype",   "fnSamplesType",           API_FUNCTION},
        {"slog",    "fnSamplesLogical",        API_FUNCTION},
        {"snum",    "fnSamplesNumeric",    API_FUNCTION},
        {"sopen",   "fnSamplesOpen",         API_FUNCTION},
        {"myclass", "clsMyClass",               API_CLASS},
        {NULL,      NULL,                   -1}
};

////////////////////////////////////////////////////////////////////////////////
// Recital API initialization. This should be in only ONE of your C files
// **IT SHOULD NEVER BE EDITED OR REMOVED**  
INIT_API;


///////////////////////////////////////////////////////////////////////
// This is an example of passing a character parameter and returning one.
RECITAL_FUNCTION fnSamplesCharacter(void)
{
    char    *arg1;
    
    if (!_parse_parameters(PCOUNT, "C", &arg1)) { 
        ERROR(-1, "Incorrect parameters");
    }
    
    _retc(arg1);
}


///////////////////////////////////////////////////////////////////////
// This is an example of passing a numeric parameter and returning one.
RECITAL_FUNCTION fnSamplesNumeric(void)
{
    int arg1;
    
    if (!_parse_parameters(PCOUNT, "N", &arg1)) { 
        ERROR(-1, "Incorrect parameters");
    }
    
    _retni(arg1);
}


///////////////////////////////////////////////////////////////////////
// This is an example returns the data type of the parameter passed.
RECITAL_FUNCTION fnSamplesType(void)
{
    char    result[10];

    if (PCOUNT != 1) { 
        ERROR(-1, "Incorrect parameters");
    }
    
    switch (_parinfo(1)) {
        case API_CTYPE:
            strcpy(result, "Character");
            break;
        case API_NTYPE:
            strcpy(result, "Numeric");
            break;
        case API_LTYPE:
            strcpy(result, "Logical");
            break;
        case API_DTYPE:
            strcpy(result, "Date");
            break;
        case API_TTYPE:
            strcpy(result, "DateTime");
            break;
        case API_YTYPE:
            strcpy(result, "Currency");
            break;
        case API_ATYPE:
            strcpy(result, "Array");
            break;
        default:
            strcpy(result, "Unkown");
            break;
    }

    _retc(result);
}


///////////////////////////////////////////////////////////////////////
// This is an example returns "True" or False.
RECITAL_FUNCTION  fnSamplesLogical(void)
{
    char    result[10];
    int     arg1;
    
    if (!_parse_parameters(PCOUNT, "L", &arg1)) { 
        ERROR(-1, "Incorrect parameters");
    }
    
    if (arg1) strcpy(result, "True");
    else strcpy(result, "False");

    _retc(result);
}


///////////////////////////////////////////////////////////////////////
// This example opens a table.
RECITAL_FUNCTION fnSamplesOpen(void)
{
    char    *arg1;
    
    if (!_parse_parameters(PCOUNT, "C", &arg1)) { 
        ERROR(-1, "Incorrect parameters");
    }
    
    if (_parinfo(1) == API_CTYPE) {
        _retni(COMMAND(arg1));
    } else {
        _retni(-1);
    }
}

///////////////////////////////////////////////////////////////////////
// Define the MyClass CLASS using the API macros
///////////////////////////////////////////////////////////////////////
RECITAL_EXPORT int DEFINE_CLASS(clsMyClass)
{
    /*-------------------------------------*/ 
    /* Dispatch factory methods and return */
    /*-------------------------------------*/
    DISPATCH_FACTORY();
 
    /*---------------------------------*/
    /* Dispatch constructor and return */ 
    /*---------------------------------*/ 
    DISPATCH_METHOD(clsMyClass, Constructor);

    /*--------------------------------*/
    /* Dispatch destructor and return */
    /*--------------------------------*/
    DISPATCH_METHOD(clsMyClass, Destructor); 

    /*-----------------------------------*/
    /* Dispatch DEFINE method and return */
    /*-----------------------------------*/
    DISPATCH_METHOD(clsMyClass, Define);

    /*------------------------------*/
    /* Dispatch SET or GET PROPERTY */
    /* method for property NumValue */
    /* then return.                 */
    /*------------------------------*/
    DISPATCH_PROPSET(clsMyClass, NumValue);
    DISPATCH_PROPGET(clsMyClass, NumValue); 

    /*------------------------------*/
    /* Dispatch SET or GET PROPERTY */
    /* method for property LogValue */
    /* then return.                 */
    /*------------------------------*/
    DISPATCH_PROPSET(clsMyClass, LogValue);
    DISPATCH_PROPGET(clsMyClass, LogValue);

    /*-------------------------------*/
    /* Dispatch SET or GET PROPERTY  */
    /* method for property DateValue */
    /* then return.                 */
    /*-------------------------------*/
    DISPATCH_PROPSET(clsMyClass, DateValue);
    DISPATCH_PROPGET(clsMyClass, DateValue);

    /*-------------------------------*/
    /* Dispatch SET or GET PROPERTY  */
    /* method for property TimeValue */
    /* then return.                  */
    /*-------------------------------*/
    DISPATCH_PROPSET(clsMyClass, TimeValue);
    DISPATCH_PROPGET(clsMyClass, TimeValue);
 
    /*-------------------------------*/
    /* Dispatch SET or GET PROPERTY  */
    /* method for property CurrValue */
    /* then return.                  */
    /*-------------------------------*/
    DISPATCH_PROPSET(clsMyClass, CurrValue);
    DISPATCH_PROPGET(clsMyClass, CurrValue);

    /*-------------------------------*/
    /* Dispatch SET or GET PROPERTY  */
    /* method for property CharValue */
    /* then return.                  */
    /*-------------------------------*/
    DISPATCH_PROPSET(clsMyClass, CharValue); 
    DISPATCH_PROPGET(clsMyClass, CharValue);

    /*------------------------------*/
    /* Dispatch SET or GET PROPERTY */ 
    /* method for property ObjValue */ 
    /* then return.                 */
    /*------------------------------*/
    DISPATCH_PROPSET(clsMyClass, ObjValue);
    DISPATCH_PROPGET(clsMyClass, ObjValue);

    /*-----------------------------------*/
    /* If message not found return error */
    /*-----------------------------------*/
    OBJECT_RETERROR("Unknown message type");
}

////////////////////////////////////////////////////////////////////////////////
// Define METHOD handlers
////////////////////////////////////////////////////////////////////////////////
DEFINE_METHOD(clsMyClass, Constructor) 
{
        struct example_data *objectDataArea;

        /* Allocate memory for objects objectData area */
        objectDataArea = (struct example_data *) 
           malloc(sizeof(struct example_data));
        if (objectDataArea == NULL) return(-1);
    
        /* Assign the default property values */
        strcpy(objectDataArea->prop_charvalue, "Test API object");
        objectDataArea->prop_numvalue = 15.2827;
        objectDataArea->prop_logvalue = 'F';
        strcpy(objectDataArea->prop_datevalue, DATE_DATE());
        strcpy(objectDataArea->prop_timevalue, DATE_DATETIME());
        strcpy(objectDataArea->prop_currvalue, "15.2827");
        strcpy(objectDataArea->object_name, "APIobject");
        objectDataArea->prop_objvalue 
             = OBJECT_NEW(objectDataArea->object_name, "exception", NULL);
    
        /* Set the object objectData area */
        OBJECT_SETDATA((char *)objectDataArea);
    
        return(0);
}
  
DEFINE_METHOD(clsMyClass, Destructor) 
{
        struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();

        if (objectData != NULL) {
            if (objectData->prop_objvalue != NULL) 
              OBJECT_DELETE(objectData->prop_objvalue);
            free(objectData);
            objectData = NULL;
        }
        return(0);
}

DEFINE_METHOD(clsMyClass, Define) 
{
    struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();
    struct      API_EXPRESSION result;
    char        buffer[512];
    int         rc;

/* Check the object class */
    OBJECT_GETPROPERTY(objectData->prop_objvalue, "class", buffer);
    rc = OBJECT_GETARG(buffer, &result);
    if (result.errno == 0 && result.type == 'C' 
        && strcmp(result.character, "Exception") == 0) { 
        switch (OBJECT_GETARGC()) {
            case 1: 
                rc = OBJECT_GETPARAMETER(1, &result);
                if (result.errno == 0 && result.type == 'C') {
                    OBJECT_SETARG(buffer, &result);
                    rc = OBJECT_SETPROPERTY(objectData->prop_objvalue,
                         "message", buffer);
                }
                break;
            case 2: 
                rc = OBJECT_GETPARAMETER(2, &result);
                if (result.errno == 0 && result.type == 'N') {
                    OBJECT_SETARG(buffer, &result);
                    rc = OBJECT_SETPROPERTY(objectData->prop_objvalue,
                         "errorno", buffer);
                }
         }
    }

    result.type = 'L';
    result.logical = (rc == 0 ? 'T' : 'F');  
    OBJECT_RETRESULT(&result);
}

////////////////////////////////////////////////////////////////////////////////
// Define GET property handlers
////////////////////////////////////////////////////////////////////////////////
DEFINE_PROPERTYGET(clsMyClass, NumValue) 
{
    struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();

    if (objectData == NULL) return(-1);

    OBJECT_RETPROPERTY('N', objectData->prop_numvalue);
}

DEFINE_PROPERTYGET(clsMyClass, LogValue) 
{
    struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();

    if (objectData == NULL) return(-1);

    OBJECT_RETPROPERTY('L', objectData->prop_logvalue);
}  

DEFINE_PROPERTYGET(clsMyClass, DateValue) 
{
    struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();

    if (objectData == NULL) return(-1);

    OBJECT_RETPROPERTY('D', objectData->prop_datevalue);
}

DEFINE_PROPERTYGET(clsMyClass, TimeValue) 
{
    struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();

    if (objectData == NULL) return(-1);

    OBJECT_RETPROPERTY('T', objectData->prop_timevalue);
}

DEFINE_PROPERTYGET(clsMyClass, CurrValue) 
{
    struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();

    if (objectData == NULL) return(-1);

    OBJECT_RETPROPERTY('Y', objectData->prop_currvalue);
}

DEFINE_PROPERTYGET(clsMyClass, CharValue) 
{
    struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();

    if (objectData == NULL) return(-1);

    OBJECT_RETPROPERTY('C', objectData->prop_charvalue);
}

DEFINE_PROPERTYGET(clsMyClass, ObjValue) 
{
    struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();

    if (objectData == NULL) return(-1);

    OBJECT_RETPROPERTY('O', objectData->prop_objvalue);
} 


////////////////////////////////////////////////////////////////////////////////
// Define SET property handlers
////////////////////////////////////////////////////////////////////////////////
DEFINE_PROPERTYSET(clsMyClass, NumValue) 
{
    struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();
    struct API_EXPRESSION result;
    int rc = OBJECT_ERROR;

    OBJECT_GETVALUE(&result);
    if (result.errno == 0 && result.type == 'N') {
        objectData->prop_numvalue = result.number;
        rc = OBJECT_SUCCESS;
    }

    return(rc);
}

DEFINE_PROPERTYSET(clsMyClass, LogValue) 
{
    struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();
    struct API_EXPRESSION result;
    int rc = OBJECT_ERROR;

    OBJECT_GETVALUE(&result);
    if (result.errno == 0 && result.type == 'L') {
        objectData->prop_logvalue = result.logical;
        rc = OBJECT_SUCCESS;
    }

    return(rc);
}

DEFINE_PROPERTYSET(clsMyClass, DateValue) 
{
    struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();
    struct API_EXPRESSION result;
    int rc = OBJECT_ERROR;
    OBJECT_GETVALUE(&result);
    if (result.errno == 0 && result.type == 'D') {
        strcpy(objectData->prop_datevalue, DATE_DTOS(result.date));
        rc = OBJECT_SUCCESS;
    }

    return(rc);
}

DEFINE_PROPERTYSET(clsMyClass, TimeValue) 
{
    struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();
    struct API_EXPRESSION result;
    int rc = OBJECT_ERROR;

    OBJECT_GETVALUE(&result);
    if (result.errno == 0 && result.type == 'T') {
        strcpy(objectData->prop_timevalue, DATE_TTOS(result.datetime));
        rc = OBJECT_SUCCESS;
    }

    return(rc); 
}

DEFINE_PROPERTYSET(clsMyClass, CurrValue) 
{
    struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();
    struct API_EXPRESSION result;
    int rc = OBJECT_ERROR;

    OBJECT_GETVALUE(&result);
    if (result.errno == 0 && result.type == 'Y') {
        strcpy(objectData->prop_currvalue, CURR_YTOS(result.currency));
        rc = OBJECT_SUCCESS;
    }

    return(rc);
}

DEFINE_PROPERTYSET(clsMyClass, CharValue)  
{
    struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();
    struct API_EXPRESSION result;
    int rc = OBJECT_ERROR;

    OBJECT_GETVALUE(&result);
    if (result.errno == 0 && result.type == 'C') {
        strcpy(objectData->prop_currvalue, result.character);
        rc = OBJECT_SUCCESS;
    }

    return(rc);
}

DEFINE_PROPERTYSET(clsMyClass, ObjValue) 
{
    struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();
    OBJECT  objvalue;
    int rc = OBJECT_ERROR;

    if (OBJECT_GETTYPE() == 'O') {
        objvalue = OBJECT_GETOBJECT(); 
        objectData->prop_objvalue = OBJECT_ASSIGN(objvalue, objectData->object_name);
        rc = OBJECT_SUCCESS;
    }

    return(rc);
}
Published in Blogs
Read more...

Here is a simple shell script to copy your ssh authorization key to a remote machine so that you can run ssh and scp without having to repeatedly login.

#!/bin/sh
# save in file ssh_copykeyto.sh then chmod +x ssh_copykeyto.sh
KEY="$HOME/.ssh/id_rsa.pub"
if [ ! -f ~/.ssh/id_rsa.pub ];then
echo "private key not found at $KEY"
echo "create it with "ssh-keygen -t rsa" before running this script
exit
fi
if [ -z $1 ];then
echo "Bad args: specify user@host as the first argument to this script"
exit
fi
echo "Copying ssh authorization key to $1... "
KEYCODE=`cat $KEY`
ssh -q $1 "mkdir ~/.ssh 2>/dev/null; chmod 700 ~/.ssh; echo "$KEYCODE" >> ~/.ssh/authorized_keys; \ chmod 644 ~/.ssh/authorized_keys"
echo "done!"
Published in Blogs
Read more...
In Recital 10, you can declare anonymous classes and call anonymous methods in these classes.
// declare some simple procedures 
proc display(cArg)
    echo "display=" + cArg
endproc

proc show(cArg)
    echo "show=" + cArg
endproc

// create an object based on an anonymous class
myobj = new object()

// add some properties
myobj["name"] = "barry"
myobj["company"] = "recital"

// now declare an anonymous method
myobj["mymethod"] = display

// call the method
myobj.mymethod("hello world")    // displays "display=hello world"

// redeclare the method
myobj["mymethod"] = show

// call the method
myobj.mymethod("hello world")    // displays "show=hello world"
Where this becomes particularly useful is when you have a procedure that calls anonymous methods in order to process data. This technique can be used to call anonymous procedures in your code.
proc processdata(oArg)
    oArg.mymethod(oArg.name)    
endproc

proc show(cArg)
    echo "show=" + cArg
endproc

myobj = new object()
myobj["name"] = "barry"
myobj["mymethod"] = show
processdata(myobj)        // displays "show=barry"
Published in Blogs
Read more...

Yes, your FoxPlus and FoxPRO applications should run under Recital with little to no changes at all. We provide expert product support if you have any questions or problems. If you lack the resources to move your applications into Recital we can provide that service to you also if required.
Published in Blogs
Read more...

MQCURMSGS()

Syntax

MQCURMSGS( <expN> )

Description

The MQCURMSGS() function returns the current number of unread messages in the queue specified by <expN>

Example

mqdes=mqopen("/myqueue")
if (mqdes < 0)
   messagebox(strerror()+",errno="+alltrim(str(error())))
   return
endif
do while (mqcurmsgs(mqdes) > 0)
   mstr=mqreceive(mqdes)
   if (empty(mstr))
      messagebox(strerror()+",errno="+alltrim(str(error())))
      return
   endif
   messagebox(mstr)
end do
mqclose(mqdes)

Published in Blogs
Read more...

Copyright © 2025 Recital Software Inc.

Login

Register

User Registration
or Cancel