运行 java 来自 VBA 中的宏 Windows 7 绕过 System32 / SysWOW64 javaw.exe
Running java from VBA macro in Windows 7 bypassing System32 / SysWOW64 javaw.exe
有没有办法绕过 32 位 java 版本(可能是在 VBA 中启动进程以调用 64 位版本 cmd、关闭 UAC 或一些其他类型的 tweek)被以下 VBA 代码 "forced" (这只是一个假设,我在下面解释调试过程):
handleDbl = Shell("javaw -cp theJar.jar com.java.SampleClass", vbNormalFocus)
这里的要点是我想分享我的宏并避免给接收者添加额外的指令所以我试图在代码上做所有事情(我在 VBA 代码上使用后期绑定以避免手动设置引用之类的东西)。
调试过程
出现错误,所以我改用了以下行:
handleDbl = Shell("cmd /k java -cp theJar.jar com.java.SampleClass", vbNormalFocus)
并得到错误 Exception in thread "main" java.lang.UnsupportedClassVersionError: Unsupported major.minor version
所以我检查了 java -version
并试图找出哪个 java 是 运行:
C:\>where java
C:\Windows\System32\java.exe
C:\Program Files\Java\_anyJava.x.x.x_\bin\java.exe
我去了 System32
文件夹,那里没有 java 但我知道 redirection 从那里发生到 C:\Windows\SysWOW64
所以我比较了之前提取的 java 版本反对 C:\Windows\SysWOW64\java.exe -version
,他们匹配。
之后我查看了我的Outlook版本,原来是32位的安装。这是一个提示,但主要是任务管理器中 cmd.exe 旁边的那个大 *32。我不知道 64 位 Outlook 是否会有所不同,或者因为 VBA 实现而相同,但这就是我得出 VBA 中的 Shell 函数的原因32 位 java 调用。
通常有一个 JAVA_HOME 环境变量集。如果是这样,那么您可以这样做:
Dim JavaExe As String
JavaExe = """" & Environ("JAVA_HOME") & "\bin\java.exe"""
handleDbl = Shell("cmd /k " & JavaExe & " -cp theJar.jar com.java.SampleClass", vbNormalFocus)
如果没有设置,你必须在编译命令之前通过一些搜索找到它。
Sam 的答案很好,但我只是对用户进行更多设置感到不安,所以我写了一些函数来检查 java 的版本并在不存在时通知用户(在那种情况下无论如何都必须安装 java)所以这是我的代码。它可能包含一些有用的东西。
Private Function IsJavaAvailable(ByVal displayMessage As Boolean, Optional ByVal isJavaMandatory As Boolean) As Boolean
Dim availability As Boolean
Dim minJavaVersion As Integer
minJavaVersion = 8
'isJavaSetup is a global variable
If (Not isJavaSetup) Then
javawPathQuoted = GetMinimumJavaVersion(minJavaVersion)
If StrComp(javawPathQuoted, "") <> 0 Then
isJavaSetup = True
End If
SetGlobalVars
End If
If javawPathQuoted = Empty Then
availability = False
Else
availability = True
End If
If (displayMessage) Then
If (isJavaMandatory) Then
If Not availability Then
MsgBox "This functionality is NOT available without Java " & minJavaVersion & "." & _
vbNewLine & vbNewLine & _
"Please install Java " & minJavaVersion & " or higher.", vbCritical, _
"Mimimum Version Required: Java " & minJavaVersion
End If
Else
If Not availability Then
MsgBox "Some features of this functionality were disabled." & _
vbNewLine & vbNewLine & _
"Please install Java " & minJavaVersion & " or higher.", vbExclamation, _
"Mimimum Version Required: Java " & minJavaVersion
End If
End If
End If
IsJavaAvailable = availability
End Function
Private Function GetMinimumJavaVersion(ByVal javaMinimumMajorVersionInt As Integer) As String
'Run a shell command, returning the output as a string
Dim commandStr As String
Dim javawPathVar As Variant
Dim javaPathStr As Variant
Dim javaVersionStr As String
Dim javaMajorVersionInt As Integer
Dim detectedJavaPaths As Collection
Dim javaVersionElements As Collection
Dim javaVersionOutput As Collection
Dim detectedJavaVersions As Collection
Dim suitableJavawPath As String
'Check available javaw executables in the SO
commandStr = "where javaw"
Set detectedJavaPaths = GetCommandOutput(commandStr)
Set detectedJavaVersions = New Collection
For Each javawPathVar In detectedJavaPaths
'Look for java.exe instead of javaw.exe by substituting it in path
' javaw.exe does NOT return version output like java.exe
javaPathStr = StrReverse(Replace(StrReverse(javawPathVar), StrReverse("javaw.exe"), StrReverse("java.exe"), , 1))
commandStr = """" & javaPathStr & """" & " -version"
Set javaVersionOutput = GetCommandOutput(commandStr)
javaVersionStr = javaVersionOutput.item(1)
Debug.Print "Getting java version: ", commandStr
Debug.Print "Version detected: "; javaVersionStr
Set javaVersionElements = SplitOnDelimiter(javaVersionStr, " ")
'Check that output is not an error or something else
'java version "1.8.0_75"
If javaVersionElements.Count > 2 Then
If StrComp(javaVersionElements.item(1), "java", vbTextCompare) = 0 Then
If StrComp(javaVersionElements.item(2), "version", vbTextCompare) = 0 Then
detectedJavaVersions.Add javaVersionStr
'Remove quotes from "1.8.0_75", split on '.', get 2nd item (java major version) and cast it to Integer
javaMajorVersionInt = CInt(SplitOnDelimiter(SplitOnDelimiter(javaVersionElements.item(3), """").item(1), ".").item(2))
'JAR will only run in Java 8 or later
If (javaMajorVersionInt >= javaMinimumMajorVersionInt) Then
'Validate that "javaw.exe" exists since the validation was made with "java.exe"
Debug.Print "Verifying if javaw.exe exists: ", javawPathVar
If Len(Dir(javawPathVar)) > 0 Then
suitableJavawPath = javawPathVar
Debug.Print "A suitable javaw.exe version found: ", suitableJavawPath
Exit For
End If
End If
End If
End If
End If
Next javawPathVar
GetMinimumJavaVersion = suitableJavawPath
End Function
Private Function GetCommandOutput(ByRef commandStr As String) As Collection
'Run a shell command, returning the output as a string
Dim shellObj As Object
Set shellObj = CreateObject("WScript.Shell")
'run command
Dim wshScriptExecObj As Object
Dim stdOutObj As Object
Dim stdErrObj As Object
Set wshScriptExecObj = shellObj.Exec(commandStr)
Set stdOutObj = wshScriptExecObj.StdOut
Set stdErrObj = wshScriptExecObj.StdErr
'handle the results as they are written to and read from the StdOut object
Dim fullOutputCollection As Collection
Set fullOutputCollection = New Collection
Dim lineStr As String
While Not stdOutObj.AtEndOfStream
lineStr = stdOutObj.ReadLine
If lineStr <> "" Then
fullOutputCollection.Add lineStr
End If
Wend
If fullOutputCollection.Count = 0 Then
While Not stdErrObj.AtEndOfStream
lineStr = stdErrObj.ReadLine
If lineStr <> "" Then
fullOutputCollection.Add lineStr
End If
Wend
End If
Set GetCommandOutput = fullOutputCollection
End Function
有没有办法绕过 32 位 java 版本(可能是在 VBA 中启动进程以调用 64 位版本 cmd、关闭 UAC 或一些其他类型的 tweek)被以下 VBA 代码 "forced" (这只是一个假设,我在下面解释调试过程):
handleDbl = Shell("javaw -cp theJar.jar com.java.SampleClass", vbNormalFocus)
这里的要点是我想分享我的宏并避免给接收者添加额外的指令所以我试图在代码上做所有事情(我在 VBA 代码上使用后期绑定以避免手动设置引用之类的东西)。
调试过程
出现错误,所以我改用了以下行:
handleDbl = Shell("cmd /k java -cp theJar.jar com.java.SampleClass", vbNormalFocus)
并得到错误 Exception in thread "main" java.lang.UnsupportedClassVersionError: Unsupported major.minor version
所以我检查了 java -version
并试图找出哪个 java 是 运行:
C:\>where java
C:\Windows\System32\java.exe
C:\Program Files\Java\_anyJava.x.x.x_\bin\java.exe
我去了 System32
文件夹,那里没有 java 但我知道 redirection 从那里发生到 C:\Windows\SysWOW64
所以我比较了之前提取的 java 版本反对 C:\Windows\SysWOW64\java.exe -version
,他们匹配。
之后我查看了我的Outlook版本,原来是32位的安装。这是一个提示,但主要是任务管理器中 cmd.exe 旁边的那个大 *32。我不知道 64 位 Outlook 是否会有所不同,或者因为 VBA 实现而相同,但这就是我得出 VBA 中的 Shell 函数的原因32 位 java 调用。
通常有一个 JAVA_HOME 环境变量集。如果是这样,那么您可以这样做:
Dim JavaExe As String
JavaExe = """" & Environ("JAVA_HOME") & "\bin\java.exe"""
handleDbl = Shell("cmd /k " & JavaExe & " -cp theJar.jar com.java.SampleClass", vbNormalFocus)
如果没有设置,你必须在编译命令之前通过一些搜索找到它。
Sam 的答案很好,但我只是对用户进行更多设置感到不安,所以我写了一些函数来检查 java 的版本并在不存在时通知用户(在那种情况下无论如何都必须安装 java)所以这是我的代码。它可能包含一些有用的东西。
Private Function IsJavaAvailable(ByVal displayMessage As Boolean, Optional ByVal isJavaMandatory As Boolean) As Boolean
Dim availability As Boolean
Dim minJavaVersion As Integer
minJavaVersion = 8
'isJavaSetup is a global variable
If (Not isJavaSetup) Then
javawPathQuoted = GetMinimumJavaVersion(minJavaVersion)
If StrComp(javawPathQuoted, "") <> 0 Then
isJavaSetup = True
End If
SetGlobalVars
End If
If javawPathQuoted = Empty Then
availability = False
Else
availability = True
End If
If (displayMessage) Then
If (isJavaMandatory) Then
If Not availability Then
MsgBox "This functionality is NOT available without Java " & minJavaVersion & "." & _
vbNewLine & vbNewLine & _
"Please install Java " & minJavaVersion & " or higher.", vbCritical, _
"Mimimum Version Required: Java " & minJavaVersion
End If
Else
If Not availability Then
MsgBox "Some features of this functionality were disabled." & _
vbNewLine & vbNewLine & _
"Please install Java " & minJavaVersion & " or higher.", vbExclamation, _
"Mimimum Version Required: Java " & minJavaVersion
End If
End If
End If
IsJavaAvailable = availability
End Function
Private Function GetMinimumJavaVersion(ByVal javaMinimumMajorVersionInt As Integer) As String
'Run a shell command, returning the output as a string
Dim commandStr As String
Dim javawPathVar As Variant
Dim javaPathStr As Variant
Dim javaVersionStr As String
Dim javaMajorVersionInt As Integer
Dim detectedJavaPaths As Collection
Dim javaVersionElements As Collection
Dim javaVersionOutput As Collection
Dim detectedJavaVersions As Collection
Dim suitableJavawPath As String
'Check available javaw executables in the SO
commandStr = "where javaw"
Set detectedJavaPaths = GetCommandOutput(commandStr)
Set detectedJavaVersions = New Collection
For Each javawPathVar In detectedJavaPaths
'Look for java.exe instead of javaw.exe by substituting it in path
' javaw.exe does NOT return version output like java.exe
javaPathStr = StrReverse(Replace(StrReverse(javawPathVar), StrReverse("javaw.exe"), StrReverse("java.exe"), , 1))
commandStr = """" & javaPathStr & """" & " -version"
Set javaVersionOutput = GetCommandOutput(commandStr)
javaVersionStr = javaVersionOutput.item(1)
Debug.Print "Getting java version: ", commandStr
Debug.Print "Version detected: "; javaVersionStr
Set javaVersionElements = SplitOnDelimiter(javaVersionStr, " ")
'Check that output is not an error or something else
'java version "1.8.0_75"
If javaVersionElements.Count > 2 Then
If StrComp(javaVersionElements.item(1), "java", vbTextCompare) = 0 Then
If StrComp(javaVersionElements.item(2), "version", vbTextCompare) = 0 Then
detectedJavaVersions.Add javaVersionStr
'Remove quotes from "1.8.0_75", split on '.', get 2nd item (java major version) and cast it to Integer
javaMajorVersionInt = CInt(SplitOnDelimiter(SplitOnDelimiter(javaVersionElements.item(3), """").item(1), ".").item(2))
'JAR will only run in Java 8 or later
If (javaMajorVersionInt >= javaMinimumMajorVersionInt) Then
'Validate that "javaw.exe" exists since the validation was made with "java.exe"
Debug.Print "Verifying if javaw.exe exists: ", javawPathVar
If Len(Dir(javawPathVar)) > 0 Then
suitableJavawPath = javawPathVar
Debug.Print "A suitable javaw.exe version found: ", suitableJavawPath
Exit For
End If
End If
End If
End If
End If
Next javawPathVar
GetMinimumJavaVersion = suitableJavawPath
End Function
Private Function GetCommandOutput(ByRef commandStr As String) As Collection
'Run a shell command, returning the output as a string
Dim shellObj As Object
Set shellObj = CreateObject("WScript.Shell")
'run command
Dim wshScriptExecObj As Object
Dim stdOutObj As Object
Dim stdErrObj As Object
Set wshScriptExecObj = shellObj.Exec(commandStr)
Set stdOutObj = wshScriptExecObj.StdOut
Set stdErrObj = wshScriptExecObj.StdErr
'handle the results as they are written to and read from the StdOut object
Dim fullOutputCollection As Collection
Set fullOutputCollection = New Collection
Dim lineStr As String
While Not stdOutObj.AtEndOfStream
lineStr = stdOutObj.ReadLine
If lineStr <> "" Then
fullOutputCollection.Add lineStr
End If
Wend
If fullOutputCollection.Count = 0 Then
While Not stdErrObj.AtEndOfStream
lineStr = stdErrObj.ReadLine
If lineStr <> "" Then
fullOutputCollection.Add lineStr
End If
Wend
End If
Set GetCommandOutput = fullOutputCollection
End Function