Sample UDF
Top  Previous  Next

Syntax  
 
(UDF('exe-name','parameter-list'))  
(UDF('-exe-name','parameter-list'))  
(UDF('+exe-name','parameter-list'))  
(UDF('@dll-name','parameter-list'))  
 
Options  
 
+, -, @, or nothing  
If you do not specify a plus or minus, the function is hidden when it runs; this setting is the default. A plus (+) runs the function in a normalized window. A minus (-) runs the function as a minimized icon. The @ sign is used to indicate that the UDF being called is a DLL. This only applies to Windows and is not available to the DOS version of R:BASE.  
 
exe-name or dll-name  
Specifies the name of the UDF (the name of the executable file or DLL into which you have compiled and linked your program). Under Windows this can be a Windows program. When using DLL's you MUST include the .DLL extension or the DLL may not be executed.  
 
parameter-list  
Specifies a text string that is sent to the program or DLL.  
 
About the UDF Function  
 
This document covers the use of executables as UDFs.  
 
You can use a user-defined function (UDF) anywhere you can use a function in R:BASE.  
 
·Forms  
·Reports  
·Entry/exit procedures  
·Applications  
·Commands  
 
R:BASE UDF's are handled slightly differently depending on which version of the R:BASE engine is in use. R:BASE or Runtime for Windows passes the command to the RBGUDF.EXE file. R:BASE or Runtime for DOS passes the  
command to the UDF.EXE. Either file can be found in the same directory as the main R:BASE or Runtime executable.  
 
When used with executables the parameter-list, from the UDF syntax, acts exactly as if you typed it at the DOS prompt. DOS may limit the size of your parameter-list. Remember to account for the length of the executable name as well as the memory address (eight characters) plus the spaces between the .EXE name, the parameter list, and the address name. The parameter list can be space delimited with EXE UDF's.  
 
You can write the UDF.EXE file in any language that allows writing to far pointers, such as Microsoft C. UDF.EXE files require protected mode libraries. You can return only 1,500 bytes of text data to R:BASE; that is, when you copy your results to either the address passed in or the shared-memory segment, you must not write more than 1,499 characters plus  
the NULL terminator (/0). If you write more than 1,500 total characters to the DOS address you will corrupt the R:BASE variables and R:BASE might "hang."  
 
If you forget the NULL terminator (/0) you will probably get high-order ASCII characters in your text variable. To pass back multiple values, delimit them with commas and then use other R:BASE functions to pull out the values. R:BASE stops looking at the returned text when it first encounters a NULL (/0). If your DOS UDF.EXE file hangs, It is very likely that R:BASE will as well.  
 
The size of a UDF is limited by the amount of available memory. Keep your executable files as small as possible. You will have to experiment to determine the maximum possible memory in a given situation. You can have different amounts of available memory at different times in an R:BASE session. Because  
you had an amount of memory available at one point in an R:BASE session does not mean that you will have the same amount of memory available in your next R:BASE session.  
 
If your UDF fails to write to the memory given to it, then the UDF function in R:BASE sets the variable to NULL (-0-). You could use this in your UDF.EXE file to show whether the UDF failed. UDFs treat error variables the same as R:BASE does; therefore, you can have your application tell you if the UDF was successful or not by using the R:BASE error variable and the compiler's function that allows the return of error variables, such as Microsoft C exit( ) function to return the ERRORLEVEL. R:BASE places the ERRORLEVEL value in the R:BASE error variable.  
 
The following example uses a UDF named dwrd to convert a currency value to words:  
 
SET VAR v1=(UDF('dwrd','$1,456.99'))  
 
If you execute the above command and then enter SHOW VARIABLE at the R> prompt, you see the following output:  
 
This UDF has been included with the program files for both DOS and OS/2: DWRD.C for DOS, and DWRD2.C for OS/2.  
 
Examples  
 
The following is a R:BASE command that calls the UDF named random.  
 
SET VAR v1 = (UDF('random', '25 345'))  
 
The following are the command line arguments for the UDF named random for DOS as seen by the UDF code:  
 
DOS  
argv[0] = random  
argv[1] = 25  
argv[2] = 345  
argv[3] = A345BD3456  
argc = 4  
 
Argument 0 is the name of the executable. Argument 1 is the first parameter. Argument 2 is the second parameter. Argument 3 is the memory address. This brings the argument count to 4.  
 
The following example uses a UDF named DWRD.EXE to convert a currency value to words:  
 
SET VAR v1=(UDF('dwrd','$1,456.99'))  
SHOW VAR v1  
 
Result: v1= one thousand, four hundred fifty six dollars and ninety nine cents  
 
The following example uses the DWRD.DLL to accomplish the same function.  
 
