From: Francogrex on
Hi, This isn't an easy question, actually it's very tough and I expect
only very experienced programmers to know the answer. I'm trying to
use the modulen function to let sas connect and use a dll. My dll
takes as an input a pointer and an integer and returns a pointer. Here
is the code of the dll that I called sas.dll:
#ifdef BUILD_DLL
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __declspec(dllimport)
#endif
#include <stdio.h>
#include <stdlib.h>
EXPORT double __stdcall *test (double *x, int n)
{
double *end=malloc((n+5)*sizeof(double));
int i;
for (i=0; i<n;i++)
{
*end=x[i]*2;
}
return(end);
}

Now from SAS I use:

filename sascbtbl catalog 'work.api.ZIAD';
data _null_;
file sascbtbl;
input;
put _infile_;
cards4;
routine test
minarg=2
maxarg=2
stackpop=called
module=sas
returns=long;

arg 1 num input byaddr format=RB8. ;
arg 2 num input byvalue format=PIB4. ;
;;;;
run;
data _null_;
array vals(4) (12 2 13 4);
rc= modulen ('*e', 'test',vals(1),1);
put rc=;
testme=peek(rc,8);
put testme=;
run;

This works well. Giving: rc=72351536 and testme=24

But I am just giving one values as an argument to the sas.dll. What I
want is to directly pass the WHOLE array arr as an argument (pointer)
and then use something like

rc= modulen ('*e', 'test', {WRONG SYNTAX ALL ARRAY vals}, 4);
ret1=peek(rc,8) ;
ret2=peek(rc+8,8);
etc..
to read the returned result. Any ideas how?
From: Barry Schwarz on
On Sat, 12 Dec 2009 06:44:07 -0800 (PST), Francogrex <franco(a)grex.org>
wrote:

>Hi, This isn't an easy question, actually it's very tough and I expect
>only very experienced programmers to know the answer. I'm trying to
>use the modulen function to let sas connect and use a dll. My dll
>takes as an input a pointer and an integer and returns a pointer. Here
>is the code of the dll that I called sas.dll:
>#ifdef BUILD_DLL
>#define EXPORT __declspec(dllexport)
>#else
>#define EXPORT __declspec(dllimport)
>#endif
>#include <stdio.h>
>#include <stdlib.h>
>EXPORT double __stdcall *test (double *x, int n)
>{
> double *end=malloc((n+5)*sizeof(double));

You allocate an array of n+5 doubles.

> int i;
> for (i=0; i<n;i++)
> {
> *end=x[i]*2;

You repeatedly store different values in the first element of that
array. Obviously, only the last value stored survives in the element.
The remaining n+4 elements have indeterminate values.

Did you intend instead
end[i] = x[i] * 2;
This will populate the first n elements of the array. The last 5 will
still be indeterminate.

> }
> return(end);
>}
>
>Now from SAS I use:
>
>filename sascbtbl catalog 'work.api.ZIAD';
>data _null_;
> file sascbtbl;
> input;
> put _infile_;
> cards4;
> routine test
> minarg=2
> maxarg=2
> stackpop=called
> module=sas
> returns=long;
>
>arg 1 num input byaddr format=RB8. ;
>arg 2 num input byvalue format=PIB4. ;
>;;;;
>run;
>data _null_;
> array vals(4) (12 2 13 4);
> rc= modulen ('*e', 'test',vals(1),1);
> put rc=;
> testme=peek(rc,8);
> put testme=;
>run;
>
>This works well. Giving: rc=72351536 and testme=24
>
>But I am just giving one values as an argument to the sas.dll. What I
>want is to directly pass the WHOLE array arr as an argument (pointer)
>and then use something like
>
>rc= modulen ('*e', 'test', {WRONG SYNTAX ALL ARRAY vals}, 4);
>ret1=peek(rc,8) ;
>ret2=peek(rc+8,8);
>etc..
>to read the returned result. Any ideas how?

