Ruby:Watir无法连接到在“默认”桌面上的非管理员帐户下运行的IE

时间:2009-09-24 20:15:19

标签: windows ruby watir

需要应用程序架构的一些背景知识:

Windows 2003 / Apache-v2.2 / IE7 / Watir-v1.6.2 / Ruby-v1.8.5

  1. 在“localsystem”帐户下运行的Apache。
  2. 请求运行Watir脚本。
  3. Apache CGI在特定用户下启动IE7,例如'tester',并将IE7窗口附加到“默认”桌面环境。这允许我们进入机器VNC并查看所有运行帐户的所有IE7窗口。
  4. IE7通过插件将ruby嵌入到进程中并在线程中执行ruby脚本。
  5. 为了点击IE中的链接/按钮,Watir提供同步“点击”方法和异步“click_no_wait”方法。 'click_no_wait'产生一个全新的ruby进程,连接回IE7窗口,点击链接/按钮。

    这对我来说是失败的。由于click_no_wait正在产生一个新进程。它似乎无法看到IE7窗口连接到它并单击链接/按钮。 我必须使用'click_no_wait',因为IE弹出某个页面的对话框,以便另一个ruby线程可以关闭它。

    我尝试了一些事情: - 使用fire_event('OnClick')而不是click_no_wait挂起像'click'那样的脚本。 - 通过注释'@ container.wait'修改'click',但'click!'本身就是挂起等待对话框关闭的API。 - 让'click_no_wait'产生一个新线程而不是一个进程',但是其他线程似乎在'click!'时被挂起了。调用在该线程中执行。这很奇怪。 - 使用与生成IE7进程完全相同的代码执行'click_no_wait'进程,但仍无法找到任何IE7窗口。

    通过上面描述的'default'桌面,生成IE的代码基本上会执行一系列C ++调用,将IE7窗口附加到'winsta0'桌面:

    - LogonUser() // log in as tester account
    - OpenWindowStation("winsta0") // to get default desktop
    - SetProcessWindowStation()
    - // add the user to interactive window station using (GetUserObjectSecurity, GetSecurityDescriptorDacl, GetAclInformation, AddAce, SetSecurityDescriptorDacl, SetUserObjectSecurity)
    - // add user to "default" desktop using APIs listed above.
    - CreateEnvironmentBlock
    - ImpersonateLoggedOnUser
    - CreateProcessAsUser('iexplore.exe')   
    - // cleanup
    

    在特定用户IE7下运行以下Watir脚本正在yield:

    下运行
    $IE = Watir::IE.attach(:title, /Google/)
    $IE.button(:name, 'btnG').click!
    
      

    c:/ruby/lib/ruby/gems/1.8/gems/watir-1.6.2/lib/watir/ie-class.rb:246:在`method_missing'中:Windows(WIN32OLERuntimeError)       OLE错误代码:80040154 in                HRESULT错误代码:0x80020009         发生了异常。来自c:/ruby/lib/ruby/gems/1.8/gems/watir-1.6.2/lib/watir/ie-class.rb:246:in“each”

    其中包含:

    c:/ruby/lib/ruby/gems/1.8/gems/watir-1.6.2/lib/watir/ie-class.rb:246
    shell = WIN32OLE.new("Shell.Application")
    windows = shell.Windows   ## Fails here
    

    如果我能提供更多细节或消除歧义,请告诉我们! :)

    谢谢, 沙恩。

1 个答案:

答案 0 :(得分:0)

好的,我已经解决了自己的问题。

事实证明,Watir用于枚举IE窗口的方法(即Shell.Application)在用户空间中不起作用。因此,我必须编写一个中间应用程序来检索IE窗口的IWebBrowser2 COM指针,并修改'eval_in_spawned_process'Watir函数以将此句柄用于'pc = Watir :: IE.bind(iWebBrowserPtr)'。

我可能不需要外部应用程序来检索IWebBrowser2对象,但我不知道如何在Ruby中执行此操作,并且我已经拥有了一个可以用于此目的的IE BHO应用程序。< / p>

现在工作正常。 :)

的Watir /页-container.rb:56

# This evaluates a cmd (e.g. "button(:id, 1).click!") in a new ruby process
# This is to primarily avoid a script hanging while a modal dialog is displayed in IE.
# It gets an IE handle from our IE BHO based off of window handle.  It needs to do this 
# to get around the problem of finding the IE window itself using Shell.Application
# which does not work across User-contexts.
# Note: This change probably invalidates the Watir unit-test for this API.
def eval_in_spawned_process(command)
  command.strip!
  load_path_code = _code_that_copies_readonly_array($LOAD_PATH, '$LOAD_PATH')
  ruby_code = "require 'watir/ie'; "
  ruby_code << 'controller = WIN32OLE.new("HttpPlugin.Controller"); '
  ruby_code << "window = controller.BrowserFromHWND(#{hwnd}); "
  ruby_code << "pc = Watir::IE.bind(window); "
  ruby_code << "pc.#{command}; "
  exec_string = "start rubyw -e #{(load_path_code + '; ' + ruby_code).inspect}"
  result = system(exec_string)
end