代码之家  ›  专栏  ›  技术社区  ›  Sancarn

win32ole-将ruby函数注入internet explorer的javascript

  •  1
  • Sancarn  · 技术社区  · 6 年前

    在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 回复  |  直到 6 年前
        1
  •  0
  •   Sancarn    6 年前

    经过一周的网络搜索,我什么也没找到,我想“如果我们太天真了,把一件东西 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将把函数解释为一个对象,也许正如人们所期望的那样。
    • 获取不存在的价值并没有任何作用: 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))