我正在尝试在RSPEC(ruby风味的BDD)和Windows应用程序之间编写一个接口.应用程序本身是用一种晦涩的语言编写的,但它有一个C API来提供访问.我已经使用Ruby/DL,但是即使是最基本的DLL方法调用也很困难.这是我到目前为止,在一个名为gt4r.rb的文件中:
require 'dl/import' module Gt4r extend DL::Importable dlload 'c:\\gtdev\\r321\\bin\\gtvapi' # GTD initialization/termination functions extern 'int GTD_init(char *[], char *, char *)' extern 'int GTD_initialize(char *, char *, char *)' extern 'int GTD_done(void)' extern 'int GTD_get_error_message(int, char **)' end
到目前为止,我的阅读表明这是我需要的所有内容,所以我写了一个RSPEC示例:
require 'gt4r' @@test_environment = "INCLUDE=C:\\graphtalk\\env\\aiadev\\config\\aiadev.ini" @@normal_user = "BMCHARGUE" describe Gt4r do it 'initializes' do rv = Gt4r.gTD_initialize @@normal_user, @@normal_user, @@test_environment rv.should == 0 end end
当跑...
C:\code\GraphTalk>spec -fs -rgt4r gt4r_spec.rb Gt4r - initializes (FAILED - 1) 1) 'Gt4r initializes' FAILED expected: 0, got: 13 (using ==) ./gt4r_spec.rb:9: Finished in 0.031 seconds 1 example, 1 failure
返回值(13)是一个实际的返回码,意思是错误,但是当我尝试将gTD_get_error_message调用添加到我的RSPEC时,我无法使参数起作用.
我是朝着正确的方向前进吗?任何人都可以指出我可以尝试的下一件事吗?
谢谢,布雷特
对此问题的跟进,显示当我尝试从目标库获取错误消息时失败的部分:
require 'gt4r' @@test_environment = "INCLUDE=C:\\graphtalk\\env\\aiadev\\config\\aiadev.ini" @@normal_user = "BMCHARGUE" describe Gt4r do it 'initializes' do rv = Gt4r.gTD_initialize @@normal_user, @@normal_user, @@test_environment Gt4r.gTD_get_error_message rv, @msg @msg.should == "" rv.should == 0 end end
我希望在@msg中返回错误消息,但是在运行时我得到以下内容:
Gt4r (eval):5: [BUG] Segmentation fault ruby 1.8.6 (2008-08-11) [i386-mswin32] This application has requested the Runtime to terminate it in an unusual way. Please contact the application's support team for more information.
如果我使用符号(:msg)代替:
C:\code\GraphTalk\gt4r_dl>spec -fs -rgt4r gt4r_spec.rb Gt4r - initializes (ERROR - 1) 1) NoMethodError in 'Gt4r initializes' undefined method `to_ptr' for :msg:Symbol (eval):5:in `call' (eval):5:in `gTD_get_error_message' ./gt4r_spec.rb:9: Finished in 0.046 seconds 1 example, 1 failure
很明显我错过了一些关于在ruby和C之间传递参数的东西,但是什么呢?
普遍的共识是你想尽可能地避免使用DL.(英文)文档非常粗略,界面很难用于任何简单的例子.
Ruby本机C接口更容易编程.或者你可以使用FFI,它填充了一个类似于DL的利基,最初来自rubinius项目,最近被移植到"普通"红宝石.它有一个更好的界面,使用起来痛苦少得多:
http://blog.headius.com/2008/10/ffi-for-ruby-now-available.html