2

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

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

  1. Apache 在“localsystem”帐户下运行。
  2. 请求运行 Watir 脚本。
  3. Apache CGI 在特定用户(例如“tester”)下启动 IE7,并将 IE7 窗口附加到“默认”桌面环境。这使我们可以 VNC 进入机器并从所有运行的帐户中查看所有 IE7 窗口。
  4. IE7通过插件将ruby嵌入到进程中,并在线程中执行ruby脚本。

对于点击 IE 中的链接/按钮,Watir 提供了同步的“click”方法和异步的“click_no_wait”方法。'click_no_wait' 生成一个全新的 ruby​​ 进程以连接回 IE7 窗口以单击链接/按钮。

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

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

通过上述“默认”桌面,生成 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:in `method_missing': Windows (WIN32OLERuntimeError) OLE 错误代码:HRESULT 错误中的 80040154代码:0x80020009 发生异常。来自 c:/ruby/lib/ruby/gems/1.8/gems/watir-1.6.2/lib/watir/ie-class.rb:246:in "每个"

其中包含:

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

让我知道我是否可以提供更多细节或消除歧义!:)

谢谢,谢恩。

4

1 回答 1

0

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

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

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

这现在工作正常。:)

Watir/page-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
于 2009-09-29T00:12:58.987 回答