SET VAR v1=(UDF('@dwrd.dll','$1,456.99'))  
SHOW VAR v1  
 
Result: v1= one thousand, four hundred fifty six dollars and ninety nine cents  
 
Source Code  
 
What follows is the source code for the dwrd.exe sample UDF, shipped with DOS products, and the source code for the dwrd.dll sample UDF, shipped with Windows products.  
 

 
/*  
* Copyright 2001 by R:BASE Technologies, Inc.  
* Author: Wayne J. Erickson 12 Apr 1991  
*  
************************************************************************  
* * Routine: dwrd2 *** DOS VERSION ***  
* * Purpose: convert a currency value to words  
*  
* Input Parameters:  
* name Brief description  
* -------------- ------------------------------------------------  
* value Currency string to be parsed  
* Shared Segment Shared memory segment to place the parsed string  
*  
************************************************************************  
*/  
 
#include  
#include  
#include  
 
void conout(char *, int);  
void crlf(void);  
int lenstr(char *, int);  
void dwrd(char *, char *);  
 
cdecl main(argc,argv)  
int argc;  
char * argv[];  
{  
long int i4;  
char *pt;  
char wordnum[160];  
int lw;  
 
/* Get the argument count. */  
if(argc <= 1) {  
conout("DWRD number pointer", 19);  
crlf();  
goto done;  
}  
 
/* Do the conversion */  
dwrd(argv[1], wordnum);  
 
/* Display the result */  
lw = strlen(wordnum);  
if (argc == 2) {  
conout(wordnum, lw);  
crlf();  
}  
 
/* See if there was an address to store the result */  
if(argc > 2) {  
i4 = atol(argv[2]);  
pt = (char *)i4;  
memcpy(pt, wordnum, lw+1);  
}  
done:  
return(0);  
}  
 
 
/**** Start of DWRD function ****/  
void dwrd(strin, strout)  
char *strin;  
char *strout;  
{  
int lstr;  
static char numbers[20][10] = {  
" ","one ","two ",  
"three ","four ","five ",  
"six ","seven ","eight ",  
"nine ","ten ","eleven ",  
"twelve ","thirteen ","fourteen ",  
"fifteen ","sixteen ","seventeen ",  
"eighteen ","nineteen "};  
 
static char tenvals[10][10] = {  
"no ","ten ","twenty ",  
"thirty ","forty ","fifty ",  
"sixty ","seventy ","eighty ",  
"ninety "};  
char blank = ' ';  
char comma = ',';  
char dsign = '$';  
char dot = '.';  
char minus = '-';  
char ch;  
char tmoney[16];  
int offset;  
int tens;  
int lw, ls, n, intch, l;  
 
/* CONVERT THE NUMBER. */  
 
tens = 0;  
memset(tmoney, ' ', 16);  
lw = 0;  
lstr = strlen(strin);  
ls = 16 - lstr + 1;  
strcpy(&tmoney[ls-1],strin);  
 
/* PICK OFF THE CHARACTERS. */  
 
n = ls - 1;  
next_digit:  
n++;  
if(n > 16) goto cleanup;  
ch = tmoney[n-1];  
 
/* SKIP THE COSMETIC CHARACTERS. */  
 
if((ch == blank) || (ch == comma) || (ch == dsign)) goto next_digit;  
if(ch == minus) {  
memcpy(&strout[(lw+1)-1], "minus ", 6);  
lw = lw + 6;  
goto next_digit;  
}  
if((n == 4) || (n == 8) || (n == 12)) tens = 1;  
 
/* SPECIAL STUFF WHEN WE HIT THE DECIMAL POINT. */  
 
if(ch == dot) {  
tens = 1;  
if(lw == 0) {  
memcpy(&strout[(lw+1)-1], "zero ", 5);  
lw = lw + 5;  
}  
memcpy(&strout[(lw+1)-1], "dollars and ", 12);  
lw = lw + 12;  
if(tmoney[(n+1)-1] == '0') {  
if(tmoney[(n+2)-1] == '0') {  
memcpy(&strout[(lw+1)-1], "zero ", 5);  
lw = lw + 5;  
n = n + 2;  
}  
}  
goto next_digit;  
}  
 
/* CONVERT A CHARACTER INTO AN OFFSET. */  
 
intch = ch - 48;  
if(tens) {  
if(intch <= 1) {  
offset = 0;  
if(intch == 1) offset = 10;  
n = n + 1;  
ch = tmoney[(n)-1];  
intch = ch - 48 + offset;  
}  
else {  
l = lenstr(tenvals[(intch+1) - 1], 10);  
if(l > 0) {  
memcpy(&strout[(lw+1)-1], tenvals[(intch+1)-1], l+1);  
lw = lw + l + 1;  
}  
tens = 0;  
goto next_digit;  
}  
}  
l = lenstr(numbers[(intch+1)-1], 10);  
if(l > 0) {  
memcpy(&strout[(lw+1)-1], numbers[(intch+1)-1], l+1);  
lw = lw + l + 1;  
}  
tens = 0;  
if(((n == 3) || (n == 7) || (n == 11)) && (intch != 0)) {  
memcpy(&strout[(lw+1)-1], "hundred ", 8);  
lw = lw + 8;  
}  
if(n == 5) {  
memcpy(&strout[(lw+1)-1], "million ", 8);  
lw = lw + 8;  
}  
if(n == 9) {  
memcpy(&strout[(lw+1)-1], "thousand ", 9);  
lw = lw + 9;  
}  
goto next_digit;  
cleanup:  
memcpy(&strout[(lw+1)-1], "cents", 5);  
lw = lw + 5;  
 
/* Add the null terminator */  
strout[(lw+1)-1] = '\0';  
 
/* ALL DONE. */  
 
return;  
}  
/**** End of DWRD function ****/  
 
 
/**** Start of CONOUT function ****/  
void conout(str, count)  
char *str;  
int count;  
{  
int i;  
for (i = 0; i < count; i++) {  
putchar(str[i]);  
}  
return;  
}  
/**** End of CONOUT function ****/  
 
