Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Ruby/DL Question

936 views
Skip to first unread message

gregarican

unread,
Oct 8, 2005, 6:57:15 PM10/8/05
to
I am trying to call a method included in a Windows DLL file. Judging by
the C header file that this DLL is created from and judging from the
API documentation I think I have the various parameters needed. But the
return code seems to be different. I have commented my code to include
the C header details as well as a sample C program that accesses this
method. Anyone know what I am missing? I guess I'm confused because the
method is supposed to return an integer result code, but also returns a
pointer called acsHandle. I thought only one thing could be returned
and that's why my Ruby code is just returning the acsHandle pointer...

=begin
acsOpenStream method based on

TSAPI
acsOpenStream ( acsHandle /* RETURN */
invokeIDType, /* INPUT */
invokeID, /* INPUT */
streamType, /* INPUT */
serverID, /* INPUT */
loginID, /* INPUT */
passwd, /* INPUT */
applicationName,/* INPUT */
acsLevelReq, /* INPUT */
apiVer, /* INPUT */
sendQSize, /* INPUT */
sendExtraBufs, /* INPUT */
recvQSize, /* INPUT */
recvExtraBufs, /* INPUT */
privateData /* INPUT */);

here's an example of this in C

rCode=acsOpenStream(acsHandle,invokeIDType,invokeID,streamType,

serverID,loginID,passwd,applicationName,acsLevelReq,

apiVer,sendQSize,sendExtraBufs,recvQSize,recvExtraBufs,

privateData);

if (rCode < 0)<
{

printf("acsOpenStream failure...");

return;

}

else

{

printf("acsOpenStream success\n");

invokeID=rCode;

}

=end

# here's my Ruby code