--
Remove del for email
From: Francogrex on
On Dec 12, 5:45 pm, Barry Schwarz <schwa...(a)dqel.com> wrote:
> You allocate an array of n+5 doubles.
>
> >  int i;
> >  for (i=0; i<n;i++)
> >    {
> >      *end=x[i]*2;
>
> You repeatedly store different values in the first element of that
> array.  Obviously, only the last value stored survives in the element.
> The remaining n+4 elements have indeterminate values.  
>
> Did you intend instead
>      end[i] = x[i] * 2;
> This will populate the first n elements of the array.  The last 5 will
> still be indeterminate.
>

Oops yes it was a typing error while I was typing it here in the
newsgroup; that line above should read: *(end+i)=x[i]*2;
Of course since it is correct in the original C file that compiled to
the sas.dll my stated problem before still remains. Any suggestions?

From: Savian on
On Dec 12, 7:44 am, Francogrex <fra...(a)grex.org> wrote:
> Hi, This isn't an easy question, actually it's very tough and I expect
> only very experienced programmers to know the answer. I'm trying to
> use the modulen function to let sas connect and use a dll. My dll
> takes as an input a pointer and an integer and returns a pointer. Here
> is the code of the dll that I called sas.dll:
> #ifdef BUILD_DLL
> #define EXPORT __declspec(dllexport)
> #else
> #define EXPORT __declspec(dllimport)
> #endif
> #include <stdio.h>
> #include <stdlib.h>
> EXPORT double __stdcall *test (double *x, int n)
> {
>   double *end=malloc((n+5)*sizeof(double));
>   int i;
>   for (i=0; i<n;i++)
>     {
>       *end=x[i]*2;
>     }
>   return(end);
>
> }
>
> Now from SAS I use:
>
> filename sascbtbl catalog 'work.api.ZIAD';
> data _null_;
>     file sascbtbl;
>     input;
>     put _infile_;
>     cards4;
>     routine test
>         minarg=2
>         maxarg=2
>         stackpop=called
>         module=sas
>         returns=long;
>
> arg 1 num input byaddr format=RB8. ;
> arg 2 num input byvalue format=PIB4. ;
> ;;;;
> run;
> data _null_;
>     array vals(4) (12 2 13 4);
>         rc=  modulen ('*e', 'test',vals(1),1);
>         put rc=;
>                 testme=peek(rc,8);
>         put testme=;
> run;
>
> This works well. Giving: rc=72351536 and testme=24
>
> But I am just giving one values as an argument to the sas.dll. What I
> want is to directly pass the WHOLE array arr as an argument (pointer)
> and then use something like
>
> rc=  modulen ('*e', 'test', {WRONG SYNTAX ALL ARRAY vals}, 4);
> ret1=peek(rc,8) ;
> ret2=peek(rc+8,8);
> etc..
> to read the returned result. Any ideas how?

I cannot answer your direct question since I have never used modulen
but let me ask a few questions that might lead to alternatives
(assuming others cannot give a direct response).

1. What O/S are you running on?
2. Can you skip a datastep and use an X command instead?
3. Do you have a data volume problem?

If I need processing external to SAS (which I do on every single
project), I tend to code it up and read in the SAS datasets, process,
then put it back into SAS format. This does not work with large volume
but it is an idea. That way, I control all aspects of the interface.

Alan
http://www.savian.net
From: Francogrex on
On Dec 12, 11:17 pm, Savian <savian....(a)gmail.com> wrote:
> I cannot answer your direct question since I have never used modulen
> but let me ask a few questions that might lead to alternatives
> (assuming others cannot give a direct response).
>
> 1. What O/S are you running on?
> 2. Can you skip a datastep and use an X command instead?
> 3. Do you have a data volume problem?
>
> If I need processing external to SAS (which I do on every single
> project), I tend to code it up and read in the SAS datasets, process,
> then put it back into SAS format. This does not work with large volume
> but it is an idea. That way, I control all aspects of the interface.

I use winXP. I know how to pipe commands to a cmd, write to external
temp files that other programs can use and spit back their outputs
into sas, but that's not what I want, sorry. I really need to pass an
array as an argument to a dll and get back an array of values in
return. I know how to get an array of values in return (see below),
what is still missing is passing the array to the dll as one argument.

This works because arguments are not pointers
sas.c file:
EXPORT double __stdcall *test (double x, double y,int n)
{
double *end=malloc((n+5)*sizeof(double));
int i;
for (i=0; i<n; i++)
{
*(end+i)=(x+y)*i;
}
return(end);
}

filename sascbtbl catalog 'work.api.myfile';
data _null_;
file sascbtbl;
input;
put _infile_;
cards4;
routine test
minarg=3
maxarg=3
stackpop=called
module=sas
returns=long;

arg 1 num input byvalue format=RB8. ;
arg 2 num input byvalue format=RB8. ;
arg 3 num input byvalue format=PIB4. ;
;;;;
run;
data _null_;
rc = modulen ('*e', 'test', 7.3, 4.6, 15);
do i=0 to 14*8 by 8;
testme=peek(rc+i,8);
put testme=;
end;
run;