Chapter Contents |
Previous |
Next |
SAS Companion for the Microsoft Windows Environment |
Updating a Character String Argument |
DWORD WINAPI GetTempPathA (DWORD nBufferLength, LPSTR lpBuffer);Here is the attribute table:
routine GetTempPathA minarg=2 maxarg=2 stackpop=called returns=long; arg 1 input byvalue format=pib4.; arg 2 update format=$cstr200.;
Note that the STACKPOP=CALLED option is used; all Win32 service routines require this attribute. The first argument is passed by value because it is an input argument only. The second argument is an update argument because the contents of the buffer are to be updated. The $CSTR200. format allows for a 200-byte character string that is null-terminated.
Here is the SAS code to invoke the function. In this example, the DLL name (KERNEL32) is explicitly given in the call (because the MODULE attribute was not used in the attribute file):
filename sascbtbl "sascbtbl.dat"; data _null_; length path $200; n = modulen( "*ie", "KERNEL32,GetTempPathA", 199, path ); put n= path=; run;
Note: KERNEL32.DLL is an internal DLL provided by Windows.
Its routines are described in the Microsoft Win32 SDK.
The code produces these log messages:
NOTE: Variable PATH is uninitialized. N=7 PATH=C:\TEMP
The example uses 199 as the buffer length because PATH can hold up to 200 characters with one character reserved for the null terminator. The $CSTR200. informat ensures that the null-terminator and all subsequent characters are replaced by trailing blanks when control returns to the DATA step.
Passing Arguments by Value |
BOOL Beep(DWORD dwFreq, DWORD dwDuration)
Here is the attribute table to use:
routine Beep minarg=2 maxarg=2 stackpop=called callseq=byvalue module=kernel32; arg 1 num format=pib4.; arg 2 num format=pib4.;
Because both arguments are passed by value, the example includes the CALLSEQ=BYVALUE attribute in the ROUTINE statement, so it is not necessary to specify the BYVALUE option in each ARG statement.
Here is the sample SAS code used to call the Beep function:
filename sascbtbl 'sascbtbl.dat'; data _null_; rc = modulen("Beep",1380,1000); run;The computer speaker beeps.
Using PEEKC to Access a Returned Pointer |
The following example uses the
lstrcat
routine, part of the Win32
API in KERNEL32.DLL.
lstrcat
accepts two strings as arguments, concatenates
them, and returns a pointer to the concatenated string. The C prototype is
LPTSTR lstrcat (LPTSTR lpszString1, LPCTSTR lpszString2);
The following is the proper attribute table:
routine lstrcat minarg=2 maxarg=2 stackpop=called module=KERNEL32 returns=ulong; arg 1 char format=$cstr200.; arg 2 char format=$cstr200.;
To use
lstrcat
, you need to use the SAS PEEKC function to
access the data referenced by the returned pointer. Here is the sample SAS
program that accesses
lstrcat
:
filename sascbtbl 'sascbtbl.dat'; data _null_; length string1 string2 conctstr $200; string1 = 'This is'; string2 = ' a test!'; rc = modulen('lstrcat',string1,string2); conctstr = peekc(rc,200); put conctstr=; run;The following output appears in the log:
conctstr=This is a test!Upon return from MODULEN, the pointer value is stored in RC. The example uses the PEEKC function to return the 200 bytes at that location, using the $CSTR200. format to produce a blank-padded string that replaces the null termination.
For more information about the PEEK functions, see PEEK.
Using Structures |
Grouping SAS Variables as Structure Arguments describes how to use the FDSTART attribute to pass several arguments as one structure argument to a DLL routine. Refer to that section for an example of the GetClientRect attribute table and C language equivalent. This example shows how to invoke the GetClientRect function after defining the attribute table.
The most straightforward method works, but generates a warning message about the variables not being initialized:
filename sascbtbl 'sascbtbl.dat'; data _null_; hwnd=modulen('GetActiveWindow'); call module('GetClientRect',hwnd, left,top,right,bottom); put _all_; run;
To remove the warning, you can use the RETAIN statement to initialize the variables to 0. Also, you can use shorthand to specify the variable list in the MODULEN statement:
data _null_; retain left top right bottom 0; hwnd=modulen('GetActiveWindow'); call module('GetClientRect',hwnd, of left--bottom); put _all_; run;
Note that the OF keyword indicates that what follows is a list of variables, in this case delimited by the double-dash. The output in the log varies depending on the active window and looks something like the following:
HWND=3536768 LEFT=2 TOP=2 RIGHT=400 BOTTOM=587
Invoking a DLL Routine from PROC IML |
The example invokes several routines from the theoretical
TRYMOD DLL. It uses the
changd
routine to add 100x+10y to each element, where x is
the C row number (0 through 3) and y is the C
column number (0 through 4). The first argument to
changd
indicates what extra amount
to sum. The
changdx
routine works just like
changd
, except that it expects a transposed
matrix. The
changi
routine works like
changd
except that it expects a matrix
of integers. The
changix
routine works like
changdx
except
that integers are expected.
Note: A maximum of three arguments can be sent when invoking a DLL routine
from PROC IML.
In this example, all four matrices x1, x2, y1, and y2 should become set to the same values after their respective MODULEIN calls. Here are the attribute table entries:
routine changd module=trymod returns=long; arg 1 input num format=rb8. byvalue; arg 2 update num format=rb8.; routine changdx module=trymod returns=long transpose=yes; arg 1 input num format=rb8. byvalue; arg 2 update num format=rb8.; routine changi module=trymod returns=long; arg 1 input num format=ib4. byvalue; arg 2 update num format=ib4.; routine changix module=trymod returns=long transpose=yes; arg 1 input num format=ib4. byvalue; arg 2 update num format=ib4.;
Here is the PROC IML step:
proc iml; x1 = J(4,5,0); do i=1 to 4; do j=1 to 5; x1[i,j] = i*10+j+3; end; end; y1= x1; x2 = x1; y2 = y1; rc = modulein('changd',6,x1); rc = modulein('changdx',6,x2); rc = modulein('changi',6,y1); rc = modulein('changix',6,y2); print x1 x2 y1 y2; run;
The following are the results of the PRINT statement:
X1 20 31 42 53 64 130 141 152 163 174 240 251 262 273 284 350 361 372 383 394 X2 20 31 42 53 64 130 141 152 163 174 240 251 262 273 284 350 361 372 383 394 Y1 20 31 42 53 64 130 141 152 163 174 240 251 262 273 284 350 361 372 383 394 Y2 20 31 42 53 64 130 141 152 163 174 240 251 262 273 284 350 361 372 383 394
Chapter Contents |
Previous |
Next |
Top of Page |
Copyright 1999 by SAS Institute Inc., Cary, NC, USA. All rights reserved.