How can a C typedef stucture containing an array be converted to a clarion structure?

From the C API …

/** 
 * This is a definition which has sole purpose of helping readability.
 * It indicates that an array has variable length, depending on some
 * other context, usually some other members of en encosing structure.
 */
#ifndef ABS_VARLEN
#define ABS_VARLEN              1
#endif

/** 
 * The ABS_DATA structure is used to associate any arbitrary long data block 
 * with the length information. 
 */
typedef struct abs_data {
  ABS_DWORD Length; 	///< Length of the Data field in bytes.
  ABS_BYTE Data[ABS_VARLEN]; 	///< The data itself, variable length.
} ABS_DATA;

My starting point in Clarion Code:

ABS_DATA                                Group, type
Length                                   LONG
Data                                     BYTE()                   ! Oy, problems ....
                                        End

Try

Data    BYTE

without the ()

Thanks I did and it did not work.
The way I read the sample is it appears the ABS_BYTE Data[ABS_VARLEN]; ///< The data itself, variable length.
is an array, just a Byte doesn’t accomplish this, yes?

It looks like I may need this:
data Like(SomeQueue)

Oh sorry, I didn’t actually pay attention to your original C example, just the clarion bit. It looks to me like it is maybe trying to declare a byte array?

Perhaps this will help:

Ah, I was searching stackoverflow yesterday but didn’t search for ABS_DATA structure.

It certainly seems helpful but not Clarion code…

Not sure whether to use queue or group not sure this code is correct either I do get GPF errors.

ABS_DATA Group, type
Length LONG
Data Like(QueueOrGroup)
End

QueueOrGroup Group, Type
Data BYTE
END

I Tried using queue and get a compiler error, so I leave at group, I am at a stand still. Any other ideas?
Thanks in advance,
~Peter

What is the Active value for ABS_VARLEN
the #ifndef is like a conditional compile, it only fires when ABS_VARLEN is not already defined.

Add your own equate

ABS_VARLEN EQUATE(42)

abs_data GROUP,TYPE
_Length        DWORD
_Data          BYTE,DIM(ABS_VARLEN)
         END

Possibly alter the variable names a bit, as LENGTH and DATA have special meaning in Clarion.

Depending on the values for ABS_VARLEN
You might even be able to simply use a PSTRING

no, you couldn’t use a PSTRING, as it’s length is a BYTE, not a DWORD

make it a long or a possibly a &byte

abs_data group,type
length long
data &byte
    end

note, I have had issues with clarion and casting byte reference variables so just a long and stuff the address in it maybe the best option

Thanks Mark,

The example has a value of 1.

/** 
 * This is a definition which has sole purpose of helping readability.
 * It indicates that an array has variable length, depending on some
 * other context, usually some other members of en encosing structure.
 */
ifndef ABS_VARLEN
define ABS_VARLEN              1
endif

Would using a reference work as well?

abs_data GROUP,TYPE
_Length        DWORD
_Data          $BYTE
         END

~Peter

Thanks Dennis,
You posted just as I proposed if this would work.
~Peter

I believe that’s just a fallback value, in case it’s being used wrong.
I expect a normal use is something like

#define ABS_VARLEN 47
#include "TheFileYouAreCopyingThisFrom.h"

Do you have some context of how this code is being used ?

Yes:

/** 
 * The ABS_DATA structure is used to associate any arbitrary long data block 
 * with the length information. 
 */
typedef struct abs_data {
  ABS_DWORD Length; 	///< Length of the Data field in bytes.
  ABS_BYTE Data[ABS_VARLEN]; 	///< The data itself, variable length.
} ABS_DATA;

/** 
 * The header of the BIR. This type is equivalent to BioAPI's structure 
 * BioAPI_BIR_HEADER. 
 */
