Pergunta

Eu estou tentando escrever uma interface entre RSPEC (ruby sabor BDD) e um aplicativo do Windows. O próprio aplicativo é escrito em uma linguagem obscura, mas ele tem uma API C para fornecer acesso. Eu tenho ido com Ruby / DL, mas estou tendo dificuldades ficando ainda a chamada mais básica de um método DLL ao trabalho. Aqui está o que eu tenho até agora, em um arquivo chamado 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

A minha leitura até agora sugere que isto é tudo necessidade I para começar, então eu escrevi um exemplo 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

E quando run ...

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

O valor de retorno (13) é um código de retorno real, ou seja, um erro, mas quando eu tento adicionar a chamada gTD_get_error_message ao meu RSPEC, não posso obter os parâmetros de trabalho.

Am I indo na direção e pode apontar qualquer direito para a próxima coisa que eu posso tentar?

Obrigado, Brett


Um acompanhamento a esta pergunta, mostrando a parte que falhar ao tentar obter a mensagem de erro de minha biblioteca de destino:

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

Espero que a mensagem de erro a ser devolvido no @msg, mas quando executado recebo a seguinte:

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.

E isso se eu usar um símbolo (: msg) em vez disso:

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

É evidente que eu estou faltando alguma coisa sobre a passagem de parâmetros entre Ruby e C, mas o que?

Foi útil?

Solução

O consenso geral é que você quer evitar DL, tanto quanto possível. O (Inglês) documentação é bastante superficial ea interface é difícil de usar para nada trivial exemplos.

interface de rubi nativa C é muito mais fácil para o programa contra. Ou você pode usar FFI, que preenche um nicho semelhante ao DL, originalmente vem do projeto Rubinius e recentemente foi portado para ruby ??"normal". Ele tem uma interface agradável e é muito menos doloroso para uso:

http://blog.headius.com/ 2008/10 / FFI-for-ruby-agora-available.html

Outras dicas

O valor de retorno (13) é um real retornar código, o que significa um erro, mas quando tento adicionar o gTD_get_error_message chamada para o meu RSPEC, não posso obter os parâmetros para trabalho.

Pode ajudar a postar o erro em vez do código que funcionou :)

Basicamente, quando você começar a ter que lidar com ponteiros como em (int, char **), as coisas ficam feias.

Você precisa alocar o ponteiro de dados para msg a ser gravado, desde otherise C terá nenhum lugar para escrever as mensagens de erro. Use DL.mallo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top