如何从Javascript启动两个或多个自定义URL协议

时间:2014-04-16 00:28:45

标签: javascript html onclick url-protocol

我有一个旧的html页面,它创建一个脚本文件并使用以下命令执行它:

fsoObject = new ActiveXObject("Scripting.FileSystemObject")
wshObject = new ActiveXObject("WScript.Shell")

我正在尝试修改它并使其也可以从其他浏览器使用。如果你知道答案停止阅读,请回答。如果没有快速回答,这里是我的尝试的描述。我成功地完成了这项工作,但只有当脚本短于2000个字符时才会这样做。我需要帮助超过2000个字符的脚本。

该网页仅供内部使用,因此我可以轻松地在从网络驱动器运行VBScript文件的每台计算机上创建自定义URL协议。

我创建了我的custom URL Protocol,它启动了一个像这样的VBScript文件:

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\MyUrlProtocol]
"URL Protocol"=""
@="Url:MyUrlProtocol"
"UseOriginalUrlEncoding"=dword:00000001

[HKEY_CLASSES_ROOT\MyUrlProtocol\DefaultIcon]
@="C:\\Windows\\System32\\WScript.exe"

[HKEY_CLASSES_ROOT\MyUrlProtocol\shell]

[HKEY_CLASSES_ROOT\MyUrlProtocol\shell\open]

[HKEY_CLASSES_ROOT\MyUrlProtocol\shell\open\command]
@="C:\\Windows\\System32\\WScript.exe \"X:\\MyUrlProtocol.vbs\" \"%1\""

MyUrlProtocol.vbs我有这个:

MsgBox "The length of the link is " & Len(WScript.Arguments(0)) & " characters"
MsgBox "The content of the link is: " & WScript.Arguments(0)

当我点击<a href="MyUrlProtocol:test" id="test">click me</a>时,我看到两条消息,因此一切正常(在Windows 7中使用Chrome和IE进行测试。)

当我执行document.getElementById("test").click()

时,它也有效

我认为这可能是解决方案:我会将脚本文本传递给VBS静态脚本,该脚本将创建动态脚本并运行它,但是使用此系统,我无法传递超过~2000个字符。

所以我尝试将脚本的文本分成小于2000个字符的块,并模拟链接上的几次点击,但只有第一个工作。

所以我尝试使用xmlhttp.open("GET","MyUrlProtocol:test",false);,但Chrome说Cross origin requests are only supported for HTTP

是否可以通过自定义URL协议将超过2000个字符传递给VBScript脚本?

如果没有,是否可以按顺序调用多个自定义URL协议?

如果没有,是否有其他方法可以创建脚本文件并从Javascript运行它?

编辑1

我找到了一个解决方案,但在Chrome中只有在喜欢的时候才能正常工作,所以我又回到原点。

IE中的以下代码执行脚本4次(正确),但在Chrome中只运行第一次执行。

如果我将其更改为delay += 2000,则Chrome通常会运行脚本2次,但有时会运行1次,有时会运行3次甚至4次。

如果我将其更改为delay += 10000,那么它通常会运行脚本4次,但有时会错过一次。

该功能总是在Chrome和IE中执行4次。奇怪的是sr.click()有时什么也不做,函数执行仍在继续。

<HTML>
<HEAD>
  <script>
    var delay;

    function runScript(text) {
      setTimeout(function(){runScript2(text)}, delay);
      delay += 100;
    }

    function runScript2(text) {
      var sr = document.getElementById('scriptRunner');
      sr.href='intelliclad:'+text;
      sr.click();
    }

    function test(){
      delay = 0;
      runScript("uno");
      runScript("due");
      runScript("tre");
      runScript("quattro");
    }
  </script>
</HEAD>
<BODY>
  <input type="button" value="Run test" onclick="test()">
  <a href="nothing yet" id="scriptRunner">scriptRunner</a>
</BODY>
</HMTL>

编辑2

我尝试了Luke的建议,即在回叫中设置下一个超时但没有任何改变(IE随时可用,Chrome随时可用)。

这是新代码:

var scripts;
var delay = 2000;

function runScript() {
  var sr = document.getElementById('scriptRunner');
  sr.href = 'intelliclad:' + scripts.shift();
  sr.click();

  if(scripts.length)
    setTimeout(function() {runScript()}, delay);
}

function test(){
  scripts = ["uno", "due", "tre", "quattro"];
  runScript();
}

一些背景:页面询问面板的形状,这可能只是几个参数[nfaces=1, shape1='square', width1=100]或数百个参数,面板有很多面,许多插槽,许多紧固件等等。生成内部3D CAD(可能大于20KB)的脚本参数,启动CAD并要求执行脚本。

我想在客户端做所有事情,因为该页面由Domino Web服务器提供服务,甚至无法管理这样复杂的脚本。

3 个答案:

答案 0 :(得分:4)

我没看完你的全部帖子......得到答案:

我也希望自定义网址协议可以处理长网址。他们根本就没有。 IE更糟糕,因为一些操作系统只接受800个字符。

所以,这是解决方案:

For long urls, only pass a single use token.   The vbscript uses the token 
and does a url get to your web server to get all of the data.

这是我能够成功传递大量数据的唯一方法。如果您找到更清晰的解决方案,请记得在此处发布。

<强>更新

请注意,这是我发现处理url协议限制的最佳方法。我也希望这不是必要的。这确实有效并且效果很好。

你提到了Dominos,所以你可能需要POS环境中的东西......我创建了一个基于Web的POS系统,所以我们可能面临很多相同的问题。

假设您想要一个自定义网址将pdf打印到默认打印机而不会​​出现恼人的弹出窗口。我们需要每天做成千上万次......

  1. 在构建网页时,添加打印按钮,按下时调用自定义网址:myproto:// printpdf?id = 12345&amp; tocken = onetimetoken

  2. 这将在本地桌面上执行您的vbscript

  3. 在你的vbscript中
  4. ,解析参数并做出反应。在这种情况下,您的命令是printpdf,id是123456,并且您有一次性的tocken密钥。

  5. 将https的vb脚本转到:https://mydomain.com/APIs/printpdf.whatever?id=12345&key=onetimetoken

  6. 根据ip地址和令牌检查凭据,如果所有对齐,则返回pdf的内容(您可能希望将pdf转换为字节数组字符串)

  7. 现在vbscript有pdf,汇编它并将其写入临时文件夹然后执行一个无声的pdf打印命令(我使用苏门答腊PDF http://blog.kowalczyk.info/software/sumatrapdf/free-pdf-reader.html

  8. 任务完成。

  9. 由于我确实知道您在自定义网址和常规工作流程中要做什么,因此我只能说明我是如何解决排序网址问题的。

    使用这种技术,可能性是无限的。您可以完全控制运行Web浏览器的本地计算机,您可以使用一次性使用令牌来授予对Web API的访问权限,并且可以返回您编写的任何类型的信息。

    如果您愿意,可以编写自定义网址协议来打开比萨饼烤箱:)

    如果您无法创建正在侦听vbscript的get请求的服务器端代码,那么这将无效。

    您可以使用剪贴板将数据从浏览器传递到vbscript。

    更新2:

    由于在这种情况下数据在客户端上(一个表单可以定义数百个参数),因此服务器API不知道应该对vb脚本请求回答什么。因此,上述工作流程必须先执行以下两个步骤:

    1. onkeypress事件执行提交以将当前参数发送到服务器

    2. 服务器使用刷新的表单进行回复,向正文onload添加对函数的调用,该函数使用另一个提交来调用自定义网址,如上面第1点所述。

    3. 更新3: stenci,您添加的内容(在Update 2中)将起作用。我会这样做:

      1. 用户按下一个按钮,表示我已完成编辑表格
      2. ajax将表单发布到服务器
      3. 服务器保存数据并将唯一密钥附加到数据存储区
      4. 服务器将密钥返回给ajax回调函数
      5. 现在客户端只有一个使用密钥,并调用传递密钥的URL模式
      6. vbscript执行https到达服务器并传递密钥
      7. 服务器将数据返回到vbscript
      8. 有点长啰嗦。一旦编码,它将像魅力一样工作。

        我能看到的唯一其他选择是使用以下内容将表单数据复制到剪贴板:http://zeroclipboard.org/

        然后在vbscript中查看是否可以阅读剪贴板,如:Use clipboard from VBScript

答案 1 :(得分:2)

如何为每个实例创建iFrame? 像这样:

function runScript(text) {
  var iframe = document.createElement('iframe');
  iframe.src = 'intelliclad:'+text;
  document.body.appendChild(iframe);
}

function test(){
  runScript("uno");
  runScript("due");
  runScript("tre");
  runScript("quattro");
}

然后,您可以使用CSS样式来使这些iframe透明/隐藏。

答案 2 :(得分:0)

你可能不喜欢这个答案,但我过去使用过这种方法并且有效。

不要依赖ActiveX,而应考虑使用Java Applet和JNI。

基本上,您必须确保要运行的本机脚本在客户端计算机上以及JNI包装器上可用。

applet必须至少是自签名的,浏览器允许它加载和访问本机库。加载JNI库后,您可以轻松地从页面/小程序中调用方法。

由于使用Java,您可以使用相同的applet用于Windows以及Linux客户端,前提是您在相应的客户端上都有本机库。

这一系列文章准确地讨论了您的问题:http://www.javaworld.com/article/2076775/java-security/escape-the-sandbox--access-native-methods-from-an-applet.html

P.S这篇文章真的很老了,但概念仍未改变。