/**** Start of CRLF function ****/  
void crlf()  
{  
putchar('\r');  
putchar('\n');  
return;  
}  
/**** End of CRLF function ****/  
 
/**** Start of LENSTR function ****/  
int lenstr(str, count)  
char *str;  
int count;  
{  
int i;  
 
i = count - 1;  
while (i >= 0) {  
if (str[i] != ' ') break;  
i--;  
}  
return (i+1);  
}  
/**** End of LENSTR function ****/  
 
 
 
#include  
/*  
* Copyright 2001 R:BASE Technologies, Inc.  
* Author: Wayne J. Erickson 18 October 1999  
*  
************************************************************************  
*  
* Routine: dwrd *** DLL VERSION ***  
*  
* Purpose: convert a currency value to words  
*  
* Input Parameters:  
* name Brief description  
* -------------- ------------------------------------------------  
* value Currency string to be parsed  
* Shared Segment Shared memory segment to place the parsed string  
*  
*  
************************************************************************  
*/  
 
#include  
void dwrd(char *, char *);  
int lenstr(char *, int);  
 
#pragma hdrstop  
 
//---------------------------------------------------------------------------  
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)  
{  
return 1;  
}  
 
//---------------------------------------------------------------------------  
extern "C" __declspec(dllexport) int WINAPI RbDllExec(const HWND dc,const char *in, int inlen, char *out, int outlen)  
{  
int returnValue = 0;  
char instr[80];  
char wordnum[160];  
 
// Put the input string in a null terminated string  
memcpy(instr, in, inlen);  
instr[inlen] = '\0';  
 
// Convert to a text string  
dwrd(instr, wordnum);  
 
// Return the result  
outlen = strlen(wordnum);  
if (outlen)  
memcpy(out, wordnum, outlen);  
// returnValue = MessageBox(dc, wordnum,"Result value",MB_OK);  
// returnValue = 0;  
return returnValue;  
}  
 
//---------------------------------------------------------------------------  
extern "C" __declspec(dllexport) int WINAPI RbDllVersion(void)  
{  
return 100;  
}  
 
