Chapter Contents

Previous

Next
SAS Companion for the Microsoft Windows Environment

The SASCBTBL Attribute Table

Because the MODULExy routine invokes an external function that the SAS System knows nothing about, you must supply information about the function's arguments so that the MODULExy routine can validate them and convert them, if necessary. For example, suppose you want to invoke a routine that requires an integer as an argument. Because the SAS System uses floating point values for all of its numeric arguments, the floating point value must be converted to an integer before you invoke the external routine. The MODULExy routine looks for this attribute information in an attribute table referred to by the SASCBTBL fileref.

The attribute table is a sequential text file that contains descriptions of the routines you can invoke with the MODULExy function. The function of the table is to define how the MODULExy function should interpret its supplied arguments when building a parameter list to pass to the called DLL routine.

The MODULExy routines locate the table by opening the file referred to by the SASCBTBL fileref. If you do not define this fileref, the MODULExy routines simply call the requested DLL routine without altering the arguments.

CAUTION:
Using the MODULExy functions without defining an attribute table can cause the SAS System to crash or force you to reset your computer. You need to use an attribute table for all external functions that you want to invoke.  [cautionend]

The attribute table should contain a description for each DLL routine you intend to call (using a ROUTINE statement) plus descriptions of each argument associated with that routine (using ARG statements).


Syntax of the Attribute Table

At any point in the attribute table file, you can create a comment using an asterisk (*) as the first nonblank character of a line or after the end of a statement (following the semicolon). You must end the comment with a semicolon.

ROUTINE Statement

The syntax of the ROUTINE statement is

ROUTINE name MINARG=minarg MAXARG=maxarg
<CALLSEQ=BYVALUE|BYADDR>
<STACKORDER=R2L|L2R>
<STACKPOP=CALLER|CALLED>
<TRANSPOSE=YES|NO> <MODULE=DLL-name>
<RETURNS=SHORT|USHORT|LONG|ULONG |DOUBLE|DBLPTR|CHAR<n>>
<RETURNREGS=DXAX>;

The following are descriptions of the ROUTINE statement attributes:

ROUTINE name
starts the ROUTINE statement. You need a ROUTINE statement for every DLL function you intend to call using the MODULExy function. The value for name must match the routine name or ordinal you specified as part of the 'module' argument in the MODULExy function, where module is the name of the DLL (if not specified by the MODULE attribute, described later) and the routine name or ordinal. For example, to be able to specify KERNEL32,GetPath in the MODULExy function call, the ROUTINE name should be GetPath.

The name argument is case sensitive, and is required for the ROUTINE statement.

MINARG=minarg
specifies the minimum number of arguments to expect for the DLL routine. In most cases, this value will be the same as MAXARG; but some routines do allow a varying number of arguments. This is a required attribute.

MAXARG=maxarg
specifies the maximum number of arguments to expect for the DLL routine. This is a required attribute.

CALLSEQ=BYVALUE | BYADDR
indicates the calling sequence method used by the DLL routine. Specify BYVALUE for call-by-value and BYADDR for call-by-address. The default value is BYADDR.

FORTRAN and COBOL are call-by-address languages; C is usually call-by-value, although a specific routine might be implemented as call-by-address.

The MODULE routine does not require that all arguments use the same calling method; you can identify any exceptions by using the BYVALUE and BYADDR options in the ARG statement, described later in this section.

STACKORDER=R2L | L2R
indicates the order of arguments on the stack as expected by the DLL routine. R2L places the arguments on the stack according to C language conventions. The last argument (right-most in the call syntax) is pushed first, the next-to-last argument is pushed next, and so on, so that the first argument is the first item on the stack when the external routine takes over. R2L is the default value.

L2R places the arguments on the stack in reverse order, pushing the first argument first, the second argument next, and so on, so that the last argument is the first item on the stack when the external routine takes over. Pascal uses this calling convention, as do some C routines.

STACKPOP=CALLER | CALLED
specifies which routine, the caller routine or the called routine, is responsible for popping the stack (updating the stack pointer) upon return from the routine. The default value is CALLER (that is, the code that calls the routine). Some routines, such as those that use Microsoft's __stdcall attribute with 32-bit compilers, require the called routine to pop the stack.

TRANSPOSE=YES | NO
specifies whether to transpose matrices with both more than one row and more than one column before calling the DLL routine. This attribute applies only to routines called from within PROC IML with MODULEI, MODULEIC, and MODULEIN.

TRANSPOSE=YES is necessary when calling a routine written in a language that does not use row-major order to store matrices. (For example, FORTRAN uses column-major order.)

For example, consider this matrix with three columns and two rows:

            columns
            1   2   3
       --------------
 rows  1 | 10  11  12
       2 | 13  14  15

PROC IML stores this matrix in memory sequentially as 10, 11, 12, 13, 14, 15. However, FORTRAN routines will expect this matrix as 10, 13, 11, 14, 12, 15.

The default value is NO.

MODULE=DLL-name
names the executable module (the DLL) in which the routine resides. The MODULExy function searches the directories named by the PATH environment variable. If you specify the MODULE attribute here in the ROUTINE statement, then you do not need to include the module name in the module argument to the MODULE function (unless the DLL routine name you are calling is not unique in the attribute table). The MODULE function is described in MODULExy.

You can have multiple ROUTINE statements that use the same MODULE name. You can also have duplicate ROUTINE names that reside in different DLLs.

RETURNS=SHORT | USHORT | LONG | ULONG | DOUBLE | DBLPTR | CHAR<n>
specifies the type of value that the DLL routine returns. This value will be converted as appropriate, depending on whether you use MODULEC (which returns a character) or MODULEN (which returns a number). The possible return value types are

SHORT
short integer

USHORT
unsigned short integer

LONG
long integer

ULONG
unsigned long integer

DOUBLE
double-precision floating point number

DBLPTR
a pointer to a double-precision floating point number (instead of using a floating point register). Consult the documentation for your DLL routine to determine how it handles double-precision floating point values.

CHARn
pointer to a character string up to n bytes long. The string is expected to be null-terminated and will be blank-padded or truncated as appropriate. If you do not specify n, the MODULExy function uses the maximum length of the receiving SAS character variable.

If you do not specify the RETURNS attribute, you should invoke the routine with only the MODULE and MODULEI call routines. You will get unpredictable values if you omit the RETURNS attribute and invoke the routine using the MODULEN/MODULEIN or MODULEC/MODULEIC functions.

The ROUTINE statement must be followed by as many ARG statements as you specified in the MAXARG= option. The ARG statements must appear in the order that the arguments will be specified within the MODULExy routines.

ARG Statement

The syntax for each ARG statement is

ARG argnum NUM|CHAR <INPUT|OUTPUT|UPDATE> <NOTREQD|REQUIRED> <BYADDR|BYVALUE> <FDSTART> <FORMAT=format>;

Here are the descriptions of the ARG statement attributes:

ARG argnum
defines the argument number. This a required attribute. Define the arguments in ascending order, starting with the first routine argument (ARG 1).

NUM | CHAR
defines the argument as numeric or character. This is a required attribute.

If you specify NUM here but pass the routine a character argument, the argument is converted using the standard numeric informat. If you specify CHAR here but pass the routine a numeric argument, the argument is converted using the BEST12 informat.

INPUT | OUTPUT | UPDATE
indicates the argument is either input to the routine, an output argument, or both. If you specify INPUT, the argument is converted and passed to the DLL routine. If you specify OUTPUT, the argument is not converted, but is updated with an outgoing value from the DLL routine. If you specify UPDATE, the argument is converted and passed to the DLL routine and updated with an outgoing value from the routine.

You can specify OUTPUT and UPDATE only with variable arguments (that is, no constants or expressions).

NOTREQD | REQUIRED
indicates if the argument is required. If you specify NOTREQD, then MODULExy can omit the argument. If other arguments follow the omitted argument, indicate the omitted argument by including an extra comma as a placeholder. For example, to omit the second argument to routine XYZ, you would specify:
call module('XYZ',1,,3);
CAUTION:
Be careful when using NOTREQD; the DLL routine must not attempt to access the argument if it is not supplied in the call to MODULExy. If the routine does attempt to access it, your system is likely to crash.   [cautionend]
The REQUIRED attribute indicates that the argument is required and cannot be omitted. REQUIRED is the default value.

BYADDR | BYVALUE
indicates the argument is passed by reference or by value.

BYADDR is the default value unless CALLSEQ=BYVALUE was specified in the ROUTINE statement, in which case BYVALUE is the default. Specify BYADDR when using a call-by-value routine that also has arguments to be passed by address.

FDSTART
indicates that the argument begins a block of values that is grouped into a structure whose pointer is passed as a single argument. Note that all subsequent arguments are treated as part of that structure until the MODULExy function encounters another FDSTART argument.

FORMAT=format
names the format that presents the argument to the DLL routine. Any SAS Institute-supplied formats, PROC FORMAT-style formats, or SAS/TOOLKIT formats are valid. Note that this format must have a corresponding valid informat if you specified the UPDATE or OUTPUT attribute for the argument.

The FORMAT= attribute is not required, but is recommended, since format specification is the primary purpose of the ARG statements in the attribute table.

CAUTION:
Using an incorrect format can produce invalid results or cause a system crash.   [cautionend]


The Importance of the Attribute Table
MODULExy routines rely heavily on the accuracy of the information in the attribute table. If this information is incorrect, unpredictable results can occur (including a system crash).

Consider an example routine xyz that expects two arguments: an integer and a pointer. The integer is a code indicating what action takes place. For example, action 1 means that a 20-byte character string is written into the area pointed to by the second argument, the pointer.

Now suppose you call xyz using the MODULE routine but indicating in the attribute table that the receiving character argument is only 10 characters long:

routine xyz minarg=2 maxarg=2;
arg 1 input num byvalue format=ib4.;
arg 2 output char format=$char10.;
Regardless of the value given by the LENGTH statement for the second argument to MODULE, MODULE passes a pointer to a 10-byte area to the xyz routine. If xyz writes 20 bytes at that location, the 10 bytes of memory following the string provided by MODULE are overwritten, causing unpredictable results:
data _null_;
    length x $20;
    call module('xyz',1,x);
    run;
The call might work fine, depending on which 10 bytes were overwritten. However, this might also cause you to lose data or cause your system to crash.

Also, note that the PEEK and PEEKC functions rely on the validity of the pointers you supply. If the pointers are invalid, it is possible that the SAS System could crash. For example, this code would cause a crash:

data _null_;
   length c $10;
     /* trying to copy from address 0!!!*/
   c = peekc(0,10); 
run;

Be sure that your pointers are valid and that they are 32-bit pointers when using PEEK and PEEKC.


Chapter Contents

Previous

Next

Top of Page

Copyright 1999 by SAS Institute Inc., Cary, NC, USA. All rights reserved.