你如何使用Ruby / DL?这是正确的吗?

时间:2008-11-06 15:21:05

标签: c ruby interface rspec rubydl

我正在尝试在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之间传递参数的东西,但是什么?

3 个答案:

答案 0 :(得分:7)

普遍的共识是你想尽可能地避免使用DL。 (英文)文档非常粗略,界面很难用于任何简单的例子。

Ruby本机C接口更容易编程。或者你可以使用FFI,它填充了一个类似于DL的利基,最初来自rubinius项目,最近被移植到“普通”红宝石。它有一个更好的界面,使用起来痛苦少得多:

http://blog.headius.com/2008/10/ffi-for-ruby-now-available.html

答案 1 :(得分:1)

  

返回值(13)是实际值   返回代码,意思是错误,但是   当我尝试添加   gTD_get_error_message给我打电话   RSPEC,我无法获取参数   工作

它可能有助于发布错误而不是有效的代码:)

基本上,一旦你开始像(int,char **)那样处理指针,事情变得很难看。

答案 2 :(得分:0)

您需要为要写入的msg分配数据指针,因为其他C将无处编写错误消息。使用DL.mallo。

相关问题