通过JNI从小程序调用DLL

8

我有一个“概念验证”项目涉及到一些陌生的领域。我的任务是将EFTPOS机连接到在我们内部网络浏览器中运行的应用程序。

我暂时忽略了EFTPOS dll,并使用我选择的编程语言(Delphi)创建了一个简单的JNI修饰DLL,它只是将一个字符串记录到c:\中的文本文件中,我可以成功地从本地Java应用程序调用它。

然而,当我创建一个applet来完成同样的事情,将其编译成.JAR,签名JAR并尝试通过网页上的Javascript调用applet中的方法时,它会失败。

我正在与一位高级Java人员合作,他认为这不可能实现,因为允许applet这样做本质上是“邪恶”的。

您可以在java.policy文件中放置一个条目以允许loadLibrary,以及allPermission,我已经尝试了许多类似这样的变化,但都没有成功,导致Java控制台中出现以下错误跟踪:

java.lang.ExceptionInInitializerError
  at app.TestApplet.LogAString(Unknown Source)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
  at java.lang.reflect.Method.invoke(Unknown Source)
  at sun.plugin.javascript.JSInvoke.invoke(Unknown Source)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
  at java.lang.reflect.Method.invoke(Unknown Source)
  at sun.plugin.javascript.JSClassLoader.invoke(Unknown Source)
  at sun.plugin.com.MethodDispatcher.invoke(Unknown Source)
  at sun.plugin.com.DispatchImpl.invokeImpl(Unknown Source)
  at sun.plugin.com.DispatchImpl$1.run(Unknown Source)
  at java.security.AccessController.doPrivileged(Native Method)
  at sun.plugin.com.DispatchImpl.invoke(Unknown Source)
Caused by: java.security.AccessControlException: access denied (java.lang.RuntimePermission loadLibrary.DLoggerImpl)
  at java.security.AccessControlContext.checkPermission(Unknown Source)
  at java.security.AccessController.checkPermission(Unknown Source)
  at java.lang.SecurityManager.checkPermission(Unknown Source)
  at java.lang.SecurityManager.checkLink(Unknown Source)
  at java.lang.Runtime.loadLibrary0(Unknown Source)
  at java.lang.System.loadLibrary(Unknown Source)
  at app.DLogger.<clinit>(Unknown Source)
  ... 16 more
java.lang.Exception: java.lang.ExceptionInInitializerError
  at sun.plugin.com.DispatchImpl.invokeImpl(Unknown Source)
  at sun.plugin.com.DispatchImpl$1.run(Unknown Source)
  at java.security.AccessController.doPrivileged(Native Method)
  at sun.plugin.com.DispatchImpl.invoke(Unknown Source)

关键问题似乎是“Caused by: java.security.AccessControlException: access denied (java.lang.RuntimePermission loadLibrary.DLoggerImpl)”,这暗示着一个权限问题。可能是我在处理策略文件或签名时出错了,或者Java天生不允许Applet获得这些权限,因为存在安全风险。
我的问题是,我是否在浪费时间?这能行吗?如果可以,该怎么做?
谢谢您的期待。
Mike

我认为值得一提的是,使用我们的Java小程序加载DLL时,大部分客户端(95%)可以无任何问题地执行该小程序。因此,这种行为必须有其他解释,可能是某种浏览器/JVM/操作系统组合导致了这种效果。 - davidecr
3个回答

15
你肯定能够完成这个任务。我在生产中有一个可以做到完全相同的 applet。即使你的applet已经签名,你仍然需要使用Access Controller来访问dll,而不能只调用 "loadlibrary"。你可以将此添加到Java策略文件中,但是由于以下原因,不建议这样做:1. 你可能无法访问用户的Java配置。2. 即使这是为了你自己公司的使用, 管理策略文件也是一件痛苦的事情,因为用户会下载一些 JRE,你的策略文件将被覆盖或忽略。
最好的选择是签署你的jar,并确保将你的加载库代码包装在特权代码块中,就像这样。
try
{
    AccessController.doPrivileged(new PrivilegedAction()
    {
        public Object run()
        {
            try
            {
                // privileged code goes here, for example:
                System.load("C:/Program Files/.../Mydll.dll");
                return null; // nothing to return
            }
            catch (Exception e)
            {
                System.out.println("Unable to load Mydll");
                return null;
            }
        }
     });
}
catch (Exception e)
{
    System.out.println("Unable to load Mydll");
}

你也可以使用System.loadlibrary(mydll.dll),但必须在Windows的路径上拥有dll文件夹,以便小程序可以找到它。

如果你需要一些调用JNI函数的源代码示例,请告诉我,我可以获取。


0
我唯一能建议的是查看该区域的源代码,尝试解密它是否因为缺乏权限而不允许或者根本不允许。不幸的是,你没有行号,这使得问题有点棘手。

0

我非常确定,除非它被“签名”,否则您无法从Applet中加载本地库,然后用户将获得接受对话框以允许或拒绝。也就是说,假设您可以在applet中执行JNI...从未尝试过。

祝你好运。


1
小程序已签名。问题归结为:1)我没有正确编写权限。2)Java 中某个地方已经硬编码了它无法完成。 - mcottle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接