WIN32OLE-将Ruby函数注入Internet Explorer的JavaScript

时间:2018-06-19 17:28:57

标签: javascript ruby internet-explorer bho

在AHK中,可以使用以下代码将AHK函数注入Internet Explorer的JavaScript引擎:

#Persistent

html =
(
<html>
  <head>
    <script>
      document.setVar = function`(name,val`){
        document[name]=val;
      }
    </script>
  </head>
  <body>
    <h1>Hello!</h1>
  </body>
</html>
)

ie := ComObjCreate("InternetExplorer.Application")
ie.navigate("about:blank")
sleep, 2000


msgbox, %html%
ie.document.writeln(html)
ie.visible := true
ie.document.setVar("someFunc",Func("someFunc"))


someFunc(){
  msgbox, "hello"
}

注入函数后,JavaScript可以调用document.someFunc(),这将导致JavaScript调用AHK函数,并最终运行消息框。

我想将此代码移植到Ruby。到目前为止,我有这个:

require 'win32ole'
ie = WIN32OLE.new('InternetExplorer.Application')
ie.navigate("about:blank")
sleep(0.1) until !ie.busy
html = <<Heredoc
<html>
  <head>
    <script>
      document.setVar = function(name,val){
        document[name]=val;
      }
    </script>
  </head>
  <body>
    <h1>Hello!</h1>
  </body>
</html>
Heredoc

ie.document.writeln(html)
ie.visible = true

现在我们在这里应该可以注入Ruby方法,但是目前我不知道如何实现此方法。每次尝试尝试时,JavaScript引擎都会冻结。我尝试过的一些事情:

ie.document.setVar("someFunc",method(:someFunc))
#----------------------------------
ie.document.setVar("someFunc",->{puts "hello"})
#----------------------------------
class someClass
  def someFunc
    puts "hello"
  end
end
ie.document.setVar("someClass",someClass})
#----------------------------------
closure = Class.new(Fiddle::Closure) {
  def call
    puts "hello world"
  end
}.new(Fiddle::TYPE_INT,[])
someFunc = Fiddle::Function.new(closure, [], Fiddle::TYPE_INT)
#Both:
doc.setVar("someFunc",closure)
#and
doc.setVar("someFunc",someFunc)
#----------------------------------

以上方法均无效。最后,他们最终都冻结了JavaScript引擎...有人知道我如何将对Ruby函数的实际引用传递给JavaScript吗?

1 个答案:

答案 0 :(得分:0)

经过一周的搜索,我什么都没找到,我想:“如果我们天真并传递一个定义了method_missing的对象,该怎么办?”

30分钟后,我可以从JavaScript调用Ruby。

class MyFunc
  # Called when no arguments are passed to JavaScript function
  def call
    #Execute any ruby code here!!

    #You can also return values back to JavaScript!!
    return 1
  end

  # Called when arguments are passed to JavaScript function
  def value(*args)
    if args.length == 0
      # This will be called if the function is called without parenthesis in JS
      # e.g. console.log(document.someFunc)
      return nil
    else
      #This is called with the parsed arguments. Note: Functions passed in from JS are of type WIN32OLE. Theoretically this should be callable, but better would be to make a JS function which can call other JS functions
      #Execute any ruby code here!!
      puts "#{args.inspect}"

      #Can also return values here as well
      return 1
    end
  end
end
ie.document.setVar("myFunc",MyFunc.new})

您还可以初始化和访问实例变量:

class MyClass
  def initialize
    @hello = "world"
  end
end
ie.document.setVar("myClass",MyClass.new})

#IN IE: document.myClass["hello"] //=> "world"

注意:

某些事情可能会严重出错,甚至导致红宝石崩溃。某些不起作用的示例:

  • 直接评估对象:document.myObj。 JavaScript会将函数解释为Object,也许就像人们期望的那样。
  • 获取不存在的值不会做任何事情:document.myObj["hello"]
  • 设置不存在的值会导致ruby崩溃:document.myObj["hello"]=1

有些事情根本没有意义,例如,我做了以下循环:

上课:

class MyClass
  def call
    puts "Call"
  end
  def method_missing(m,*args,&block)
    puts "#{m}(#{args.inspect})"
  end
end
ie.document.setVar("obj",MyClass.new)

和JavaScript:

for(var i=0;i<24;i++){
  document.obj[chars[i]]()
}

这将执行以字母字符命名的obj的所有功能。确实,它在大多数情况下都这样做,但是有时却没有。有时它将调用主要的call方法,而在document.obj.j()的情况下,它将什么都不做...

完整日志:

a([])
b([])
c([])
d([])
e([])
f([])
Hello world
h([])
i([])
k([])
Hello world
m([])
n([])
o([])
q([])
s([])
t([])
Hello world
v([])
w([])
x([])
y([])
Hello world

编辑

I've written a GIST,这通常更容易实现。例如。要将File对象传递给IE,您可以执行以下操作:

ie.document.setVar("RubyFile",WIN32OLE::getDispatch(File))