typedef struct abs_bir_header {
  ABS_DWORD Length; 	///< Length of Header + Opaque Data
  ABS_BYTE HeaderVersion; 	///< HeaderVersion = 1
  ABS_BYTE Type; 	///< Type = 4 (BioAPI_BIR_DATA_TYPE_PROCESSED)
  ABS_WORD FormatOwner; 	///< FormatOwner = 0x12 (STMicroelectronics)
  ABS_WORD FormatID; 	///< FormatID = 0
  ABS_CHAR Quality; 	///< Quality = -2 (BioAPI_QUALITY is not supported)
  ABS_BYTE Purpose; 	///< Purpose (BioAPI_PURPOSE_xxxx, ABS_PURPOSE_xxxx).
  ABS_DWORD FactorsMask; 	///< FactorsMask = 0x08 (BioAPI_FACTOR_FINGERPRINT)
} ABS_BIR_HEADER;

/** 
 * A container for biometric data. 
 */
typedef struct abs_bir {
  ABS_BIR_HEADER Header; 	///< BIR header
  ABS_BYTE Data[ABS_VARLEN]; 	///< The data composing the fingerprint template.
} ABS_BIR;

struct abs_operation;
typedef struct abs_operation ABS_OPERATION;  /* forward declaration */

/** 
 * A type of the callback function that an application can supply to 
 * the BSAPI to enable itself to display GUI state information to user. 
 * 
 * @param pOperation Pointer to ABS_OPERATION structure used when calling the interactive operation.
 * @param dwMsgID ID of message. See description of ABS_MSG_xxxx constants.
 * @param pMsgData Pointer to data with additional information related with 
 * the message. 
 */
typedef void (BSAPI  *ABS_CALLBACK) ( const ABS_OPERATION*, ABS_DWORD, void*);

/** 
 * Holds common data used by all interactive operation functions.
 */
struct abs_operation {
  ABS_DWORD OperationID; 	///< Unique operation ID or zero.
  void* Context; 	///< User defined pointer, passed into the operation callback.
  ABS_CALLBACK Callback; 	///< Pointer to application-defined function, implementing operation callback.
  ABS_LONG Timeout; 	///< Timeout of user's inactivity in milliseconds
  ABS_DWORD Flags; 	///< Bitmask of flags, tuning the operation process.
} ;

res = ABSEnroll(conn, &op, &tset[slot], 0);

Thanks for posting something
But that posting doesn’t use abs_data or set ABS_VARLEN
(also note, you can highlight code, and press the code button </> to make it easier to read.)

Hi Mark:
Got interrupted with a support call.
The below clarion code is using a different set of group, types with same array style in question.
This has an example of use:
Thanks
~Peter

ABS_BIR_HEADER                          GROUP,TYPE
Length                                   ULONG
HeaderVersion                            BYTE
Type                                     BYTE
FormatOwner                              SHORT
FormatID                                 SHORT
Quality                                  BYTE
Purpose                                  BYTE
FactorsMask                              ULONG
                                        End

ABS_BIR_HEADER_1                        Like(ABS_BIR_HEADER)

ABS_BIR                                 Group, Dim(16), TYPE           !dim(16)
abs_bir_Header                           Long                       !Address(ABS_BIR_HEADER)
abs_bir_Data                             BYTE,DIM(ABS_VARLEN)
                                        End
ABS_BIR_1                               Like(ABS_BIR)


</* Maximal template set size. */
#define TSET_SIZE        16

/* We use trivial template set representation, as an array of pointers 
 * to ABS_BIR. Unused slots are set to NULL. */
static ABS_BIR* tset[TSET_SIZE];

/* 0 - BIR was obtained via a ABS_* call (and thus should be freed
 *     by ABSFree()),
 * 1 - BIR was created manually and should be freed with free(). */
static char tsetAttr[TSET_SIZE];

/* BSAPI session handle. */
static ABS_CONNECTION conn = 0;



/* Pointer to ABS_OPERATION is taken as a parameter by those BSAPI 
 * funtions which work as interactive operation. The main purpose of it is 
 * to pass pointer to the callback function into the interactive functions. 
 *
 * It also allows to specifie some flags and/or timeout.
 *
 * In this sample we reuse this one operation instance. In real complex 
 * application you may need to use special ABS_OPERATION instance for 
 * each BSAPI interactive operation. This allows you to use specialized
 * callback for them, past various flags etc.
 */
