|
Option Explicit |
|
|
|
#Const TARGET_APP_NAME = "Excel" ' "Excel" / "Word" |
|
|
|
#If TARGET_APP_NAME = "Excel" Then |
|
Function GetExcelVersion() As String |
|
Application.Volatile |
|
Dim ExcelVersion As String |
|
On Error Resume Next |
|
ExcelVersion = GetOfficeVersion() |
|
If Err.Number <> 0 Then |
|
'[備忘] 一部の環境[^1]ではGetOfficeVersion()(から内部的に呼び出されるGetOfficeAppId()等)がエラーになるため、その場合は関数有無で判別 |
|
' [^1] プリインストール版(Microsorft Store版・UWPアプリ)のOffice等)ではOSPP.VBSが見つからない |
|
If IsError([CONCAT(1)]) Then |
|
ExcelVersion = "2016" |
|
ElseIf IsError([SEQUENCE(1)]) Then |
|
ExcelVersion = "2019" |
|
ElseIf IsError([LAMBDA(1)()]) Then |
|
ExcelVersion = "2021" |
|
Else |
|
ExcelVersion = "365" |
|
End If |
|
End If |
|
GetExcelVersion = IIf(ExcelVersion = "", Application.Version, ExcelVersion) |
|
End Function |
|
#End If |
|
|
|
Function GetOfficeVersion() As String |
|
Static OfficeVersion As String |
|
If OfficeVersion <> "" Then |
|
GetOfficeVersion = OfficeVersion |
|
Exit Function |
|
End If |
|
If CLng(Application.Version) < 16 Then |
|
Select Case Application.Version |
|
Case "15.0" |
|
OfficeVersion = "2013" |
|
Case "14.0" |
|
OfficeVersion = "2010" |
|
Case "12.0" |
|
OfficeVersion = "2007" |
|
Case "11.0" |
|
OfficeVersion = "2003" |
|
Case "10.0" |
|
OfficeVersion = "2002" |
|
Case "9.0" |
|
OfficeVersion = "2000" |
|
Case "8.0" |
|
OfficeVersion = "97" |
|
Case "7.0" |
|
OfficeVersion = "95" |
|
End Select |
|
GetOfficeVersion = OfficeVersion |
|
Exit Function |
|
End If |
|
With CreateObject("VBScript.RegExp") |
|
.Global = True: .IgnoreCase = True |
|
.Pattern = "^.*?(\d{3,4}).*$" ' [TODO] 簡易的に3桁もしくは4桁の数字を取り出しているが、本来はもう少し厳密にパターンを考えるべき |
|
Dim OfficeAppName: OfficeAppName = GetOfficeAppName() |
|
'■OfficeAppName(LICENSE NAME) 例 |
|
' Office 16, Office16O365BusinessR_Grace edition (←Microsoft 365 Business) |
|
' Office 16, Office16O365HomePremR_Grace edition (←Microsoft 365 Personal(旧Sole)) |
|
' Office 19, Office19HomeBusiness2019R_OEM_Perp edition (←Office Home and Business 2019) |
|
' Office 14, OfficeHomeBusiness-Retail3 edition (←Office Home and Business 2010)※本Functionの対象外 |
|
Dim MatchParts As Object: Set MatchParts = .Execute(OfficeAppName) |
|
If 0 < MatchParts.Count Then |
|
OfficeVersion = MatchParts(0).SubMatches(0) |
|
GetOfficeVersion = OfficeVersion |
|
End If |
|
End With |
|
End Function |
|
|
|
Function GetOfficeAppName(Optional ByVal AppVer As Long = 0) As String |
|
'[備忘] |
|
' [ospp.vbs script](https://learn.microsoft.com/en-us/office/volume-license-activation/tools-to-manage-volume-activation-of-office) |
|
' と同等の処理を実施してLICENSE NAMEを取得 |
|
If AppVer = 0 Then AppVer = CLng(Application.Version) |
|
Dim OfficeAppId: OfficeAppId = GetOfficeAppId(AppVer) |
|
If OfficeAppId = "" Then |
|
Exit Function |
|
End If |
|
Dim OSVer |
|
#If TARGET_APP_NAME = "Word" Then |
|
OSVer = System.OperatingSystem & " " & System.Version |
|
#Else |
|
OSVer = Application.OperatingSystem |
|
#End If |
|
Dim Win7 As Boolean: Win7 = OSVer Like "Windows*NT 6.01" |
|
Dim objWMI As Object: Set objWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2") ' [備忘] 対象はローカルマシン固定 |
|
Dim strSelect: strSelect = "ApplicationId, ProductKeyID, Name" |
|
Dim strWhere: strWhere = "ApplicationId = '" & OfficeAppId & "' " |
|
Dim productClass: productClass = IIf(Win7 Or AppVer < 16, "OfficeSoftwareProtectionProduct", "SoftwareLicensingProduct") |
|
Dim productinstances As Object: Set productinstances = objWMI.ExecQuery("SELECT " & strSelect & " FROM " & productClass & IIf(AppVer < 16, "", " WHERE " & strWhere)) |
|
Dim instance As Object |
|
For Each instance In productinstances |
|
If (LCase(instance.ApplicationId) = OfficeAppId) Then |
|
If instance.ProductKeyID <> "" Then |
|
GetOfficeAppName = instance.Name |
|
'[TODO] ProductKeyIdがNull以外のものが複数存在するケースあり (例: https://x.com/KotorinChunChun/status/1493585372009226243) |
|
' → とりあえず最初に見つかったものを優先 |
|
Exit For |
|
End If |
|
End If |
|
Next |
|
End Function |
|
|
|
Function GetOfficeAppId(Optional ByVal AppVer As Long = 0) As String |
|
Const DEFAULT_OFFICE_APP_ID As String = "0ff1ce15-a989-479d-af46-f275c6370663" ' [備忘] 2013以降は共通らしい? |
|
Const adReadLine As Long = -2 |
|
|
|
If AppVer = 0 Then AppVer = CLng(Application.Version) |
|
On Error GoTo SET_DEFAULT |
|
Dim OsppPath: OsppPath = Application.Path & IIf(LCase(Application.Path) Like "*\root\office*", "\..\..\", "\..\") & "Office" & CStr(AppVer) & "\OSPP.VBS" |
|
' OfficeAppIdは |
|
' [ospp.vbs script](https://learn.microsoft.com/en-us/office/volume-license-activation/tools-to-manage-volume-activation-of-office) |
|
' 上に直書きされているため、これを取得 |
|
' [TODO] OSPP.VBSへのPathの求め方がこれでよいか確証がない |
|
With CreateObject("ADODB.Stream") |
|
.Charset = "utf-8" |
|
.Open |
|
.LoadFromFile OsppPath |
|
Dim Reg As Object: Set Reg = CreateObject("VBScript.RegExp") |
|
With Reg |
|
.Global = True: .IgnoreCase = True |
|
.Pattern = "^\s*CONST\s*OfficeAppId\s*=\s*""([^""]+)""" |
|
End With |
|
Dim WorkLine |
|
Dim MatchParts As Object |
|
Do Until .Eos |
|
WorkLine = .ReadText(adReadLine) |
|
Set MatchParts = Reg.Execute(WorkLine) |
|
If 0 < MatchParts.Count Then |
|
GetOfficeAppId = MatchParts(0).SubMatches(0) |
|
End If |
|
Loop |
|
.Close |
|
End With |
|
Exit Function |
|
SET_DEFAULT: |
|
If 14 < AppVer Then |
|
GetOfficeAppId = DEFAULT_OFFICE_APP_ID |
|
End If |
|
End Function |