简体   繁体   中英

How to programmatically distinguish Excel 2019 from 2016?

I maintain a diagnostic that programmatically determines the version of MS Office applications, including Excel and Word. It has worked correctly for MS Office versions 2003, 2007, 2010, 2013, and 2016. But now I find that it incorrectly reports MS Office 2019 applications as MS Office 2016.

Eight years ago, MA Hanin posted a similar question:

Identifying Excel version programmatically

mathieu's reply, the accepted answer, correlated numbers used to identify MS Office in the registry versus the product versions. For instance, the number 14.0 corresponded to Office 2010. Doug Glancy directly addressed the question with VB code that prints the version property of Excel Application object:

https://docs.microsoft.com/en-us/office/vba/api/excel.application.version

Here is a VB Script that diagnoses which, if any, version of Excel is installed to the system:

On Error Resume Next
Set excelApp = CreateObject("Excel.Application") 
If Err.Number <> 0 Then
    WScript.Echo "Excel is not installed"
Else
    Wscript.Echo "Excel Version: " & excelApp.Version 
End If

The diagnostic faithfully reports MS Office versions consistent with the post from 2011. Since then, it reports 15.0 for Office 2013, and 16.0 for Office 2016. Recently, though, I was surprised to find that it also reports 16.0 for Office 2019. That is just not right! The 2016 and 2019 feature sets are clearly distinct, so they should not be lumped together:

https://support.office.com/en-us/article/what-s-new-in-office-2019-5077cbbe-0d94-44cc-b30e-654e37629b0c?ui=en-US&rs=en-US&ad=US

Is there an alternate way to programmatically distinguish Office 2016 from Office 2019?

A workaround is to parse the version number from output of the MS Office Client Software License Management Tool, OSPP.VBS, run with the /dstatus option. Here is a sample CMD script that demonstrates the workaround:

:: GetOfficeVer.cmd - Print the version of a licensed MS Office package.
::   Prerequisite:
::      Copy this cmd script to a folder including these MS Office files:
::          * OSPP.VBS    - MS Office Software Protection Platform script.
::          * OSPP.HTM    - Help file for OSPP.VBS.
::          * SLERROR.XML - Data file for OSPP.VBS.
::   Syntax:
::      GetOfficeVer [ComputerName[ PackageAbbr]]
::        ComputerName    - Windows system name  (defaults to local system)
::        PackageAbbr     - Package abbreviation (list below is not exhaustive)
::          *  ProPlus    - Office Professional Plus (default)
::          *  VisioPro   - Visio Professional
::          *  InfoPath   - InfoPath Designer
::   Return Values:
::          *  If the package is licensed, print the MS Office package version
::             string using the MS Office Application.Version property format.
::          *  If the package is unlicensed, print an empty line.
@echo off
setlocal ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
if %2_==_ (set MSO_PKG=ProPlus) else (set MSO_PKG=%2)
set "MSO_PKG_LIC=cscript "%~dp0\OSPP.VBS" /dstatus %1 | findstr /R /C:"^LICENSE NAME:.*%MSO_PKG%""
for /f "tokens=1-4 delims=, " %%G in ('!MSO_PKG_LIC!') do (set MSO_VER=%%J)
if %MSO_VER%_==_ (echo.) else ( echo %MSO_VER%.0)
endlocal

Tips on using OSPP.VBS:

  • It can take a few seconds to execute.
  • It is included in the folder stored in the Application.Path property.
  • It does not require MS Office to be installed to the system it is run from.
  • It does not need to be run as elevated for this purpose.
  • It will fail if the target system is in need of a restart.
  • The versions with 2013, 2016, and 2019 each work versus all three versions.

Yes, v16 can be 2016 or 2019

This works for version for me.

:GetOfficeVer
set vbs="%temp%\_.vbs"
if exist %vbs% del /f /q %vbs%
    >%vbs% @echo off
    >>%vbs% echo Option Explicit ' Enforce variable declaration
    >>%vbs% echo Dim oShell
    >>%vbs% echo Dim lOfficeVersion
    >>%vbs% echo Set oShell = CreateObject("WScript.Shell")
    >>%vbs% echo On Error Resume Next
    >>%vbs% echo lOfficeVersion = GetOfficeVersionNumber() 
    >>%vbs% echo MsgBox "OfficeVersion = " ^& lOfficeVersion
    >>%vbs% echo     Function GetOfficeVersionNumber()
    >>%vbs% echo         GetOfficeVersionNumber = "" 
    >>%vbs% echo         Dim sTempValue
    >>%vbs% echo         sTempValue = oShell.RegRead("HKCR\Excel.Application\CurVer\")
    >>%vbs% echo         If Len(sTempValue) ^> 2 Then GetOfficeVersionNumber = Replace(Right(sTempValue, 2), ^".^", ^"^")
    >>%vbs% echo     End Function   
cscript //nologo %vbs%
pause
if exist %vbs% del /f /q %vbs%
endlocal
goto :EOF

To expand the answers already given, it looks like OSPP.VBS is sadly the sanest way to get the info we need to differentiate between Office 2016, 2019, and 365.

Instead of executing cscript OSPP.VBS /dstatus , it's possible to get the same information by implementing the WMI queries used by OSPP.VBS ourselves (here in C#):

// Implementation is based on the OSPP.VBS file in the Office directory,
// when it executes the /dstatus command...
// result examples:
// - Office 16, Office16StandardVL_MAK edition
// - Office 19, Office19Standard2019VL_KMS_Client_AE edition
// - Office 16, Office16O365ProPlusR_Subscription1 edition
// - Office 15, OfficeStandardVL_MAK edition

// This constant is apparently the same for all Office versions:
const string officeAppId = "0ff1ce15-a989-479d-af46-f275c6370663";

// Note: OSPP.VBS uses == instead of <= but it seems wrong...
string productClass;
if (Environment.OSVersion.Version <= new Version(6, 1)) // Windows 7 or below
    productClass = "OfficeSoftwareProtectionProduct";
else
    productClass = "SoftwareLicensingProduct";

// Get the product name for all Office products having a product key:
var query = $"SELECT Name FROM {productClass} where "
+ $"ApplicationID=\"{officeAppId}\" AND PartialProductKey <> NULL AND PartialProductKey <> \"\"";

using (var searcher = new System.Management.ManagementObjectSearcher(query))
{
    var result = new List<string>();
    foreach (var instance in searcher.Get())
    {
        result.Add(instance.Properties["Name"].Value?.ToString() ?? "Null");
    }
    
    // result now contains a list of license names with the same format as `cscript OSPP.VBS /dstatus`
}

You could try to parse excelApp.Path to find out the installation path. This would work if the new office is installed in C:* \\Office 19\\Excel.exe

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM