Connect SAS to a C library
This is related to calling C functions (made into dynamic libraries) from SAS. There are 4 files. the first 2 (1 c-file and 1 sas-file) are a positive control using doubles. The remaining files are the problematic.
C-FILE-1
#ifdef BUILD_DLL
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __declspec(dllimport)
#endif
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
EXPORT void test (double *inarray, double *outarray, int n)
{
int i;
for (i=0; i<n;i++)
{
outarray[i]= inarray[i]*2;
}
return;
}
//gcc -c -DBUILD_DLL pointersVoid.c
//gcc -shared -o pointersVoid.dll pointersVoid.oSAS-FILE-1
filename sascbtbl catalog 'work.api.MYFILE';
data _null_;
file sascbtbl; 开发者_StackOverflow
input;
put _infile_;
cards4;
routine test
module=pointersVoid
minarg=3
maxarg=3;
arg 1 input num byvalue format=IB4.;
arg 2 input num byvalue format=IB4.;
arg 3 input num byvalue format=PIB4.;
;;;;
run;
data test;
array arr(5) _temporary_ (7.56 2.356 63.54 5.14 8.2);
array ret(5);
rc=modulen ("*e","test",addr(arr(1)), addr(ret(1)), 5);
run;
This works fine and ret array now contains the *2 of the original values. But when we use strings we get errors:
C-FILE-2
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
char *strtrim_right(char *p)
{
char *end;
int len;
len = strlen(p);
while (*p && len)
{
end = p + len-1;
if(isalpha(*end))
*end = 0;
else
break;
len = strlen(p);
}
return(p);
}
EXPORT char **test (char **x, char **y, int n)
{
int i;
for (i = 0; i < n; i++)
{
y[i] = strtrim_right(x[i]);
}
}
/*
gcc -c -DBUILD_DLL pointers-array-string-void.c
gcc -shared -o pointers-array-string-void.dll pointers-array-string-void.o
*/
SAS-FILE-2
filename sascbtbl catalog 'work.api.MYFILE';
data _null_;
file sascbtbl;
input;
put _infile_;
cards4;
routine test
module=pointers-array-string-void
minarg=3
maxarg=3;
arg 1 input char byvalue format=$CSTR200. ;
arg 2 input char byvalue format=$CSTR200. ;
arg 3 input num byvalue format=PIB4. ;
;;;;
run;
data test;
array arr(5) $ _temporary_ ('PM23RO' '85AB12RE' 'RE147AMF' 'TAGH14MMF' 'LCA2Q');
array ret(5) $;
call module ("*e","test",addr(arr(1)), addr(ret(1)), 5);
run;
This doesn't work and gives errors:
Unrecognized option - in ROUTINE statement
NOTE: Invalid argument to function MODULE
ret1= ret2= ret3= ret4= ret5= rc=. _ERROR_=1 _N_=1
I know the C-FILE-2 works well because the dll has been tested from another aplication, so ther error source is very likely the SAS code in SAS-FILE-2. Any suggestions to make it work?
In 64-bit SAS you will want to use addrlong
and update the module parameter declarations to have format=$ptr. datalen=8
.
If your .dll is 32 bit you should still be able to invoke its routines by adding the routine
declaration option dlltype=32
. ("When I'm 64-bit: How to Still Use 32-bit DLLs in Microsoft Windows" Rick Langston, SAS Global Forum 2015.)
精彩评论