static ABS_OPERATION op = { 
    /* ID of the operation. We don't need to identify the operation in this 
     * sample. When non-zero, the ID identifies the operation and allows it
     * to be canceled from any other thread with ABSCancelOperation(). */
    0,         
    
    /* Arbitrary pointer, which allows application to pass any data into
     * the callback. Not used in this sample. */
    NULL,      
    
    /* Pointer to a simple callback implementation function. */
    callback,  
    
    /* Timeout. For example, lets set timeout to 60 sec. Note the value does 
     * not limit how long the operation (e.g. ABSVerify()) can take. The 
     * timeout only specifies time the operation waits for user to put his 
     * finger on a sensor. Zero would mean no timeout (i.e. the operation can 
     * never end if user never puts his finger on the sensor.) */
    60000,
    
    /* By default BSAPI places short time delays between sending some important
     * callback messages. The purpose of this is to guarantee that if multiple
     * messages come very closely in sequence, then the user still has enough
     * time to see all the messages and not just the lat one of the fast
     * sequence.
     *
     * For application developer, this simplifies callback implementation
     * which in most cases can be just showing an appropriate message in a 
     * window or dialog.
     *
     * However the time delays are not needed when user can see all history
     * of the messages, e.g. (as in this sample) the messages are outputted
     * to standard output stream. Hence we disable the time delays with with 
     * the flag ABS_OPERATION_FLAG_LL_CALLBACK here. */
    ABS_OPERATION_FLAG_LL_CALLBACK
};


/* Helper function, asking the user to choose what slot in the template set 
 * to work with. Returns number of the slot or -1 if the slot can not be used.
 */
static int
choose_slot(const char* msg)
{
    int slot;
    
    printf("%s: ", msg);
    scanf("%d", &slot);
    if(slot < 0  ||  slot >= TSET_SIZE) {
        printf("No such slot.\n");
        return -1;
    }
    if(tset[slot] == NULL) {
        printf("Slot %d is not enrolled.\n", slot);
        return -1;
    }
    
    return slot;
}

/* Open BSAPI session. Note that this sample allows only one session
 * at a time to be opened. */
static void 
cmd_open(void)
{
    ABS_STATUS res;
    ABS_DEVICE_LIST* dev_list;
    int dev_index;
    
    printf("Openening a session...\n");
    
    /* Check whether it's not already open. It is possible to use multiple
     * sessions from one process, but it would make this sample much more 
     * copmplex, and most applications do not need that anyway. */
    if(conn != 0) {
        printf("The session is already open.\n");
        return;
    }
    
    /* Enumerate all supported USB devices and decide which one of them to 
     * use. */
    res = ABSEnumerateDevices("usb", &dev_list);
    if(res != ABS_STATUS_OK) {
        printf("ABSEnumerateDevices() failed.\n");
        status_info(res);
        return;
    }
    if(dev_list->NumDevices == 0) {
        printf("No fingerprint device found.\n");
        return;
    }
    if(dev_list->NumDevices == 1) {
        /* There is a single device, so take it. */
        dev_index = 0;
    } else {
        /* There is more then one device connected: Ask user which one
         * of them to use. */
        int i;
        
        printf("Found devices: \n");
        for(i = 0; i < (int)dev_list->NumDevices; i++)
            printf("   %d  %s\n", i, dev_list->List[i].DsnSubString);
        printf("Enter number of device you want to use: ");
        scanf("%d", &dev_index);
        if(dev_index < 0  ||  dev_index >= (int)dev_list->NumDevices) {
            printf("No such device.\n");
            return;
        }
    }
    
    /* Open the selected device. */
    printf("Opening device '%s'...\n", dev_list->List[dev_index].DsnSubString);
    res = ABSOpen(dev_list->List[dev_index].DsnSubString, &conn);
    if(res != ABS_STATUS_OK) {
        ABSFree(dev_list);
        printf("ABSOpen() failed.\n");
        status_info(res);
        return;
    }
    
    /* Release memory allocated for the device list. */
    ABSFree(dev_list);
    
    printf("Opened successfully.\n");
}

/* Close BSAPI session */
static void 
cmd_close(void)
{
    ABS_STATUS res;
    
    printf("Closing the current session...\n");
    
    /* close the connection */    
    res = ABSClose(conn);
    if(res != ABS_STATUS_OK) {
        printf("ABSClose() failed.\n");
        status_info(res);
        return;
    }
    conn = 0;
}

