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...
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]]
gregarican wrote: > 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...
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.
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,loginI d,passwd,applicationName,acsLevelReq,apiVer,sendQSize,sendExtraBufs,recvQSi ze,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.
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
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?
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:
resultCode=openStream.call(acsHandle,invokeIdType,invokeId,streamType,serve rId,loginId,passwd,applicationName,acsLevelReq,apiVer,sendQSize,sendExtraBu fs,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 :-)
#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?
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...
#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...
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 :-)
> 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.