From: xlr82sas on
On Dec 13, 12:45 pm, Savian <savian....(a)gmail.com> wrote:
> On Dec 13, 11:21 am, Francogrex <fra...(a)grex.org> wrote:
>
> > On Dec 13, 10:17 am, Francogrex <fra...(a)grex.org> wrote:
>
> > > On Dec 13, 12:36 am, Savian <savian....(a)gmail.com> wrote:
>
> > > > Do you have control of the dll or is it 3rd party?
>
> > > I make it myself from the C file I showed above.
>
> > ok since I got no solutions then I guess it's either not possible or
> > I'll need to ask the sas developers at the sas institute because the
> > programmers don't seem to know about it.
>
> Why not use an X command and pass the array in an XML file? You could
> also just pass it as a command line argument but I would use XML
> instead. Also consider using C# since you are on Windows. C is very
> old school. Yes, it works, but consider alternatives. C# EASILY
> handles XML so you could be running it in no time.
>
> Richard D. could answer it but he probably doesn't post on the
> weekends.
>
> Alan

Hi,

I wish I had a little more time, you asked a very interesting
question, I tend to use strings for communicating with other
languages.

see
http://support.sas.com/techsup/technote/ts353.html

and

http://www.devenezia.com/

Some possible Ideas ( may not work)

1. I think you could create a exe from a dll and use a pipe with stdin
stdout(see below)
2. Use modelc and pass a very long string using delimited(or non
delimited) hex16. values ie '4F00000000000,56f0000000000'
just decode the values in your C program.
3. Consider using Java to call the dll using 9.2 Java obj?
4. Convert you C program to Java an do something like. Here the Java
concat command is used concatenate two strings. I think you may be
able to call the DLL from java. There is alot more to this on my site.

data _null_;
length s_out $200;
declare JavaObj j1 ('java/lang/String','ABCDE');
declare JavaObj j2 ('java/lang/String','FGHIJ');
j1.callStringMethod ('concat', j2, s_out);
put s_out=;
j1.delete(); j2.delete();
run;

WINDOWS (untested code)
where fid contains the highlighted code in the clipboard (highlight
code and put "store;gsub '%alansexe' on a function key)
filename fmt pipe "c:\cpound\fmt.exe < &fid 2>c:\fmt.log"
filename fmt pipe "c:\cpound\fmt.exe < &fid 2>&1"



From: Tom Abernathy on
Not that I have ever used it, but someone just mentioned using peek or
poke on another thread.
Couldn't you use that to pass the base address of the array to your
function?

On Dec 13, 1:21 pm, Francogrex <fra...(a)grex.org> wrote:
> On Dec 13, 10:17 am, Francogrex <fra...(a)grex.org> wrote:
>
> > On Dec 13, 12:36 am, Savian <savian....(a)gmail.com> wrote:
>
> > > Do you have control of the dll or is it 3rd party?
>
> > I make it myself from the C file I showed above.
>
> ok since I got no solutions then I guess it's either not possible or
> I'll need to ask the sas developers at the sas institute because the
> programmers don't seem to know about it.

From: Jonathan Goldberg on
Assuming you are running on a 32 bit platform, you should try the addr()
function. I haven't tried this, but I suggest you do two things:
1) put your data into a _temporary_ array to insure that the values are
stored in contiguous memory locations
2) pass y = addr(yourarry(1));

On a 64 bit platform use addrlong();

Note: addr() returns the address of a numeric variable. Addrlong() returns
the address of a character variable. Whichever, you will need to have
your data be the appropriate type on the SAS side and do any needed
conversions in your dll. Also, addrlong() works in both environments and
is the recommended method for this reason.

HTH.

Jonathan


On Sat, 12 Dec 2009 06:44:07 -0800, 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));
> 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: S=?ISO-8859-1?Q?=C3=B8ren?= Lassen on
Franco,

I do not think your approach is quite the right one.
Even if you succeed, you would probably have a memory leak,
as you allocate the return values with malloc, but the
memory is (as far as I can see) not released again anywhere.

If you want to take data from an array and return the
data in another array, you should probably let SAS allocate
both arrays. Something like this:

data x;
array vals(4) (12 2 13 4);
array returns (4) 8;
call module('*e','test',vals(1),returns(1),4);
run;

That way, SAS will take care of allocating and deallocating the
memory.

Your C routine would then look something like

EXPORT void test (double *inarray,
double *outarray,
int n)
{
int i;
for (i=0; i<n;i++)
{
outarray[i]=inarray[i]*2;
}
return;
}

Of course, the call may be made more elegant and foolproof by
putting it in a macro:

%macro doublearray(inarray,outarray,
n=min(dim(&inarray),dim(&outarray)) );
call module('*e','test',
&inarray(lbound(&inarray)),
&outarray(lbound(&outarray)),
&n)
%mend;

Regards,
Søren


On Sat, 12 Dec 2009 06:44:07 -0800, 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));
> 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: Jonathan Goldberg on
Soren:

Good catch. Gad, it's been a long time since I programmed in C. Those
were the days...

Your modified code calls the module routine. This is necessary if the
routine called does not return a value. The original code called modulen
and specified the return type as long. Since the C code writes multiple
values directly to memory it's a little obscure which is correct; however,
Franco might try it your way to see if it helps.

On Wed, 16 Dec 2009 02:56:31 -0500, S=?ISO-8859-1?Q?=C3=B8ren?= Lassen
<s.lassen(a)POST.TELE.DK> wrote:

>Franco,
>
>I do not think your approach is quite the right one.
>Even if you succeed, you would probably have a memory leak,
>as you allocate the return values with malloc, but the
>memory is (as far as I can see) not released again anywhere.
>
>If you want to take data from an array and return the
>data in another array, you should probably let SAS allocate
>both arrays. Something like this:
>
>data x;
> array vals(4) (12 2 13 4);
> array returns (4) 8;
> call module('*e','test',vals(1),returns(1),4);
>run;
>
>That way, SAS will take care of allocating and deallocating the
>memory.
>
>Your C routine would then look something like
>
>EXPORT void test (double *inarray,
> double *outarray,
> int n)
>{
> int i;
> for (i=0; i<n;i++)
> {
> outarray[i]=inarray[i]*2;
> }
> return;
>}
>
>Of course, the call may be made more elegant and foolproof by
>putting it in a macro:
>
>%macro doublearray(inarray,outarray,
> n=min(dim(&inarray),dim(&outarray)) );
> call module('*e','test',
> &inarray(lbound(&inarray)),
> &outarray(lbound(&outarray)),
> &n)
>%mend;
>
>Regards,
>Søren
>
>
>On Sat, 12 Dec 2009 06:44:07 -0800, 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));
>> 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?