/* Add (enroll) new template into the template set. */
static void
cmd_add(void)
{
    int i;
    int slot = -1;
    ABS_STATUS res;
    
    printf("Add new template...\n");
    
    /* find an empty slot */
    for(i = 0; i < TSET_SIZE; i++) {
        if(tset[i] == NULL) {
            slot = i;
            break;
        }
    }    
    if(slot < 0) {
        printf("Cannot add new template. The template set is full.\n");
        return;
    }
    
    /* enroll the tamplate into the slot */
    res = ABSEnroll(conn, &op, &tset[slot], 0);
    if(res != ABS_STATUS_OK) {
        printf("ABSEnroll() failed.\n");
        status_info(res);
        return;
    }
    
    printf("Successfully enrolled into the template set as slot #%d.\n", slot);
}

/* Import a template from a file into the template set. */
static void
cmd_import(void)
{
    int i;
    int slot = -1;
    char templateFileName[1024];
    FILE *f;
    long fileSize;
    
    printf("Import a template...\n");
    
    /* find an empty slot */
    for(i = 0; i < TSET_SIZE; i++) {
        if(tset[i] == NULL) {
            slot = i;
            break;
        }
    }    
    if(slot < 0) {
        printf("Cannot add new template. The template set is full.\n");
        return;
    }
    
    /* ask user for the filename */
    printf("Please enter template file name: ");
    if (scanf("%s", templateFileName) != 1) {
        printf("Cannot get the file name.\n");
        return;
    }

    f = fopen(templateFileName, "rb");
    if (f == NULL) {
        printf("Cannot open file '%s'.\n", templateFileName);
        return;
    }

    if (fseek(f, 0, SEEK_END) != 0) {
        printf("Cannot seek in file '%s'.\n", templateFileName);
        fclose(f);
        return;
    }

    fileSize = ftell(f);
    if (fileSize < 0) {
        printf("Cannot determine the size of file '%s'.\n", templateFileName);
        fclose(f);
        return;
    }

    if (fseek(f, 0, SEEK_SET) != 0) {
        printf("Cannot seek back in file '%s'.\n", templateFileName);
        fclose(f);
        return;
    }

    tset[slot] = (ABS_BIR*)malloc(fileSize);
    if (tset[slot] == NULL) {
        printf("Cannot allocate %ld bytes.\n", fileSize);
        fclose(f);
        return;
    }

    if (fread(tset[slot], fileSize, 1, f) != 1) {
        printf("Cannot read %ld bytes from file '%s'.\n", fileSize,
            templateFileName);
        free(tset[slot]);
        tset[slot] = NULL;
        fclose(f);
        return;
    }

    tsetAttr[slot] = 1;

    fclose(f);
    printf("Successfully imported into the template set as slot #%d.\n", slot);
}

/* Export a template from the template set into a file. */
static void
cmd_export(void)
{
    int slot;
    char templateFileName[1024];
    FILE *f;

    printf("Exporting a template from the template set...\n");

    /* Ask user which templates to compare */
    slot = choose_slot("Enter slot number of template to export");
    if(slot < 0)
        return;

    /* ask user for the filename */
    printf("Please enter template file name: ");
    if (scanf("%s", templateFileName) != 1) {
        printf("Cannot get the file name.\n");
        return;
    }

    f = fopen(templateFileName, "wb");
    if (f == NULL) {
        printf("Cannot open file '%s'.\n", templateFileName);
        return;
    }

    if (fwrite(tset[slot], tset[slot]->Header.Length, 1, f) != 1) {
        printf("Cannot write %u bytes to file '%s'.\n",
            tset[slot]->Header.Length, templateFileName);
        fclose(f);
        return;
    }

    fclose(f);
    printf("Successfully exported template from the slot #%d to file '%s'.\n",
        slot, templateFileName);
}

