[英]How to detect installed version of MS-Office?
有谁知道检测安装了哪个版本的 Office 的最佳方法是什么? 另外,如果安装了多个版本的 Office,我想知道它们是什么版本。 如果我能检测到安装的 Excel 的特定版本,那将是一个奖励。
检查安装的 Office 版本的一种方法是检查感兴趣的 Office 应用程序的InstallRoot
注册表项。
例如,如果您想检查是否安装了 Word 2007,您应该检查是否存在以下注册表项:
HKLM\Software\Microsoft\Office\12.0\Word\InstallRoot::Path
此项包含可执行文件的路径。
将 12.0(对于 Office 2007)替换为相应的版本号:
Office 97 - 7.0 Office 98 - 8.0 Office 2000 - 9.0 Office XP - 10.0 Office 2003 - 11.0 Office 2007 - 12.0 Office 2010 - 14.0 (sic!) Office 2013 - 15.0 Office 2016 - 16.0 Office 2019 - 16.0 (sic!)
其他应用程序有类似的键:
HKLM\Software\Microsoft\Office\12.0\Excel\InstallRoot::Path
HKLM\Software\Microsoft\Office\12.0\PowerPoint\InstallRoot::Path
或者您可以检查所有应用程序的公共根路径:
HKLM\Software\Microsoft\Office\12.0\Common\InstallRoot::Path
另一种不使用特定注册表项的选项是使用此处所述的MSIEnumProducts
API 查询 MSI 数据库。
顺便说一句,Microsoft 不正式支持不同 Office 版本的并行安装。 它们确实有些作用,但您可能会得到不想要的效果和不一致。
更新:Office 2019 和 Office 365
从 Office 2019 开始,基于 MSI 的设置不再可用,即点即用是现在部署 Office 的唯一方法。 连同对定期更新的 Office 365 的这种更改,Office 的主要/次要版本号也不再更新(至少目前是这样)。 这意味着 - 即使对于 Office 2019 - 注册表项中使用的值和Application.Version
返回的值(例如在 Word 中)仍然是16.0
。
暂时没有记录的方法来区分 Office 2016 和 Office 2019。线索可能是 winword.exe 的文件版本; 但是,此版本也会针对打过补丁的 Office 2016 版本增加(请参阅下面@antonio 的评论)。
如果您需要以某种方式区分 Office 版本,例如确保存在某个功能或安装了最低版本的 Office,这可能是查看主要 Office 应用程序之一的文件版本的最佳方式:
// Using the file path to winword.exe
// Retrieve the path e.g. from the InstallRoot Registry key
var fileVersionInfo = FileVersionInfo.GetVersionInfo(@"C:\Program Files (x86)\Microsoft Office\root\Office16\WINWORD.EXE");
var version = new Version(fileVersionInfo.FileVersion);
// On a running instance using the `Process` class
var process = Process.GetProcessesByName("winword").First();
string fileVersionInfo = process.MainModule.FileVersionInfo.FileVersion;
var version = Version(fileVersionInfo);
Office 2019 的文件版本是 16.0.10730.20102,所以如果你看到任何大于你正在处理的 Office 2019 或当前 Office 365 版本的内容。
HKEY_CLASSES_ROOT\\Word.Application\\CurVer 怎么样?
如果您在 64 位计算机上安装了 32 位 Office,您可能需要检查是否存在“SOFTWARE\\Wow6432Node\\Microsoft\\Office\\12.0\\”,用适当的版本替换 12.0。 安装在 64 位 Windows 7 上的 Office 2007 肯定就是这种情况。
请注意,Office 2010 (== 14.0) 是第一个存在 64 位版本的 Office。
我发现这个CodeProject帮助我解决了这个问题: http : //www.codeproject.com/Articles/26520/Getting-Office-s-Version
namespace Software_Info_v1._0
{
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Office.Interop;
public class MS_Office
{
public string GetOfficeVersion()
{
string sVersion = string.Empty;
Microsoft.Office.Interop.Word.Application appVersion = new Microsoft.Office.Interop.Word.Application();
appVersion.Visible = false;
switch (appVersion.Version.ToString())
{
case "7.0":
sVersion = "95";
break;
case "8.0":
sVersion = "97";
break;
case "9.0":
sVersion = "2000";
break;
case "10.0":
sVersion = "2002";
break;
case "11.0":
sVersion = "2003";
break;
case "12.0":
sVersion = "2007";
break;
case "14.0":
sVersion = "2010";
break;
default:
sVersion = "Too Old!";
break;
}
Console.WriteLine("MS office version: " + sVersion);
return null;
}
}
}
尽管这个问题很久以前就得到了回答,但我发现了一些与上述答案相关的有趣事实要补充。
正如 Dirk 提到的,从 Office 365 / 2019 开始,MS 似乎有一种奇怪的版本控制方式。您无法再通过查看可执行路径来区分这三个(2016、2019、O365)。 就像他自称的那样,查看可执行文件的构建,作为判断哪个是什么的手段,也不是很有效。
经过一番研究,我找到了一个可行的解决方案。 解决方案位于注册表子项Computer\\HKEY_CURRENT_USER\\Software\\Microsoft\\Office\\16.0\\Common\\Licensing\\LicensingNext
。
所以,我的逻辑如下:
案例1 :如果电脑安装了MSOffice 2016,则Licensing
下没有子项。
情况 2 :如果计算机安装了 MSOffice 2019,则有值的名称(Office 产品 ID 之一)。 (例如Standard2019Volume
)
情况 3 :如果计算机安装了 Office365,则有一个名为o365bussinessretail
(也是产品 ID)的值以及一些其他值。
为了区分这三个,我只是打开了钥匙,看看是否失败。 如果打开失败,其Office 2016 . 然后我枚举LicensingNext
并尝试查看是否有任何名称具有前缀o365
,如果找到它,则它的O365 。 如果没有,那么它的Office 2019 。
坦率地说,我没有足够的时间来测试不同环境下的逻辑。 所以请注意。
希望这对感兴趣的人有所帮助。
如果我可以检测到已安装的特定版本的 Excel,那将是一个奖励。
我知道这个问题很久以前就有人问过和回答过,但同样的问题让我很忙,直到我做出这个观察:
要获取内部版本号(例如15.0.4569.1506
),请探测HKLM\\SOFTWARE\\Microsoft\\Office\\[VER]\\Common\\ProductVersion::LastProduct
,其中[VER]
是主要版本号(Office 2007 为 12.0,Office 为 14.0 2010,Office 2013 为 15.0)。
在 64 位 Windows 上,您需要在SOFTWARE
和Microsoft
crumbs 之间插入Wow6432Node
,而不管 Office 安装的位数。
在我的机器上,这给出了最初安装版本的版本信息。 例如,对于 Office 2010,数字与此处列出的数字匹配,并且它们与File > Help
报告的版本不同,后者反映了修补程序应用的补丁。
public string WinWordVersion
{
get
{
string _version = string.Empty;
Word.Application WinWord = new Word.Application();
switch (WinWord.Version.ToString())
{
case "7.0": _version = "95";
break;
case "8.0": _version = "97";
break;
case "9.0": _version = "2000";
break;
case "10.0": _version = "2002";
break;
case "11.0": _version = "2003";
break;
case "12.0": _version = "2007";
break;
case "14.0": _version = "2010";
break;
case "15.0": _version = "2013";
break;
case "16.0": _version = "2016";
break;
default:
break;
}
return WinWord.Caption + " " + _version;
}
}
当您想检测是否安装了“Office 2016”或“Office 2019”时,我想出了一种检测“Microsoft Office 版本”的优雅方法,该方法可能也有效。
我刚刚检测到“Microsoft Office”的安装路径,然后从“Office”应用程序(在我的示例“Word”中)的 exe 文件中声明了一个 System.Diagnostics.FileVersionInfo,并从这个 FileVersionInfo 中获得了我需要的一切。
以下是一个非常小的控制台应用程序的完整代码作为示例:
using System;
using System.IO;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Sandbox_Console
{
public class Program
{
static void Main(string[] args)
{
string installpath = GetOfficeInstallPath();
OfficeVersionInfo info = new OfficeVersionInfo(installpath);
Console.WriteLine("Full Office Version Number: " + info.FullVersionNumber);
Console.WriteLine("Full Office Name: " + info.FullOfficeVersionName);
Console.Write("Press any key to end this program...");
Console.ReadKey();
}
public class OfficeVersionInfo
{
private string _FullVersionNumber = "";
private string _FullOfficeVersionName = "";
public string FullVersionNumber { get { return _FullVersionNumber; } }
public string FullOfficeVersionName { get { return _FullOfficeVersionName; } }
public OfficeVersionInfo(string installPath)
{
string filepath = installPath + "\\winword.exe"; //For Excel, PowerPoint or others use the exe-files for them.
if (File.Exists(filepath))
{
FileVersionInfo info = FileVersionInfo.GetVersionInfo(filepath);
_FullVersionNumber = info.ProductVersion;
_FullOfficeVersionName = info.ProductName;
}
}
}
public static string GetOfficeInstallPath()
{
string result = "";
try
{
Type appType = Type.GetTypeFromProgID("Word.Application"); //Also works with Excel, PowerPoint or others.
dynamic appInstance = Activator.CreateInstance(appType);
result = appInstance.Path;
appInstance.quit();
Marshal.ReleaseComObject(appInstance);
} catch (Exception exc)
{
Debug.Print(exc.Message);
}
return result;
}
}
}
代码示例中存储在“OfficeVersionInfo”中的信息是您左键单击“winword.exe”然后单击“属性”时获得的信息。 请参阅: winword.exe 的详细信息
对于可能关心的任何人,这是我的版本,用于检查 Office 95-2019 和 O365,在 32 位和 64 位系统上均支持基于 MSI 和 ClickAndRun(在未安装 64 位版本时回退到 32 位)。
用 Python 3.5 编写,但当然你总是可以使用该逻辑来用另一种语言编写自己的代码:
from winreg import *
from typing import Tuple, Optional, List
# Let's make sure the dictionnary goes from most recent to oldest
KNOWN_VERSIONS = {
'16.0': '2016/2019/O365',
'15.0': '2013',
'14.0': '2010',
'12.0': '2007',
'11.0': '2003',
'10.0': '2002',
'9.0': '2000',
'8.0': '97',
'7.0': '95',
}
def get_value(hive: int, key: str, value: Optional[str], arch: int = 0) -> str:
"""
Returns a value from a given registry path
:param hive: registry hive (windows.registry.HKEY_LOCAL_MACHINE...)
:param key: which registry key we're searching for
:param value: which value we query, may be None if unnamed value is searched
:param arch: which registry architecture we seek (0 = default, windows.registry.KEY_WOW64_64KEY, windows.registry.KEY_WOW64_32KEY)
Giving multiple arches here will return first result
:return: value
"""
def _get_value(hive: int, key: str, value: Optional[str], arch: int) -> str:
try:
open_reg = ConnectRegistry(None, hive)
open_key = OpenKey(open_reg, key, 0, KEY_READ | arch)
value, type = QueryValueEx(open_key, value)
# Return the first match
return value
except (FileNotFoundError, TypeError, OSError) as exc:
raise FileNotFoundError('Registry key [%s] with value [%s] not found. %s' % (key, value, exc))
# 768 = 0 | KEY_WOW64_64KEY | KEY_WOW64_32KEY (where 0 = default)
if arch == 768:
for _arch in [KEY_WOW64_64KEY, KEY_WOW64_32KEY]:
try:
return _get_value(hive, key, value, _arch)
except FileNotFoundError:
pass
raise FileNotFoundError
else:
return _get_value(hive, key, value, arch)
def get_keys(hive: int, key: str, arch: int = 0, open_reg: HKEYType = None, recursion_level: int = 1,
filter_on_names: List[str] = None, combine: bool = False) -> dict:
"""
:param hive: registry hive (windows.registry.HKEY_LOCAL_MACHINE...)
:param key: which registry key we're searching for
:param arch: which registry architecture we seek (0 = default, windows.registry.KEY_WOW64_64KEY, windows.registry.KEY_WOW64_32KEY)
:param open_reg: (handle) handle to already open reg key (for recursive searches), do not give this in your function call
:param recursion_level: recursivity level
:param filter_on_names: list of strings we search, if none given, all value names are returned
:param combine: shall we combine multiple arch results or return first match
:return: list of strings
"""
def _get_keys(hive: int, key: str, arch: int, open_reg: HKEYType, recursion_level: int, filter_on_names: List[str]):
try:
if not open_reg:
open_reg = ConnectRegistry(None, hive)
open_key = OpenKey(open_reg, key, 0, KEY_READ | arch)
subkey_count, value_count, _ = QueryInfoKey(open_key)
output = {}
values = []
for index in range(value_count):
name, value, type = EnumValue(open_key, index)
if isinstance(filter_on_names, list) and name not in filter_on_names:
pass
else:
values.append({'name': name, 'value': value, 'type': type})
if not values == []:
output[''] = values
if recursion_level > 0:
for subkey_index in range(subkey_count):
try:
subkey_name = EnumKey(open_key, subkey_index)
sub_values = get_keys(hive=0, key=key + '\\' + subkey_name, arch=arch,
open_reg=open_reg, recursion_level=recursion_level - 1,
filter_on_names=filter_on_names)
output[subkey_name] = sub_values
except FileNotFoundError:
pass
return output
except (FileNotFoundError, TypeError, OSError) as exc:
raise FileNotFoundError('Cannot query registry key [%s]. %s' % (key, exc))
# 768 = 0 | KEY_WOW64_64KEY | KEY_WOW64_32KEY (where 0 = default)
if arch == 768:
result = {}
for _arch in [KEY_WOW64_64KEY, KEY_WOW64_32KEY]:
try:
if combine:
result.update(_get_keys(hive, key, _arch, open_reg, recursion_level, filter_on_names))
else:
return _get_keys(hive, key, _arch, open_reg, recursion_level, filter_on_names)
except FileNotFoundError:
pass
return result
else:
return _get_keys(hive, key, arch, open_reg, recursion_level, filter_on_names)
def get_office_click_and_run_ident():
# type: () -> Optional[str]
"""
Try to find the office product via clickandrun productID
"""
try:
click_and_run_ident = get_value(HKEY_LOCAL_MACHINE,
r'Software\Microsoft\Office\ClickToRun\Configuration',
'ProductReleaseIds',
arch=KEY_WOW64_64KEY |KEY_WOW64_32KEY,)
except FileNotFoundError:
click_and_run_ident = None
return click_and_run_ident
def _get_used_word_version():
# type: () -> Optional[int]
"""
Try do determine which version of Word is used (in case multiple versions are installed)
"""
try:
word_ver = get_value(HKEY_CLASSES_ROOT, r'Word.Application\CurVer', None)
except FileNotFoundError:
word_ver = None
try:
version = int(word_ver.split('.')[2])
except (IndexError, ValueError, AttributeError):
version = None
return version
def _get_installed_office_version():
# type: () -> Optional[str, bool]
"""
Try do determine which is the highest current version of Office installed
"""
for possible_version, _ in KNOWN_VERSIONS.items():
try:
office_keys = get_keys(HKEY_LOCAL_MACHINE,
r'SOFTWARE\Microsoft\Office\{}'.format(possible_version),
recursion_level=2,
arch=KEY_WOW64_64KEY |KEY_WOW64_32KEY,
combine=True)
try:
is_click_and_run = True if office_keys['ClickToRunStore'] is not None else False
except:
is_click_and_run = False
try:
is_valid = True if office_keys['Word'] is not None else False
if is_valid:
return possible_version, is_click_and_run
except KeyError:
pass
except FileNotFoundError:
pass
return None, None
def get_office_version():
# type: () -> Tuple[str, Optional[str]]
"""
It's plain horrible to get the office version installed
Let's use some tricks, ie detect current Word used
"""
word_version = _get_used_word_version()
office_version, is_click_and_run = _get_installed_office_version()
# Prefer to get used word version instead of installed one
if word_version is not None:
office_version = word_version
version = float(office_version)
click_and_run_ident = get_office_click_and_run_ident()
def _get_office_version():
# type: () -> str
if version:
if version < 16:
try:
return KNOWN_VERSIONS['{}.0'.format(version)]
except KeyError:
pass
# Special hack to determine which of 2016, 2019 or O365 it is
if version == 16:
if isinstance(click_and_run_ident, str):
if '2016' in click_and_run_ident:
return '2016'
if '2019' in click_and_run_ident:
return '2019'
if 'O365' in click_and_run_ident:
return 'O365'
return '2016/2019/O365'
# Let's return whatever we found out
return 'Unknown: {}'.format(version, click_and_run_ident)
if isinstance(click_and_run_ident, str) or is_click_and_run:
click_and_run_suffix = 'ClickAndRun'
else:
click_and_run_suffix = None
return _get_office_version(), click_and_run_suffix
您可以使用如下示例所示的代码:
office_version, click_and_run = get_office_version()
print('Office {} {}'.format(office_version, click_and_run))
评论
试试这个(适用于所有 Office 版本):
ManagementObjectSearcher LicenseSearcher =
new ManagementObjectSearcher("root\\CIMV2",
"SELECT name, LicenseStatus,Description,PartialProductKey FROM SoftwareLicensingProduct where name like '%office%'");
foreach (ManagementObject LSObj in LicenseSearcher.Get())
{
String prod_name = LSObj["Name"].ToString();
String prod_description = LSObj["Description"].ToString();
String prod_key = "";
try
{
prod_key = LSObj["PartialProductKey"].ToString();
}
catch
{
prod_key = "";
}
String prod_lic_sta= LSObj["LicenseStatus"].ToString();
switch (prod_lic_sta)
{
case "0":
prod_lic_sta = "Unlicensed";
break;
case "1":
prod_lic_sta = "Licensed";
break;
case "2":
prod_lic_sta = "OOBGrace";
break;
case "3":
prod_lic_sta = "OOTGrace";
break;
case "4":
prod_lic_sta = "NonGenuineGrace";
break;
case "5":
prod_lic_sta = "Notification";
break;
case "6":
prod_lic_sta = "ExtendedGrace";
break;
}
}
Output:
办公室 19
Office19HomeBusiness2019R_零售版
密钥:XXXXX
状态:许可
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.