【发布时间】:2012-03-09 13:34:54
【问题描述】:
我有一个内部使用 java 的 C++ 程序(通过我的 C++ dll 包装内部使用 jvm.dll 的 WebLogic jsmc.dll)。
当我在运行我的程序之前设置 CLASSPATH 时,所有的 JAR 库都被找到并且程序可以正常运行。 当我在运行程序之前不设置 CLASSPATH 时,未找到 JAR,这当然是意料之中的。
现在,当我在运行我的程序之前设置了 CLASSPATH,但是 clear 程序代码中的这个 CLASSPATH 环境变量 在 加载我使用 java 的 dll 之前,很奇怪发生:仍然找到所有 JAR,并且程序运行起来好像一切正常。我已经通过几种方式验证了 CLASSPATH 确实从 env 变量中删除(例如,通过使用 ProcessExplorer 或通过打印其值)。
问题:
你能向我解释一下这种行为吗?我不想知道为什么 java 会忽略我设置的 CLASSPATH,但是 怎么可能 java 看到旧的 CLASSPATH 值,而不是当前的值?我强调,java 不可能以某种方式存储旧的 CLASSPATH 值,因为在旧值可用时未加载 java。
如何让 java 尊重进程环境变量的变化?
详情:
上面的问题只是我为探索我的真正问题所做的简化。我正在尝试从程序内部设置 CLASSPATH 并避免在外部设置它。但是java使用的是外部设置的CLASSPATH,不是我在程序里面设置的。
我使用 Windows API(GetEnvironmentVariableA、SetEnvironmentVariableA)读取和设置环境变量值。我已经验证了程序进程环境变量在以这种方式设置后确实发生了变化。在调用任何 java 方法之前,我什至从使用 java 的 dll 中打印了 CLASSPATH 值。我使用 ProcessMonitor 检查了 jvm.dll 确实在 CLASSPATH 被删除之后加载。我还试图排除从父进程读取 CLASSPATH 的可能性。现在我很确定在加载 jvm.dll 时,CLASSPATH 已经从进程环境中删除了。
我尝试了 Visual C++ 2010 测试程序和 HP LoadRunner C 编译器 (mmdrv.exe) vuser 脚本,结果相同。 LoadRunner 是我需要解决这个问题的主要原因。
【问题讨论】:
-
您是否仔细检查过正在使用的 CLASSPATH 只能来自父进程(例如,命令外壳),而不是来自例如存储在注册表中的默认环境变量值?
-
我设法让代码在 Visual Studio 中运行。将“jmsc.dll”标记为延迟加载就足够了(属性 -> 链接器 -> 输入 -> 延迟加载的 Dlls =“jmsc.dll”)。不幸的是,相同的代码在 LoadRunner 中的工作方式不同 - 即使 dll 被延迟加载,加载的 dll 仍然使用原始的 CLASSPATH,而不是修改后的。 :-((( 可能在 lr_load_dll() 的实现中有些怪癖。
-
一种可能的解释是 jmsc.dll 中包含或引用的 C 运行时可能会在启动时制作自己的环境变量副本。我不确定它们会如何在 jvm.dll 中结束:也许它使用相同的运行时,或者 jmsc.dll 出于某种原因明确地将 CLASSPATH 传递给 jvm.dll。您需要使用调试器查看它才能确定。
-
我已经测试过了。 1)jvm.dll 必须在创建 JVM 实例时显式分配类路径,请参见下面 Peter Cetinski 的回答和以下 cmets。 2)有人向我建议 MCVCRT.DLL 保留自己的环境副本。所以我把SetEnvironmentVariableA()改成了_putenv(),没有效果。 _putenv 在 msvcrt 中实现。
-
但也许您的程序没有使用与 jsmc.dll 相同的运行时实例?
标签: java windows visual-c++ classpath environment-variables