require 'dl'
csta=DL.dlopen('csta32.dll')
openStream=csta['acsOpenStream', 'PSISSSSSISIIIIS']
results=openStream.call("LIB_GEN_ID",0,"ST_CSTA","AVAYA#MERLIN#CSTA#MERLIN-CTI\000","username\000","password\000","CTI
Test\000",2,"TS2",0,0,0,0,nil)
p results

# my results show as
# [#<DL::PtrData:0x02ABD620 ptr=0xFFFFFFFE size=0 free=0x00000000>,
["LIB_GEN_ID",0,"ST_CSTA","AVAYA#MERLIN#CSTA#MERLIN-CTI\000","username\000","password\000","CTI
Test\000",2,"TS2",0,0,0,0,nil]]

Takaaki Tateishi

unread,
Oct 9, 2005, 6:49:48 AM10/9/05
to


--
Takaaki Tateishi <tt...@ttsky.net>

Takaaki Tateishi

unread,
Oct 9, 2005, 6:53:15 AM10/9/05
to
gregarican wrote:
> method. Anyone know what I am missing? I guess I'm confused because the
> method is supposed to return an integer result code, but also returns a
> pointer called acsHandle.
...
> openStream=csta['acsOpenStream', 'PSISSSSSISIIIIS']

I think the above line should be csta['acsOpenStream', 'IPSISSSSSISIIIIS'].
As you can see, I put 'I' before the 'PSISS....' since the method is supposed to
return an integer value.

Regards,
--
Takaaki Tateishi <tt...@ttsky.net>

gregarican

unread,
Oct 9, 2005, 8:11:51 AM10/9/05
to
Takaaki Tateishi wrote:

> I think the above line should be csta['acsOpenStream', 'IPSISSSSSISIIIIS'].
> As you can see, I put 'I' before the 'PSISS....' since the method is supposed to
> return an integer value.


I made the change to include the integer return value, and removed the
P entry since the pointer was no longer in the picture. In addition I
checked the parameter data types to ensure that they matched. There
were a couple of entries that I originally had as strings which were
actually enum types in the C header file. So I went in and found the
corresponding integer values they represent. Now my code looks like:
----------------------------------------
=begin
TSAPI
acsOpenStream (acsHandle /* RETURN an integer value? */
invokeIDType, /* INPUT an integer ENUM value?*/
invokeID, /* INPUT an integer value? */
streamType, /* INPUT an integer ENUM value? */
serverID, /* INPUT a null terminated string value? */
loginID, /* INPUT a null terminated string value? */
passwd, /* INPUT a null terminated string value? */
applicationName,/* INPUT a null terminated string value? */
acsLevelReq, /* INPUT an integer ENUM value?*/
apiVer, /* INPUT a string value? */
sendQSize, /* INPUT an integer value? */
sendExtraBufs, /* INPUT an integer value? */
recvQSize, /* INPUT an integer value? */
recvExtraBufs, /* INPUT an integer value? */
privateData /* INPUT a null terminated string value? */);
=end


require 'dl'
csta=DL.dlopen('csta32.dll')

openStream=csta['acsOpenStream', 'IIIISSSSISIIIIS']
invokeIdType=2
invokeId=0
streamType=1
serverId="AVAYA#MERLIN#CSTA#MERLIN-CTI\000"
loginId="username\000"
passwd="password\000"
applicationName="CTI Test\000"
acsLevelReq=1
apiVer="TS2"
sendQSize=0
sendExtraBufs=0
recvQSize=0
recvExtraBufs=0
privateData="VERSION\000"

resultCode=openStream.call(invokeIdType,invokeId,streamType,serverId,loginId,passwd,applicationName,acsLevelReq,apiVer,sendQSize,sendExtraBufs,recvQSize,recvExtraBufs,privateData)
p resultCode[0]
----------------------------

The resultCode[0] entry returned -2, which according to the API means a
bad parameter was passed to the call. I double checked the expected
parameter data types and everything appears to be correct. the code
comments indicate what I _think_ the API expects to be passed to the
acsOpenStream method. This was going strictly against the TSAPI docs
that are public domain.
http://www.cs.cornell.edu/courses/cs519/1998fa/project/Doc/PBX/tsapi.pdf
is such an example.

Sigh....this is getting frustrating...

gregarican

unread,
Oct 9, 2005, 8:54:49 AM10/9/05
to
gregarican wrote:

> Sigh....this is getting frustrating...

I think I am getting closer. I know that the ENUM values being fed as
parameters are integer data types ('I') and some of the other numeric
values being fed are long data types ('L'). But the last few numeric
values being fed in are listed as being short data types (see my code
comments below). What do I put into the DL call method to indicate the
short data types for them? I couldn't find the corresponding flag for
them...
-----------------------------------------
=begin
TSAPI
acsOpenStream (acsHandle /* RETURN long value */
invokeIDType, /* INPUT integer ENUM value*/
invokeID, /* INPUT long value*/
streamType, /* INPUT integer ENUM value*/
serverID, /* INPUT null terminated string value*/
loginID, /* INPUT null terminated string value*/
passwd, /* INPUT null terminated string value*/
applicationName, /* INPUT null terminated string value*/
acsLevelReq, /* INPUT integer ENUM value (ignored)*/
apiVer, /* INPUT string value*/
sendQSize, /* INPUT short value */
sendExtraBufs, /* INPUT short value*/
recvQSize, /* INPUT short value*/
recvExtraBufs, /* INPUT short value*/
privateData /* INPUT null terminated string value */);
=end

Takaaki Tateishi

unread,
Oct 9, 2005, 4:32:48 PM10/9/05
to
gregarican wrote:
> values being fed are long data types ('L'). But the last few numeric
> values being fed in are listed as being short data types (see my code
> comments below). What do I put into the DL call method to indicate the
> short data types for them?

"h" or "H" are for the short data types.

P.S.
Please refer the following resources if needed.
http://rubyforge.org/cgi-bin/viewcvs.cgi/dlcookbook/win32/?cvsroot=dlcookbook
http://raa.ruby-lang.org/project/rdl_en/
http://www.ruby-lang.org/cgi-bin/cvsweb.cgi/~checkout~/ruby/ext/dl/doc/Attic/dl.txt?rev=1.9;content-type=text%2Fplain;hideattic=0;only_with_tag=v1_8_3
--
Takaaki Tateishi <tt...@ttsky.net>

gregarican

unread,
Oct 9, 2005, 9:06:08 PM10/9/05
to
Takaaki Tateishi wrote:

> "h" or "H" are for the short data types.

Thanks. I found that in the DL docs
(http://www.ruby-doc.org/stdlib/libdoc/dl/rdoc/classes/DL/Types.html)
earlier today. I finally got this put together. The return type of the
method call is a long value. Previously I had used an integer value.
Then I had to make the call's first parameter (acsHandle) a pointer
value. Before I had totally left this parameter out. That's why the -2
return code was coming back. This translates to 'bad parameter.' Here's
my working code now:

---------------------------------------


require 'dl'
csta=DL.dlopen('csta32.dll')

openStream=csta['acsOpenStream', 'LPILISSSSISHHHHS']
acsHandle=[0].pack('L').to_ptr
invokeIdType=1


invokeId=0
streamType=1
serverId="AVAYA#MERLIN#CSTA#MERLIN-CTI\000"
loginId="username\000"
passwd="password\000"
applicationName="CTI Test\000"
acsLevelReq=1

apiVer="TS1-2\000"


sendQSize=0
sendExtraBufs=0
recvQSize=0
recvExtraBufs=0
privateData="VERSION\000"

resultCode=openStream.call(acsHandle,invokeIdType,invokeId,streamType,serverId,loginId,passwd,applicationName,acsLevelReq,apiVer,sendQSize,sendExtraBufs,recvQSize,
recvExtraBufs,privateData)
p resultCode[0]
--------------------------------------
Once I get all of this written I plan to share it with anyone who is
interested. It will be a working Ruby CTI envionment that works with
TSAPI-compliant elements. Not sure of the interest level, but I for one
will be glad to see it all come together :-)

Thanks for your replies!

Peña, Botp

unread,
Oct 10, 2005, 3:51:09 AM10/10/05
to
gregarican [mailto:greg....@gmail.com]

#Once I get all of this written I plan to share it with anyone who is
#interested. It will be a working Ruby CTI envionment that works with
#TSAPI-compliant elements. Not sure of the interest level, but I for one
#will be glad to see it all come together :-)

could you expound on this, pls.
are you saying that you are building a pure ruby telephony api?

thanks and kind regards -botp

ps: puts "interested" if greg.reply =~ /y/

#
#Thanks for your replies!
#
#
#


gregarican

unread,
Oct 10, 2005, 8:43:08 AM10/10/05
to
P wrote:

> could you expound on this, pls.
> are you saying that you are building a pure ruby telephony api?

What I am looking to do is write a group of Ruby classes that connect
to the TSAPI. This API is an existing interface that was developed
first by AT&T and then transferred to Novell. It implements the set of
CSTA standard protocol for communicating with certain PBX systems. I am
not building a new API per se, as I am just creating a Ruby way of
hooking into it. I have all of the C headers that define the CSTA
protocol, as well as the C++ header/implementation files for TSAPI. But
trying SWIG and other manual methods left me dizzy. There are a lot of
files involved and I'm totally clueless when it comes to wrapping or
translating things over :-) So I resorted to using Ruby/DL for
connecting to the csta32.dll file so that I can directly access the
methods using Ruby. Now it's just a question or accessing the other
methods that I need for full CTI functionality.

Right now I just tackled the first one, initializing the CSTA
communication stream that connects a client with the PBX system. We'll
see how long the rest of the methods take now that this one is done.
I'm hoping now that I have a better idea about the various method
parameters and their corresponding data types the rest will be a
downhill battle. There are roughly three dozen methods that will have
to be included. If/when I complete this I will place something out
there for people to review. I figure it can possibly make some people's
lives easier since they won't have to reinvent the wheel if they are
looking to access CTI using Ruby...

Peña, Botp

unread,
Oct 10, 2005, 9:45:03 PM10/10/05
to
gregarican [mailto:greg....@gmail.com]

#Right now I just tackled the first one, initializing the CSTA
#communication stream that connects a client with the PBX system. We'll
#see how long the rest of the methods take now that this one is done.
#I'm hoping now that I have a better idea about the various method
#parameters and their corresponding data types the rest will be a
#downhill battle. There are roughly three dozen methods that will have
#to be included. If/when I complete this I will place something out
#there for people to review. I figure it can possibly make some people's
#lives easier since they won't have to reinvent the wheel if they are
#looking to access CTI using Ruby...

your work could be another ruby killer app. It would expose cleanly the t-apis and there would be no need to resort to C. Ultimately, it would make mystical apps/boxes (like pbxes) appear sooo easy to use and manager...

thanks for your project and kind regards -botp


gregarican

unread,
Oct 11, 2005, 7:01:32 PM10/11/05
to
P wrote:

> thanks for your project and kind regards -botp

Four methods down, 95 to go. Checking the TSAPI docs in detail there
are a lot more items in it than I first thought. A lot more than
30-something. All of the pointer passing back and forth between the DLL
file and Ruby gets tedious, but at least the Ruby/DL library makes it
easier than the more manual methods in Win32API. I guess my app would
be portable to non-Windows platforms as long as an alternative library
is loaded in DL instead of the csta32.dll file.

Figure that I owe it to the Ruby community to hand something over when
I finally get done with this thing. Lord knows I have picked people's
brains with the most off base and newbie-ish questions over the past
year :-)

