我正试图在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:codeGraphTalk>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:codeGraphTalkgt4r_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项目,最近被移植到"普通"ruby。它有一个更好的界面,使用起来也不那么痛苦:
http://blog.headius.com/2008/10/ffi-for-ruby-now-available.html
返回值(13)是实际值返回代码,表示错误,但是当我尝试添加gTD_get_error_message调用到我的RSPEC,我无法获取工作
这可能有助于发布错误,而不是有效的代码:)
基本上,一旦你开始像(int,char**)中那样处理指针,事情就会变得很糟糕。
您需要为要写入的msg分配数据指针,因为其他C将无处写入错误消息。使用DL.mallo.