Ruby - 将方法作为回调传递给 DLL 库

Posted

技术标签:

【中文标题】Ruby - 将方法作为回调传递给 DLL 库【英文标题】:Ruby - passing a method to a DLL library as a callback 【发布时间】:2015-03-02 21:16:42 【问题描述】:

假设我有一个带有此函数的 C/C++ 库,编译为 DLL:

#include <Windows.h>

extern "C" __declspec(dllexport) void __stdcall myFunction(void (*myCallback)(int)) 
    int result = MessageBox(
        0, (LPCWSTR)L"Press yes or no", (LPCWSTR)L"Test", MB_YESNO
    );
    myCallback(result);

它只是打开标准 Win32 消息框并将结果传递给回调函数。

问题是:是否可以通过 Fiddle 或类似的方式在 Ruby 中使用此函数,并以某种方式将 Ruby 方法传递给它,以便从 C++ 代码中调用它?

这是我用来将 DLL 库导入 Ruby 的代码:

require "fiddle"

myLibrary = Fiddle.dlopen("myLibrary.dll")
myFunction = Fiddle::Function.new(
  myLibrary["myFunction"], 
  [Fiddle::TYPE_VOIDP], 
  Fiddle::TYPE_VOID
)

def myCallback(value)
  puts "MessageBox result is #value"
end

这显然行不通:

myFunction.call(method(:myCallback))

它只是抛出一个 TypeError - 无法将 Method 转换为 Integer。

有没有办法将回调传递给 C 函数?

【问题讨论】:

可能相关:***.com/questions/3327666/… 该链接描述了如何使用 Ruby 调用需要回调的 API 函数。因此,您可能可以将其用作指南。 测试包括a qsort() example。也看看Fiddle::Importer#bind 感谢您提供的 qsort() 示例! Fiddle::Closure 似乎是回调的正确选择:) 【参考方案1】:

所以我找到了解决方案:

myClosure = Class.new(Fiddle::Closure) 
  def call(value)
    puts "MessageBox result is #value"  
  end
.new(Fiddle::TYPE_VOID, [Fiddle::TYPE_INT])

然后我可以简单地调用C函数:

myFunction.call(myClosure)

我真的不知道它是如何工作的 - 但它工作正常。

【讨论】:

【参考方案2】:

另一种语法是使用 Fiddle 的 BlockCaller:

myClosure = Fiddle::Closure::BlockCaller.new(Fiddle::TYPE_VOID, [Fiddle::TYPE_INT]) do |value|
  puts "MessageBox result is #value"
end

【讨论】:

以上是关于Ruby - 将方法作为回调传递给 DLL 库的主要内容,如果未能解决你的问题,请参考以下文章

如何将多个参数作为数组传递给 ruby​​ 方法?

如何将组件中的 Angular2 方法作为第三方库的回调方法传递?

使用Fiddle将RUBY数组传递给C DLL

将 Go 函数作为回调传递给 C

将非托管方法作为回调传递给托管 C++/CLI 类

如何将 C# 中的方法指针传递给 C 库?