/**** Start of DWRD function ****/  
void dwrd(char *strin,char *strout)  
{  
int lstr;  
static char numbers[20][11] = {  
" ","one ","two ",  
"three ","four ","five ",  
"six ","seven ","eight ",  
"nine ","ten ","eleven ",  
"twelve ","thirteen ","fourteen ",  
"fifteen ","sixteen ","seventeen ",  
"eighteen ","nineteen "};  
 
static char tenvals[10][11] = {  
"no ","ten ","twenty ",  
"thirty ","forty ","fifty ",  
"sixty ","seventy ","eighty ",  
"ninety "};  
char blank = ' ';  
char comma = ',';  
char dsign = '$';  
char dot = '.';  
char minus = '-';  
char ch;  
char tmoney[16];  
int offset;  
int tens;  
int lw, ls, n, intch, l;  
 
/* CONVERT THE NUMBER. */  
 
tens = 0;  
memset(tmoney, ' ', 16);  
lw = 0;  
lstr = strlen(strin);  
ls = 16 - lstr + 1;  
strcpy(&tmoney[ls-1],strin);  
 
/* PICK OFF THE CHARACTERS. */  
 
n = ls - 1;  
next_digit:  
n++;  
if(n > 16) goto cleanup;  
ch = tmoney[n-1];  
 
/* SKIP THE COSMETIC CHARACTERS. */  
 
if((ch == blank) || (ch == comma) || (ch == dsign)) goto next_digit;  
if(ch == minus) {  
memcpy(&strout[(lw+1)-1], "minus ", 6);  
lw = lw + 6;  
goto next_digit;  
}  
if((n == 4) || (n == 8) || (n == 12)) tens = 1;  
 
/* SPECIAL STUFF WHEN WE HIT THE DECIMAL POINT. */  
 
if(ch == dot) {  
tens = 1;  
if(lw == 0) {  
memcpy(&strout[(lw+1)-1], "zero ", 5);  
lw = lw + 5;  
}  
memcpy(&strout[(lw+1)-1], "dollars and ", 12);  
lw = lw + 12;  
if(tmoney[(n+1)-1] == '0') {  
if(tmoney[(n+2)-1] == '0') {  
memcpy(&strout[(lw+1)-1], "zero ", 5);  
lw = lw + 5;  
n = n + 2;  
}  
}  
goto next_digit;  
}  
 
/* CONVERT A CHARACTER INTO AN OFFSET. */  
 
intch = ch - 48;  
if(tens) {  
if(intch <= 1) {  
offset = 0;  
if(intch == 1) offset = 10;  
n = n + 1;  
ch = tmoney[(n)-1];  
intch = ch - 48 + offset;  
}  
else {  
l = lenstr(tenvals[(intch+1) - 1], 10);  
if(l > 0) {  
memcpy(&strout[(lw+1)-1], tenvals[(intch+1)-1], l+1);  
lw = lw + l + 1;  
}  
tens = 0;  
goto next_digit;  
}  
}  
l = lenstr(numbers[(intch+1)-1], 10);  
if(l > 0) {  
memcpy(&strout[(lw+1)-1], numbers[(intch+1)-1], l+1);  
lw = lw + l + 1;  
}  
tens = 0;  
if(((n == 3) || (n == 7) || (n == 11)) && (intch != 0)) {  
memcpy(&strout[(lw+1)-1], "hundred ", 8);  
lw = lw + 8;  
}  
if(n == 5) {  
memcpy(&strout[(lw+1)-1], "million ", 8);  
lw = lw + 8;  
}  
if(n == 9) {  
memcpy(&strout[(lw+1)-1], "thousand ", 9);  
lw = lw + 9;  
}  
goto next_digit;  
cleanup:  
memcpy(&strout[(lw+1)-1], "cents", 5);  
lw = lw + 5;  
 
/* Add the null terminator */  
strout[(lw+1)-1] = '\0';  
 
/* ALL DONE. */  
 
return;  
}  
/**** End of DWRD function ****/  
 
/**** Start of LENSTR function ****/  
int lenstr(char *str, int count)  
{  
int i;  
 
i = count - 1;  
while (i >= 0) {  
if (str[i] != ' ') break;  
i--;  
}  
return (i+1);  
}  
/**** End of LENSTR function ****/  
 

 
Making and Setting DLL  
 
You can use a DLL (Dynamic Link Library) which you make for use in R:BASE Turbo V-8. DLLs which you make can be used column and variable objects in Forms, Reports and Labels.  
 
If you make a DLL, you must follow some rules of making DLLs.  
 
Rules of making DLLs  
 
Value of DLL's version      
 
·int WINAPI RbDllVersion(void);      
·You must specify to return 100.      
 
DLL name which is displayed in the Combo Box      
 
·const char* WINAPI RbDllSpec(void);      
·You designate the DLL function's name which is displayed in the Combo Box.      
 
DLL's ID      
 
·int WINAPI RbDllId(void);      
·It is the identity number of the DLL. You designate to return a number form 2 to 127.      
 
The function called by Form when drawing field      
 
·int WINAPI RbDllDraw(const char*, const HDC, long, long, long, long)      
·Return value : 0 success / Not 0 fails      
·Argument : const char* Data strings  
·const HDC Device Context handle  
·long Left upper corner X position of object  
·long Left upper corner Y position of object  
·long Right lower corner X position of object  
·long Right lower corner Y position of object  
 
The function called by Report or Label when drawing field      
 
·int WINAPI RbDllDrawP(const char*, const HDC, long, long, long, long)      
·Return value : 0 success / Not 0 fails      
·Argument : const char* Data strings      
·const HDC Device Context handle      
·long Left upper corner X position of object      
·long Left upper corner Y position of object      
·long Right lower corner X position of object      
·long Right lower corner Y position of object