Bill Kelly

unread,
Oct 11, 2005, 8:25:41 PM10/11/05
to
From: "gregarican" <greg....@gmail.com>

>
> Four methods down, 95 to go. Checking the TSAPI docs in detail there
> are a lot more items in it than I first thought. A lot more than
> 30-something. All of the pointer passing back and forth between the DLL
> file and Ruby gets tedious, but at least the Ruby/DL library makes it
> easier than the more manual methods in Win32API.

Hi, I think you may have mentioned SWIG earlier in the
thread - but if you've only taken a brief look at SWIG
so far, I'd definitely recommend having another go at it
(unless there's a known reason why SWIG can't cope with
your particular project.)

I did ruby bindings by hand for a few projects. I kept
looking at SWIG but somehow didn't "get" it from the
documentation - or at least, for whatever reason, everytime
I downloaded SWIG and started trying to figure out how to
use it, I ended up thinking, heck I'd be half-done if I
wrote the bindings by hand by now, and ended up putting off
learning SWIG.

I finally forced myself to learn SWIG doing the bindings
for ruby-ftgl ( http://rubyforge.org/projects/ruby-ftgl/ )
It was worth it. You pretty much just give SWIG the
function declarations from the the library you're trying
to wrap, and the bindings magically appear. Some tweaks
can be needed, such as functions which return values
through paramters - but SWIG can handle that, it just
needs some simple hints.

You can point SWIG at the actual header files from the
library, but it may end up trying to wrap more stuff than
you really wanted. So you can just copy the function
declarations from the library header file(s) you're
interested in, and turn SWIG loose on those. (Which is
good, because you may need to mark up a few of the
declarations slightly, to provide the hints alluded to
above.)

Anyway just wanted to give some props to SWIG in case
you might be at the same point I was for awhile where
SWIG seemed to weird and complicated to bother with. It's
pretty neat.


Regards,

Bill

0 new messages