/* Remove one slot from the template set */
static void
cmd_delete(void)
{
    int slot;
    
    printf("Delete a template from the template set...\n");
    
    /* Ask user which slot to delete */
    slot = choose_slot("Enter slot number to delete from template set");
    if(slot < 0)
        return;
    
    /* And just do it */
    if (tsetAttr[slot] != 0)
        free(tset[slot]);
    else
        ABSFree(tset[slot]);
    tset[slot] = NULL;
    printf("Successfully deleted slot %d\n", slot);
}

/* Remove all templates stored in the template set */
static void
cmd_delete_all(void)
{
    int i;
    
    printf("Delete all templates from the template set...\n");
    
    /* Remove all templates in the template set */
    for(i = 0; i < TSET_SIZE; i++) {
        if(tset[i] != NULL) {
            if (tsetAttr[i] != 0)
                free(tset[i]);
            else
                ABSFree(tset[i]);
            tset[i] = NULL;
        }
    }
    printf("Successfully deleted all slots\n");
}

/* This function only lists which slots on the template sets are used 
 * (i.e. which contain an enrolled template). */
static void
cmd_list(void)
{
    int i;
    int empty = 1;
    
    printf("Listing which slots are used (enrolled)...\n");
    printf("Enrolled slots: ");
    
    for(i = 0; i < TSET_SIZE; i++) {
        if(tset[i] != NULL) {
            printf("%d ", i);
            empty = 0;
        }
    }
    
    if(empty)
        printf("none\n");
    else
        printf("\n");
}

/* Verify user's finger against one template in the set */
static void 
cmd_verify(void)
{
    int slot;
    ABS_STATUS res;
    ABS_LONG matching_slot;
    
    printf("Verify user's finger against a template in template set...\n");
    
    /* Ask user which template to compare with */
    slot = choose_slot("Enter slot number to match against");
    if(slot < 0)
        return;
    
    /* And just do it. Note that matching_slot is set to index of the 
     * matching slot in the template set or -1 is no one matches. Here 
     * we pass in only the one template we are interested in, so in case of 
     * match it will be zero. */
    res = ABSVerify(conn, &op, 1, &tset[slot], &matching_slot, 0);
    if(res != ABS_STATUS_OK) {
        printf("ABSVerify() failed\n");
        status_info(res);
        return;
    }    
    if(matching_slot == 0) {
        printf("Match\n");
    } else if(matching_slot < 0) {
        printf("No match\n");
    } else {
        /* this never happen */
        assert(0);
    }
}

/* Here we compare the user's finger with all templates stored in the set */
static void
cmd_verify_all(void)
{
    int i;
    ABS_BIR* tmp_tset[TSET_SIZE];
    int tmp_slot[TSET_SIZE];
    ABS_DWORD count = 0;
    ABS_STATUS res;
    ABS_LONG index;
    
    printf("Verify user's finger against all templates in template set...\n");
    
    /* Functions ABSVerify accepts an arbitrary count of templates to verify
     * the scanned finger against. It expects pointers to the templates in an
     * array of pointers to ABS_BIR structures. This matches our template 
     * set representation, however our template set might have some gaps
     * (NULLs) in the array, so we copy the BIR pointers to a temporary array
     * without the gaps (i.e. NULL values can be only on tail of the array). 
     * Therefore we also have to save the original index so we can map the 
     * resulting matching index to the original slot number.
     *
     * During the work we also count how many templates are in the set.
     */
    for(i = 0; i < TSET_SIZE; i++) {
        if(tset[i] != NULL) {
            tmp_tset[count] = tset[i];
            tmp_slot[count] = i;
            count++;
        }
    }
    if(count == 0) {
        printf("The template set is empty.\n");
        return;
    }

    /* Now we can compare the finger against all the templates in the 
     * temporary array */
    res = ABSVerify(conn, &op, count, tmp_tset, &index, 0);
    if(res != ABS_STATUS_OK) {
        printf("ABSVerify() failed\n");
        status_info(res);
        return;
    }
    
    /* Find out the slot number (index in the tset array) */
    if(index >= 0) {
        printf("Slot %d matches.\n", tmp_slot[index]);
    } else {
        printf("No slot matches.\n");
    }
}

/* Here we compare two templates from the template set */
static void
cmd_verify_match(void)
{
    int slot1, slot2;
    ABS_STATUS res;
    ABS_BOOL match;
    
    printf("Comparing two templates in the template set...\n");
    
    /* Ask user which templates to compare */
    slot1 = choose_slot("Enter slot number of template 1 to compare");
    if(slot1 < 0)
        return;
    slot2 = choose_slot("Enter slot number of template 2 to compare");
    if(slot2 < 0)
        return;
    
    /* Now compare the two templates. Note this is not interactive operation.
     * I.e. the user is not asked to manipulate with the sensor, nor the
     * function takes pointer to ABS_OPERATION. */
    res = ABSVerifyMatch(conn, tset[slot1], tset[slot2], &match, 0);
    if(res != ABS_STATUS_OK) {
        printf("ABSVerifyMatch() failed.\n");
        status_info(res);
        return;
    }
    if(match)
        printf("Templates %d and %d do match.\n", slot1, slot2);
    else
        printf("Templates %d and %d do NOT match.\n", slot1, slot2);
}

/* Writes down simple help. */
static void
cmd_help(void)
{
    printf("Press any of the following keys to do the corresponding action:\n");
    printf("   o ... open BSAPI session\n");
    printf("   c ... close the BSAPI session\n");
    printf("   a ... add new template into the template set\n");
    printf("   i ... import a template into the template set\n");
    printf("   e ... export a template from the template set to a file\n");
    printf("   d ... delete template from the template set\n");
    printf("   D ... delete all templates from the template set\n");
    printf("   l ... list templates in the template set\n");
    printf("   v ... verify finger against one template\n");
    printf("   V ... verify finger against complete template set\n");
    printf("   m ... match two templates from the template set\n");
    printf("   h ... writes down this help message\n");
    printf("   q ... quit this sample program\n");
}

int
main(int argc, char** argv)
{
    ABS_STATUS res;
    int i;
    int done = 0;
    char buffer[256];
    
    UNREFERENCED_PARAMETER(argc);
    UNREFERENCED_PARAMETER(argv);
    
    printf(
        "This sample shows BSAPI as it can be used in typical real application\n"
        "The sample keeps a fingerprint template set in memory and provides\n"
        "functions for manipulating with the template set as adding new\n"
        "template into it (enrollment), removing it, various verification\n"
        "and matching functions.\n"
        "\n"
        "Note that when started, it does not open session to the device\n"
        "automatically so before you can use any command operating with\n"
        "the fingerprint device you have to open it with 'o'.\n"
        "\n"
        "In this regard behavior of the sample may differ from real life\n"
        "applications which may call ABSOpen() just after ABSInitialize().\n"
        "\n"
        "This design was chosen so that you can manually close and reopen\n"
        "the session, and that you can see which functions require an open\n"
        "session and which do not.\n"
        "\n"
    );
    
    /* initialize BSAPI */
    res = ABSInitialize();
    if(res != ABS_STATUS_OK) {
        printf("ABSInitilize() failed\n");
        status_info(res);
        return -1;
    }
    
    /* ensure the template set is empty */
    for(i = 0; i < TSET_SIZE; i++)
    {
        tset[i] = NULL;
        tsetAttr[i] = 0;
    }

    /* On the start, always show the help */
    cmd_help();

    while(!done) {
        /* Ask the use what to do... */
        printf("\n");
        printf("\n>> ");
        scanf("%s", buffer);
        
        /* ...and then just do that. */
        switch(buffer[0]) {
            case 'o': cmd_open(); break;
            case 'c': cmd_close(); break;
            case 'a': cmd_add();  break;
            case 'i': cmd_import();  break;
            case 'e': cmd_export();  break;
            case 'd': cmd_delete(); break;
            case 'D': cmd_delete_all(); break;
            case 'l': cmd_list(); break;
            case 'v': cmd_verify(); break;
            case 'V': cmd_verify_all(); break;
            case 'm': cmd_verify_match(); break;
            case 'q': done = 1; break;
            
            case '?':
            case 'h': cmd_help(); break;
            
            default:  
                printf("Unknown command. Press 'h' to get help.\n"); 
                break;
        }
    }

    /* Release any templates kept in the template set. */
    for(i = 0; i < TSET_SIZE; i++) {
        if(tset[i] != NULL) {
            if (tsetAttr[i] != 0)
                free(tset[i]);
            else
                ABSFree(tset[i]);
            tset[i] = NULL;
        }
    }
    
    /* If BSAPI session is opened, close it */
    if(conn != 0)
        cmd_close();
    
    /* Free any resources allocated in ABSInitialize. */
    ABSTerminate();
    
    return 0;
}

