有谁知道检测哪个版本的Office的最佳方法是什么?另外,如果安装了多个版本的Office,我想知道它们是什么版本。如果我能够检测到安装的Excel的特定版本,我将获得奖励。
答案 0 :(得分:69)
检查已安装的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
另一个不使用特定注册表项的选项是使用here所述的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版本的任何内容。
答案 1 :(得分:23)
HKEY_CLASSES_ROOT \ Word.Application \ CurVer怎么样?
答案 2 :(得分:16)
如果您在64位计算机上安装了32位Office,则可能需要检查是否存在“SOFTWARE \ Wow6432Node \ Microsoft \ Office \ 12.0 \”,并使用相应的版本替换12.0。对于安装在64位Windows 7上的Office 2007,情况确实如此。
请注意,Office 2010(== 14.0)是第一个存在64位版本的Office。
答案 3 :(得分:9)
我发现这个CodeProject帮助我解决了这个问题:http://www.codeproject.com/Articles/26520/Getting-Office-s-Version
答案 4 :(得分:8)
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;
}
}
}
答案 5 :(得分:5)
为什么不选中HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\[office.exe]
,其中[office.exe]
代表特定的办公产品exe-filename,例如winword.exe
,excel.exe
等
在那里,您将获得可执行文件的路径并检查该文件的版本。
对这种做法有任何批评吗?
答案 6 :(得分:2)
如果我能够检测到安装的Excel的特定版本,我将获得奖励。
我知道很久以前这个问题已被提出并得到解答,但同样的问题一直让我忙碌直到我做出这样的观察:
要获取内部版本号(例如15.0.4569.1506
),请调查HKLM\SOFTWARE\Microsoft\Office\[VER]\Common\ProductVersion::LastProduct
,其中[VER]
是主要版本号(Office 2007为12.0,Office 2010为14.0,Office 2013为15.0) )。
在64位Windows上,无论Office安装的位数如何,都需要在Wow6432Node
和SOFTWARE
面包屑之间插入Microsoft
。
在我的计算机上,这会提供最初安装版本的版本信息。例如,对于Office 2010,这些数字与列出的here匹配,它们与File > Help
中报告的版本不同,后者反映了修补程序应用的修补程序。
答案 7 :(得分:1)
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;
}
}
答案 8 :(得分:1)
当您想检测是否安装了“Office 2016”或“Office 2019”时,我找到了一种检测“Microsoft Office 版本”的优雅方法,这可能也有效。
我刚刚检测到“Microsoft Office”的安装路径,然后从“Office”应用程序的 exe 文件(在我的“Word”示例中)声明了 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”然后单击“属性”时获得的信息。看到这个: Detailes of winword.exe
答案 9 :(得分:0)
尽管这个问题早已得到回答,但我发现有一些有趣的事实与上述答案有关。
正如Dirk所述,从Office 365/2019开始,MS似乎存在一种奇怪的版本控制方式。您无法再通过查看可执行路径来区分这三个(2016、2019,O365)。就像他自言自语那样,看着可执行文件的构建,以此来告诉这是什么,也不是很有效。
经过研究,我找到了可行的解决方案。该解决方案位于注册表子项error.ejs
下。
所以,我的逻辑如下:
案例1 :如果计算机安装了MSOffice 2016,则Computer\HKEY_CURRENT_USER\Software\Microsoft\Office\16.0\Common\Licensing\LicensingNext
下没有子项。
案例2 :如果计算机安装了MSOffice 2019,则存在值的名称(这是Office产品ID之一)。 (例如Licensing
)
情况3 :如果计算机安装了Office365,则存在一个名为Standard2019Volume
(也是产品ID)的值以及一些其他值。
here提供了可能的productId。
要区分这三个,我只是打开了钥匙,看是否失败。如果打开失败,则其 Office 2016 。然后,我枚举o365bussinessretail
并尝试查看是否有任何名称带有前缀LicensingNext
的前缀(如果找到),然后为其 O365 。如果不是,则其 Office 2019 。
坦白说,我没有足够的时间在变化的环境下测试逻辑。所以请注意。
希望这会帮助任何感兴趣的人。
答案 10 :(得分:0)
对于可能关心的人,这是我的版本,用于检查32和64位系统上是否都支持基于MSI和ClickAndRun的Office 95-2019和O365(如果未安装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))
备注