You don’t have an array of groups but instead it’s an array of pointers to the variable length blocks of memory. You can do this in Clarion by using an array of longs to keep track the address of the memory blocks.

The API allocates the memory if you use ABSEnroll() (maybe other methods too), and you have to allocate memory if you load templates from a file. The example uses another array to track which method was used to allocate the template memory for the “slot”.

It looks like this in memory:
HEADER (size(Header) bytes long

DATA (variable, Header.Length bytes long)


There are still quite a few unknowns but consider this and see if it helps.

TSET_SIZE   Equate(16)  
               
ABS_BIR_HEADER_TYPE                    GROUP,TYPE !changed this because it'll clash with ABS_BIR element
Length                                   ULONG    !you might run into problems with the default packing (byte) of the Clarion compiler
HeaderVersion                            BYTE     
Type                                     BYTE
FormatOwner                              SHORT
FormatID                                 SHORT
Quality                                  BYTE
Purpose                                  BYTE
FactorsMask                              ULONG
                                       End
            

   !ABS_BIR_HEADER_1                        Like(ABS_BIR_HEADER)

absBirHeader                            &ABS_BIR_HEADER_TYPE
    
ABS_BIR                                 Group, TYPE                  !need the C def
abs_bir_Header                           Like(ABS_BIR_HEADER_TYPE)   !Address(ABS_BIR_HEADER) Are you sure?
abs_bir_Data                             BYTE,DIM(ABS_VARLEN)        !this will be the first byte of the data
                                            End
    
    

tset Long, Dim(TSET_SIZE)   !This array will contain the address of the first byte of the block of memory for the template

  Code                                                               
  ...... missing stuff

  !/* enroll the tamplate into the slot */ 
  ... setup op....
  slot = SomeEmptySlot
  res = ABSEnroll(conn, Address(op), Address(tset[slot]), 0) !How did you prototype this
 
  !The api allocates memory and puts the address of the template into that element
  !to read the header you could do this:
  absBirHeader &= (tset[slot])  
  
  !now you can read the length of the data, it starts just after the header
  message('the length is: ' &absBirHeader.length)
  
  !any memory allocated for the template by ABSEnroll() must be freed with ABSFree()

Larry

Thanks Larry this was very helpful, it isn’t working yet … I am going through and making some corrections.

but instead it’s an array of pointers to the variable length blocks of memory.
Bingo!

Larry to answer your first question on header: this is in the header types library. There is no direct reference in any .h files with this name “BioAPI_BIR_HEADER” only in this descriptive paragraph, so I conclude the header is defined as abs_bir_header and is referenced “header” in abs_bir.

/** 
 * The header of the BIR. This type is equivalent to BioAPI's structure 
 * BioAPI_BIR_HEADER. 
 */
typedef struct abs_bir_header {
  ABS_DWORD Length; 	///< Length of Header + Opaque Data
  ABS_BYTE HeaderVersion; 	///< HeaderVersion = 1
  ABS_BYTE Type; 	///< Type = 4 (BioAPI_BIR_DATA_TYPE_PROCESSED)
  ABS_WORD FormatOwner; 	///< FormatOwner = 0x12 (STMicroelectronics)
  ABS_WORD FormatID; 	///< FormatID = 0
  ABS_CHAR Quality; 	///< Quality = -2 (BioAPI_QUALITY is not supported)
  ABS_BYTE Purpose; 	///< Purpose (BioAPI_PURPOSE_xxxx, ABS_PURPOSE_xxxx).
  ABS_DWORD FactorsMask; 	///< FactorsMask = 0x08 (BioAPI_FACTOR_FINGERPRINT)
} ABS_BIR_HEADER;

/** 
 * A container for biometric data. 
 */
typedef struct abs_bir {
  ABS_BIR_HEADER Header; 	///< BIR header
  ABS_BYTE Data[ABS_VARLEN]; 	///< The data composing the fingerprint template.
} ABS_BIR;

Larry>>There are still quite a few unknowns but consider this and see if it helps.
Peter>> I like adding the _TYPE to the group structure and I am editing to use the reference symbol instead of like
Larry>>res = ABSEnroll(conn, Address(op), Address(tset[slot]), 0) !How did you prototype this
Peter>>ABSEnroll(LONG,LONG,LONG,ULONG),short,Pascal,Raw,DLL(dll_mode)
Peter>>Clarion use in embed: ABS_Status=ABSEnroll(ABS_Handle,Address(ABS_OPERATION_1),ADDRESS(TSET[1]),0)
Peter>>This is when I GPF. I need to look at ABS_OPERATION_1 and apply what I just learned.

ABS_Operation                           GROUP,TYPE
OperationID                             ULONG
Context                                 Long
Callback                                Like(ABS_CallbackID)
TimeOut                                 LONG
Flags                                   ULONG
                                        End

ABS_OPERATION_1                         Like(ABS_OPERATION)
Peter>>I changed to: (basically using & for reference as opposed to Like()
ABS_BIR_TYPE                                 Group, TYPE           !Removed DIM(16)
abs_bir_Header                           Long                       !Address(ABS_BIR_HEADER)
abs_bir_Data                             BYTE,DIM(ABS_VARLEN)
                                        End
                                        
ABS_BIR                               &ABS_BIR_TYPE

ABS_CallbackID                          GROUP,TYPE
ID                                      LONG
                                        END

ABS_CallbackAdress                      &ABS_CallbackID

ABS_Context                             GROUP,TYPE
Data                                    CSTRING(30)
                                        End

ABS_Context_Data                        Group(ABS_Context)
Value                                    CSTRING(30)
                                        End

ABS_Operation_Type                     GROUP,TYPE
OperationID                             ULONG
Context                                 Long
Callback                                Like(ABS_CallbackID)
TimeOut                                 LONG
Flags                                   ULONG
                                        End

ABS_OPERATION                         &ABS_Operation_Type

~Peter

Peter,

Too many things to comment on at one time. First post the C API defs of EVERYTHING in question and how you did it in Clarion. The way you defined and used abs_operation is most likely not correct.

Larry

Thanks Larry,

Because the names of the C API end in .h I changed the names to _h.clw.
I attached all so you can reference everything that may come into question.

bsgui_h.clw (1.5 KB)bsapi_h.clw (18.9 KB)bytypes_h.clw (30.8 KB)

These are my clarion definitions and prototypes.
definition_prototypes.clw (19.8 KB)

This is the callback function.
CallBackFunction.clw (7.3 KB)
These functions work:

ABS_Status=ABS_Initialize(DeviceInterface)
ABS_Status=ABS_Open(DeviceInterface,ABS_Handle)
ABSFree(ABS_Handle)

This is where I prepare for enroll function the device activates for enrollment then program crashes:

ABS_CallbackAdress=Address(ABS_Callback)
Clear(ABS_Context_Data.Value)
ABS_OPERATION.OperationID=0
ABS_OPERATION.Context=Address(ABS_Context_Data)                      !Null
ABS_OPERATION.Callback=Address(ABS_CALLBACK)
ABS_OPERATION.TimeOut=18000
ABS_OPERATION.Flags=ABS_OPERATION_FLAG_LL_CALLBACK

ABS_Status=ABSEnroll(ABS_Handle,Address(ABS_OPERATION),ADDRESS(TSET[1]),0)

~Peter

ABS_Operation_Type                     GROUP,TYPE
OperationID                             ULONG
Context                                 Long
Callback                                Like(ABS_CallbackID)
TimeOut                                 LONG
Flags                                   ULONG
                                        End

ABS_OPERATION                         &ABS_Operation_Type

I don’t see where your code allocates ABS_OPERATION. Without a New(ABS_OPERATION) this line (from above) will GPF:

ABS_OPERATION.OperationID=0

Larry