├── .gitattributes
├── .gitignore
├── LICENSE.txt
├── LKY_OfficeTools.sln
├── LKY_OfficeTools
├── App.config
├── Common
│ ├── Com_ExeOS.cs
│ ├── Com_FileOS.cs
│ ├── Com_InstallerOS.cs
│ ├── Com_NetworkOS.cs
│ ├── Com_PrivilegeOS.cs
│ ├── Com_ServiceOS.cs
│ ├── Com_SystemOS.cs
│ ├── Com_TextOS.cs
│ ├── Com_Timer.cs
│ └── Com_WebOS.cs
├── LKY_OfficeTools.csproj
├── Lib
│ ├── Lib_AppClosing.cs
│ ├── Lib_AppCommand.cs
│ ├── Lib_AppInfo.cs
│ ├── Lib_AppLog.cs
│ ├── Lib_AppMessage.cs
│ ├── Lib_AppSdk.cs
│ ├── Lib_AppServiceConfig.cs
│ ├── Lib_AppServiceHub.Designer.cs
│ ├── Lib_AppServiceHub.cs
│ ├── Lib_AppSignCert.cs
│ ├── Lib_AppState.cs
│ ├── Lib_AppUpdate.cs
│ ├── Lib_Aria2c.cs
│ ├── Lib_OfficeActivate.cs
│ ├── Lib_OfficeClean.cs
│ ├── Lib_OfficeDownload.cs
│ ├── Lib_OfficeInfo.cs
│ ├── Lib_OfficeInstall.cs
│ └── Lib_OfficeProcess.cs
├── OfficeTools.cs
├── Properties
│ ├── AssemblyInfo.cs
│ └── app.manifest
├── Resource
│ ├── Json
│ │ └── OfficeChannels.txt
│ ├── Office_Processes.list
│ ├── PublisherCert.cer
│ └── SDK
│ │ ├── Activate.lotp
│ │ ├── Aria2c.lotp
│ │ ├── ODT.lotp
│ │ ├── SDK_Processes.list
│ │ └── SaRA.lotp
└── logo.ico
└── README.md
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Ww][Ii][Nn]32/
27 | [Aa][Rr][Mm]/
28 | [Aa][Rr][Mm]64/
29 | bld/
30 | [Bb]in/
31 | [Oo]bj/
32 | [Oo]ut/
33 | [Ll]og/
34 | [Ll]ogs/
35 |
36 | # Visual Studio 2015/2017 cache/options directory
37 | .vs/
38 | # Uncomment if you have tasks that create the project's static files in wwwroot
39 | #wwwroot/
40 |
41 | # Visual Studio 2017 auto generated files
42 | Generated\ Files/
43 |
44 | # MSTest test Results
45 | [Tt]est[Rr]esult*/
46 | [Bb]uild[Ll]og.*
47 |
48 | # NUnit
49 | *.VisualState.xml
50 | TestResult.xml
51 | nunit-*.xml
52 |
53 | # Build Results of an ATL Project
54 | [Dd]ebugPS/
55 | [Rr]eleasePS/
56 | dlldata.c
57 |
58 | # Benchmark Results
59 | BenchmarkDotNet.Artifacts/
60 |
61 | # .NET Core
62 | project.lock.json
63 | project.fragment.lock.json
64 | artifacts/
65 |
66 | # ASP.NET Scaffolding
67 | ScaffoldingReadMe.txt
68 |
69 | # StyleCop
70 | StyleCopReport.xml
71 |
72 | # Files built by Visual Studio
73 | *_i.c
74 | *_p.c
75 | *_h.h
76 | *.ilk
77 | *.meta
78 | *.obj
79 | *.iobj
80 | *.pch
81 | *.pdb
82 | *.ipdb
83 | *.pgc
84 | *.pgd
85 | *.rsp
86 | *.sbr
87 | *.tlb
88 | *.tli
89 | *.tlh
90 | *.tmp
91 | *.tmp_proj
92 | *_wpftmp.csproj
93 | *.log
94 | *.vspscc
95 | *.vssscc
96 | .builds
97 | *.pidb
98 | *.svclog
99 | *.scc
100 |
101 | # Chutzpah Test files
102 | _Chutzpah*
103 |
104 | # Visual C++ cache files
105 | ipch/
106 | *.aps
107 | *.ncb
108 | *.opendb
109 | *.opensdf
110 | *.sdf
111 | *.cachefile
112 | *.VC.db
113 | *.VC.VC.opendb
114 |
115 | # Visual Studio profiler
116 | *.psess
117 | *.vsp
118 | *.vspx
119 | *.sap
120 |
121 | # Visual Studio Trace Files
122 | *.e2e
123 |
124 | # TFS 2012 Local Workspace
125 | $tf/
126 |
127 | # Guidance Automation Toolkit
128 | *.gpState
129 |
130 | # ReSharper is a .NET coding add-in
131 | _ReSharper*/
132 | *.[Rr]e[Ss]harper
133 | *.DotSettings.user
134 |
135 | # TeamCity is a build add-in
136 | _TeamCity*
137 |
138 | # DotCover is a Code Coverage Tool
139 | *.dotCover
140 |
141 | # AxoCover is a Code Coverage Tool
142 | .axoCover/*
143 | !.axoCover/settings.json
144 |
145 | # Coverlet is a free, cross platform Code Coverage Tool
146 | coverage*.json
147 | coverage*.xml
148 | coverage*.info
149 |
150 | # Visual Studio code coverage results
151 | *.coverage
152 | *.coveragexml
153 |
154 | # NCrunch
155 | _NCrunch_*
156 | .*crunch*.local.xml
157 | nCrunchTemp_*
158 |
159 | # MightyMoose
160 | *.mm.*
161 | AutoTest.Net/
162 |
163 | # Web workbench (sass)
164 | .sass-cache/
165 |
166 | # Installshield output folder
167 | [Ee]xpress/
168 |
169 | # DocProject is a documentation generator add-in
170 | DocProject/buildhelp/
171 | DocProject/Help/*.HxT
172 | DocProject/Help/*.HxC
173 | DocProject/Help/*.hhc
174 | DocProject/Help/*.hhk
175 | DocProject/Help/*.hhp
176 | DocProject/Help/Html2
177 | DocProject/Help/html
178 |
179 | # Click-Once directory
180 | publish/
181 |
182 | # Publish Web Output
183 | *.[Pp]ublish.xml
184 | *.azurePubxml
185 | # Note: Comment the next line if you want to checkin your web deploy settings,
186 | # but database connection strings (with potential passwords) will be unencrypted
187 | *.pubxml
188 | *.publishproj
189 |
190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
191 | # checkin your Azure Web App publish settings, but sensitive information contained
192 | # in these scripts will be unencrypted
193 | PublishScripts/
194 |
195 | # NuGet Packages
196 | *.nupkg
197 | # NuGet Symbol Packages
198 | *.snupkg
199 | # The packages folder can be ignored because of Package Restore
200 | **/[Pp]ackages/*
201 | # except build/, which is used as an MSBuild target.
202 | !**/[Pp]ackages/build/
203 | # Uncomment if necessary however generally it will be regenerated when needed
204 | #!**/[Pp]ackages/repositories.config
205 | # NuGet v3's project.json files produces more ignorable files
206 | *.nuget.props
207 | *.nuget.targets
208 |
209 | # Microsoft Azure Build Output
210 | csx/
211 | *.build.csdef
212 |
213 | # Microsoft Azure Emulator
214 | ecf/
215 | rcf/
216 |
217 | # Windows Store app package directories and files
218 | AppPackages/
219 | BundleArtifacts/
220 | Package.StoreAssociation.xml
221 | _pkginfo.txt
222 | *.appx
223 | *.appxbundle
224 | *.appxupload
225 |
226 | # Visual Studio cache files
227 | # files ending in .cache can be ignored
228 | *.[Cc]ache
229 | # but keep track of directories ending in .cache
230 | !?*.[Cc]ache/
231 |
232 | # Others
233 | ClientBin/
234 | ~$*
235 | *~
236 | *.dbmdl
237 | *.dbproj.schemaview
238 | *.jfm
239 | *.pfx
240 | *.publishsettings
241 | orleans.codegen.cs
242 |
243 | # Including strong name files can present a security risk
244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
245 | #*.snk
246 |
247 | # Since there are multiple workflows, uncomment next line to ignore bower_components
248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
249 | #bower_components/
250 |
251 | # RIA/Silverlight projects
252 | Generated_Code/
253 |
254 | # Backup & report files from converting an old project file
255 | # to a newer Visual Studio version. Backup files are not needed,
256 | # because we have git ;-)
257 | _UpgradeReport_Files/
258 | Backup*/
259 | UpgradeLog*.XML
260 | UpgradeLog*.htm
261 | ServiceFabricBackup/
262 | *.rptproj.bak
263 |
264 | # SQL Server files
265 | *.mdf
266 | *.ldf
267 | *.ndf
268 |
269 | # Business Intelligence projects
270 | *.rdl.data
271 | *.bim.layout
272 | *.bim_*.settings
273 | *.rptproj.rsuser
274 | *- [Bb]ackup.rdl
275 | *- [Bb]ackup ([0-9]).rdl
276 | *- [Bb]ackup ([0-9][0-9]).rdl
277 |
278 | # Microsoft Fakes
279 | FakesAssemblies/
280 |
281 | # GhostDoc plugin setting file
282 | *.GhostDoc.xml
283 |
284 | # Node.js Tools for Visual Studio
285 | .ntvs_analysis.dat
286 | node_modules/
287 |
288 | # Visual Studio 6 build log
289 | *.plg
290 |
291 | # Visual Studio 6 workspace options file
292 | *.opt
293 |
294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
295 | *.vbw
296 |
297 | # Visual Studio LightSwitch build output
298 | **/*.HTMLClient/GeneratedArtifacts
299 | **/*.DesktopClient/GeneratedArtifacts
300 | **/*.DesktopClient/ModelManifest.xml
301 | **/*.Server/GeneratedArtifacts
302 | **/*.Server/ModelManifest.xml
303 | _Pvt_Extensions
304 |
305 | # Paket dependency manager
306 | .paket/paket.exe
307 | paket-files/
308 |
309 | # FAKE - F# Make
310 | .fake/
311 |
312 | # CodeRush personal settings
313 | .cr/personal
314 |
315 | # Python Tools for Visual Studio (PTVS)
316 | __pycache__/
317 | *.pyc
318 |
319 | # Cake - Uncomment if you are using it
320 | # tools/**
321 | # !tools/packages.config
322 |
323 | # Tabs Studio
324 | *.tss
325 |
326 | # Telerik's JustMock configuration file
327 | *.jmconfig
328 |
329 | # BizTalk build output
330 | *.btp.cs
331 | *.btm.cs
332 | *.odx.cs
333 | *.xsd.cs
334 |
335 | # OpenCover UI analysis results
336 | OpenCover/
337 |
338 | # Azure Stream Analytics local run output
339 | ASALocalRun/
340 |
341 | # MSBuild Binary and Structured Log
342 | *.binlog
343 |
344 | # NVidia Nsight GPU debugger configuration file
345 | *.nvuser
346 |
347 | # MFractors (Xamarin productivity tool) working folder
348 | .mfractor/
349 |
350 | # Local History for Visual Studio
351 | .localhistory/
352 |
353 | # BeatPulse healthcheck temp database
354 | healthchecksdb
355 |
356 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
357 | MigrationBackup/
358 |
359 | # Ionide (cross platform F# VS Code tools) working folder
360 | .ionide/
361 |
362 | # Fody - auto-generated XML schema
363 | FodyWeavers.xsd
364 | /LKY_OfficeTools/Resource/Json/LKY_OfficeTools_AppInfo.json
365 |
--------------------------------------------------------------------------------
/LKY_OfficeTools.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.3.32929.385
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LKY_OfficeTools", "LKY_OfficeTools\LKY_OfficeTools.csproj", "{6D00F508-106A-42D1-BE0F-048762434E69}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {6D00F508-106A-42D1-BE0F-048762434E69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {6D00F508-106A-42D1-BE0F-048762434E69}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {6D00F508-106A-42D1-BE0F-048762434E69}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {6D00F508-106A-42D1-BE0F-048762434E69}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {BECB0D54-D9AD-42F5-9AAE-FD91AF555D72}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/LKY_OfficeTools/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/LKY_OfficeTools/Common/Com_ExeOS.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * [LKY Office Tools] Copyright (C) 2022 - 2024 LiuKaiyuan Inc.
3 | *
4 | * FileName : Com_ExeOS.cs
5 | * Developer: OdysseusYuan@foxmail.com (Odysseus.Yuan)
6 | */
7 |
8 | using System;
9 | using System.Collections.Generic;
10 | using System.Diagnostics;
11 | using static LKY_OfficeTools.Lib.Lib_AppLog;
12 |
13 | namespace LKY_OfficeTools.Common
14 | {
15 | internal class Com_ExeOS
16 | {
17 | internal class Run
18 | {
19 | internal static int Exe(string file_path, string args)
20 | {
21 | try
22 | {
23 | Process p = new Process();
24 | var result = Process(file_path, args, out p, true); //默认等待完成
25 |
26 | //是否执行了
27 | if (!result)
28 | {
29 | throw new Exception($"执行 {file_path} 异常!");
30 | }
31 |
32 | return p.ExitCode;
33 | }
34 | catch (Exception Ex)
35 | {
36 | new Log(Ex.ToString());
37 | return -920921;
38 | }
39 | }
40 |
41 | internal static bool Process(string file_path, string args, out Process ProcessInfo, bool WaitForExit)
42 | {
43 | try
44 | {
45 | Console.ForegroundColor = ConsoleColor.Gray;
46 |
47 | ProcessInfo = new Process();
48 | ProcessInfo.StartInfo.FileName = file_path; //需要启动的程序名
49 | ProcessInfo.StartInfo.Arguments = args; //启动参数
50 |
51 | //是否使用操作系统shell启动
52 | ProcessInfo.StartInfo.UseShellExecute = false;
53 |
54 | //启动
55 | ProcessInfo.Start();
56 |
57 | //接收返回值
58 | //p.StandardInput.AutoFlush = true;
59 |
60 | //获取输出信息
61 | //string strOuput = p.StandardOutput.ReadToEnd();
62 |
63 | //等待程序执行完退出进程
64 | if (WaitForExit)
65 | {
66 | ProcessInfo.WaitForExit();
67 | }
68 |
69 | return true;
70 | }
71 | catch (Exception Ex)
72 | {
73 | ProcessInfo = null;
74 | new Log(Ex.ToString());
75 | return false;
76 | }
77 | }
78 |
79 | internal static string Cmd(string args)
80 | {
81 | try
82 | {
83 | Console.ForegroundColor = ConsoleColor.Gray;
84 |
85 | Process p = new Process();
86 | //设置要启动的应用程序
87 | p.StartInfo.FileName = "cmd.exe";
88 |
89 | //是否使用操作系统shell启动
90 | p.StartInfo.UseShellExecute = false;
91 |
92 | // 接受来自调用程序的输入信息
93 | p.StartInfo.RedirectStandardInput = true;
94 |
95 | //输出信息
96 | p.StartInfo.RedirectStandardOutput = true;
97 |
98 | // 输出错误
99 | p.StartInfo.RedirectStandardError = true;
100 |
101 | //不显示程序窗口
102 | p.StartInfo.CreateNoWindow = true;
103 |
104 | //启动程序
105 | p.Start();
106 |
107 | //向cmd窗口发送输入信息
108 | p.StandardInput.WriteLine(args + "&exit");
109 |
110 | p.StandardInput.AutoFlush = true;
111 |
112 | //获取输出信息
113 | string strOuput = p.StandardOutput.ReadToEnd();
114 |
115 | //等待程序执行完退出进程
116 | p.WaitForExit();
117 | p.Close();
118 |
119 | return strOuput;
120 | }
121 | catch (Exception Ex)
122 | {
123 | new Log(Ex.ToString());
124 | return null;
125 | }
126 | }
127 | }
128 |
129 | internal class KillExe
130 | {
131 | internal enum KillMode
132 | {
133 | Try_Friendly = 1,
134 |
135 | Only_Friendly = 2,
136 |
137 | Only_Force = 4,
138 | }
139 |
140 | internal static bool ByExeName(string exe_name, KillMode kill_mode, bool isWait)
141 | {
142 | try
143 | {
144 | //先判断是否存在进程
145 | if (Info.IsRun(exe_name))
146 | {
147 | Process[] p = Process.GetProcessesByName(exe_name);
148 | foreach (Process now_p in p)
149 | {
150 | ByProcessID(now_p.Id, kill_mode, isWait);
151 | }
152 | return true;
153 | }
154 | else
155 | {
156 | //不存在时,直接返回 true
157 | return true;
158 | }
159 | }
160 | catch (Exception Ex)
161 | {
162 | new Log(Ex.ToString());
163 | return false;
164 | }
165 | }
166 |
167 | internal static bool ByProcessID(int exe_id, KillMode kill_mode, bool isWait)
168 | {
169 | try
170 | {
171 | //先判断是否存在进程
172 | if (Info.IsRun(exe_id))
173 | {
174 | //进程存在,获取对象
175 | Process now_p = Process.GetProcessById(exe_id);
176 |
177 | switch (kill_mode)
178 | {
179 | case KillMode.Try_Friendly:
180 | {
181 | //先尝试友好关闭
182 | if (!now_p.CloseMainWindow())
183 | {
184 | //有好关闭失败时,启用强制结束
185 | now_p.Kill();
186 | }
187 | break;
188 | }
189 | case KillMode.Only_Friendly:
190 | {
191 | //只友好关闭
192 | now_p.CloseMainWindow();
193 | break;
194 | }
195 | case KillMode.Only_Force:
196 | {
197 | //只强制结束
198 | now_p.Kill();
199 | break;
200 | }
201 | }
202 |
203 | //判断是否等待进程结束
204 | if (isWait)
205 | {
206 | //等待进程被结束
207 | now_p.WaitForExit();
208 | }
209 |
210 | return true; //如果不是等待结束进程,中途未出现catch时,也返回true
211 | }
212 | else
213 | {
214 | //不存在时,直接返回 true
215 | return true;
216 | }
217 | }
218 | catch (Exception Ex)
219 | {
220 | new Log(Ex.ToString());
221 | return false;
222 | }
223 | }
224 | }
225 |
226 | internal class Info
227 | {
228 | internal static bool IsRun(string exe_name)
229 | {
230 | try
231 | {
232 | Process[] p = Process.GetProcesses();
233 | foreach (Process now_p in p)
234 | {
235 | if (now_p.ProcessName.Equals(exe_name, StringComparison.OrdinalIgnoreCase))
236 | {
237 | return true;
238 | }
239 | }
240 | return false;
241 | }
242 | catch (Exception Ex)
243 | {
244 | new Log(Ex.ToString());
245 | return false;
246 | }
247 | }
248 |
249 | internal static bool IsRun(int exe_id)
250 | {
251 | try
252 | {
253 | Process[] p = Process.GetProcesses();
254 | foreach (Process now_p in p)
255 | {
256 | if (now_p.Id == exe_id)
257 | {
258 | return true;
259 | }
260 | }
261 | return false;
262 | }
263 | catch (Exception Ex)
264 | {
265 | new Log(Ex.ToString());
266 | return false;
267 | }
268 | }
269 |
270 | internal static List GetProcessByTitle(string window_title, bool need_equal = false)
271 | {
272 | try
273 | {
274 | Process[] process_list = Process.GetProcesses();
275 |
276 | List result = new List();
277 | foreach (var now_p in process_list)
278 | {
279 | if (need_equal)
280 | {
281 | //严格相等
282 | if (now_p.MainWindowTitle == window_title)
283 | {
284 | result.Add(now_p);
285 | }
286 | }
287 | else
288 | {
289 | //包含即可
290 | if (now_p.MainWindowTitle.Contains(window_title))
291 | {
292 | result.Add(now_p);
293 | }
294 | }
295 | }
296 | return result;
297 | }
298 | catch (Exception Ex)
299 | {
300 | new Log(Ex.ToString());
301 | return null;
302 | }
303 | }
304 | }
305 | }
306 | }
307 |
--------------------------------------------------------------------------------
/LKY_OfficeTools/Common/Com_FileOS.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * [LKY Office Tools] Copyright (C) 2022 - 2024 LiuKaiyuan Inc.
3 | *
4 | * FileName : Com_FileOS.cs
5 | * Developer: OdysseusYuan@foxmail.com (Odysseus.Yuan)
6 | */
7 |
8 | using System;
9 | using System.Collections.Generic;
10 | using System.IO;
11 | using System.Security.Cryptography;
12 | using System.Text;
13 | using static LKY_OfficeTools.Lib.Lib_AppLog;
14 |
15 | namespace LKY_OfficeTools.Common
16 | {
17 | internal class Com_FileOS
18 | {
19 | internal class XML
20 | {
21 | internal static bool SetValue(string xml_path, string Key_str, string new_Value)
22 | {
23 | try
24 | {
25 | //读取文件
26 | string xml_content = File.ReadAllText(xml_path, Encoding.UTF8);
27 |
28 | //获得当前值
29 | string current_value = Com_TextOS.GetCenterText(xml_content, $"{Key_str}=\"", "\"");
30 |
31 | //替换值
32 | string xml_new_content = xml_content.Replace(current_value, new_Value);
33 |
34 | //判断是否替换成功
35 | if (string.IsNullOrEmpty(xml_new_content))
36 | {
37 | //new Log("替换失败!");
38 | return false;
39 | }
40 |
41 | //写入文件
42 | File.WriteAllText(xml_path, xml_new_content, Encoding.UTF8);
43 |
44 | return true;
45 | }
46 | catch (Exception Ex)
47 | {
48 | new Log(Ex.ToString());
49 | return false;
50 | }
51 | }
52 | }
53 |
54 | internal class ScanFiles
55 | {
56 | internal List FilesList = new List();
57 |
58 | internal void GetFilesByExtension(string dirPath, string fileType = "*", bool isRoot = false)
59 | {
60 | if (Directory.Exists(dirPath)) //目录存在
61 | {
62 | DirectoryInfo folder = new DirectoryInfo(dirPath);
63 |
64 | //获取当前目录下的文件名
65 | foreach (FileInfo file in folder.GetFiles())
66 | {
67 | //如果没有限制文件后缀名,或者满足了特定后缀名,开始写入List
68 | if (fileType == "*" || file.Extension == (fileType))
69 | {
70 | //扫描到的文件添加到列表中
71 | FilesList.Add(file.FullName);
72 | }
73 | }
74 |
75 | //如果是根目录先排除掉 回收站目录
76 | if (isRoot)
77 | {
78 | foreach (DirectoryInfo dir in folder.GetDirectories())
79 | {
80 | if (dir.FullName.Contains("$RECYCLE.BIN") || dir.FullName.Contains("System Volume Information"))
81 | {
82 | //Console.ForegroundColor = ConsoleColor.Gray;
83 | //new Log("跳过: " + dir.FullName);
84 | }
85 | else
86 | {
87 | //new Log("----->: " + dir.FullName);
88 | GetFilesByExtension(dir.FullName, fileType);
89 | }
90 | }
91 | }
92 | else
93 | {
94 | //遍历下一个子目录
95 | foreach (DirectoryInfo subFolders in folder.GetDirectories())
96 | {
97 | //new Log(subFolders.FullName);
98 | GetFilesByExtension(subFolders.FullName, fileType);
99 | }
100 | }
101 | }
102 | else
103 | {
104 | /*Console.ForegroundColor = ConsoleColor.Gray;
105 | new Log("不存在: " + dirPath);*/
106 | }
107 | }
108 | }
109 |
110 | internal class Covert
111 | {
112 | /* - - - - - - - - - - - - - - - - - - - - - - - -
113 | * Stream 和 byte[] 之间的转换
114 | * - - - - - - - - - - - - - - - - - - - - - - - */
115 | internal static byte[] StreamToBytes(Stream stream)
116 | {
117 | byte[] bytes = new byte[stream.Length];
118 | stream.Read(bytes, 0, bytes.Length);
119 |
120 | // 设置当前流的位置为流的开始
121 | stream.Seek(0, SeekOrigin.Begin);
122 | return bytes;
123 | }
124 | }
125 |
126 | internal class Write
127 | {
128 | internal static bool TextToFile(string file_path, string content, bool is_append = true)
129 | {
130 | try
131 | {
132 | // 创建文件所在目录
133 | Directory.CreateDirectory(new FileInfo(file_path).DirectoryName);
134 |
135 | //非追加模式,并且已经存在目标文件,则先删除原有文件
136 | if (!is_append && File.Exists(file_path))
137 | {
138 | File.Delete(file_path);
139 | }
140 |
141 | var fs = new FileStream(file_path, FileMode.OpenOrCreate, FileAccess.Write);
142 | var sw = new StreamWriter(fs);
143 | sw.BaseStream.Seek(0, SeekOrigin.End);
144 | sw.WriteLine(content);
145 |
146 | sw.Flush();
147 | sw.Close();
148 | fs.Close();
149 |
150 | return true;
151 | }
152 | catch (Exception Ex)
153 | {
154 | new Log(Ex.ToString());
155 | return false;
156 | }
157 | }
158 |
159 | internal static bool FromStream(Stream stream, string to_path)
160 | {
161 | try
162 | {
163 | byte[] Save = Covert.StreamToBytes(stream);
164 |
165 | //创建文件所在目录
166 | Directory.CreateDirectory(new FileInfo(to_path).DirectoryName);
167 |
168 | FileStream fsObj = new FileStream(to_path, FileMode.Create);
169 | fsObj.Write(Save, 0, Save.Length);
170 | fsObj.Close();
171 |
172 | return true;
173 | }
174 | catch (Exception Ex)
175 | {
176 | new Log(Ex.ToString());
177 | return false;
178 | }
179 | }
180 | }
181 |
182 | internal class Info
183 | {
184 | internal static string GetHash(string file_path)
185 | {
186 | try
187 | {
188 | //文件不存在,返回null
189 | if (!File.Exists(file_path))
190 | {
191 | return null;
192 | }
193 |
194 | //为了防止文件被占用,无法校验,这里先拷贝一份副本,校验副本的值
195 | string file_copied = DateTime.Now.ToFileTime().ToString() + ".hash";
196 | File.Copy(file_path, file_copied, true);
197 | if (!File.Exists(file_copied))
198 | {
199 | return null; //副本文件拷贝失败,返回null
200 | }
201 |
202 | //var hash = SHA256.Create();
203 | //var hash = MD5.Create();
204 | var hash = SHA1.Create();
205 | var stream = new FileStream(file_copied, FileMode.Open);
206 | byte[] hashByte = hash.ComputeHash(stream);
207 | stream.Close();
208 |
209 | //校验完成,删除副本
210 | if (File.Exists(file_copied))
211 | {
212 | File.Delete(file_copied);
213 | }
214 |
215 | return BitConverter.ToString(hashByte).Replace("-", "");
216 | }
217 | catch (Exception Ex)
218 | {
219 | new Log(Ex.ToString());
220 | return null;
221 | }
222 | }
223 | }
224 | }
225 | }
226 |
--------------------------------------------------------------------------------
/LKY_OfficeTools/Common/Com_InstallerOS.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * [LKY Office Tools] Copyright (C) 2022 - 2024 LiuKaiyuan Inc.
3 | *
4 | * FileName : Com_InstallerOS.cs
5 | * Developer: OdysseusYuan@foxmail.com (Odysseus.Yuan)
6 | */
7 |
8 | using System;
9 | using WindowsInstaller;
10 | using static LKY_OfficeTools.Lib.Lib_AppLog;
11 |
12 | namespace LKY_OfficeTools.Common
13 | {
14 | internal class Com_InstallerOS
15 | {
16 | internal enum MsiInfoType
17 | {
18 | ProductName,
19 |
20 | ProductCode,
21 |
22 | ProductVersion
23 | }
24 |
25 | internal static string GetProductInfo(string msi_path, MsiInfoType msi_info)
26 | {
27 | try
28 | {
29 | Type oType = Type.GetTypeFromProgID("WindowsInstaller.Installer");
30 | if (oType == null)
31 | {
32 | return null;
33 | }
34 |
35 | Installer inst = Activator.CreateInstance(oType) as Installer;
36 | if (inst == null)
37 | {
38 | return null;
39 | }
40 |
41 | Database DB = inst.OpenDatabase(msi_path, MsiOpenDatabaseMode.msiOpenDatabaseModeReadOnly);
42 | if (DB == null)
43 | {
44 | return null;
45 | }
46 |
47 | //生成要查询的内容
48 | string str = $" SELECT * FROM Property WHERE Property = '{msi_info}' ";
49 |
50 | View thisView = DB.OpenView(str);
51 | if (thisView == null)
52 | {
53 | return null;
54 | }
55 |
56 | thisView.Execute();
57 |
58 | Record thisRecord = thisView.Fetch();
59 | if (thisRecord == null)
60 | {
61 | return null;
62 | }
63 |
64 | string result = thisRecord.get_StringData(2);
65 |
66 | return result;
67 | }
68 | catch (Exception Ex)
69 | {
70 | new Log(Ex.ToString());
71 | return null;
72 | }
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/LKY_OfficeTools/Common/Com_NetworkOS.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * [LKY Office Tools] Copyright (C) 2022 - 2024 LiuKaiyuan Inc.
3 | *
4 | * FileName : Com_NetworkOS.cs
5 | * Developer: OdysseusYuan@foxmail.com (Odysseus.Yuan)
6 | */
7 |
8 | using System;
9 | using System.Collections.Generic;
10 | using System.Runtime.InteropServices;
11 | using System.Text.RegularExpressions;
12 | using static LKY_OfficeTools.Lib.Lib_AppInfo;
13 | using static LKY_OfficeTools.Lib.Lib_AppLog;
14 |
15 | namespace LKY_OfficeTools.Common
16 | {
17 | internal class Com_NetworkOS
18 | {
19 | internal class Check
20 | {
21 | //导入判断网络是否连接的 .dll
22 | [DllImport("wininet.dll", EntryPoint = "InternetGetConnectedState")]
23 | //判断网络状况的方法,返回值true为连接,false为未连接
24 | private extern static bool InternetGetConnectedState(out int conState, int reder);
25 |
26 | internal static bool IsConnected
27 | {
28 | get
29 | {
30 | return InternetGetConnectedState(out int n, 0);
31 | }
32 | }
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/LKY_OfficeTools/Common/Com_PrivilegeOS.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * [LKY Office Tools] Copyright (C) 2022 - 2024 LiuKaiyuan Inc.
3 | *
4 | * FileName : Com_PrivilegeOS.cs
5 | * Developer: OdysseusYuan@foxmail.com (Odysseus.Yuan)
6 | */
7 |
8 | using System;
9 | using System.IO;
10 | using System.Security.Principal;
11 | using static LKY_OfficeTools.Lib.Lib_AppInfo;
12 | using static LKY_OfficeTools.Lib.Lib_AppLog;
13 | using static LKY_OfficeTools.Lib.Lib_AppMessage;
14 | using static LKY_OfficeTools.Lib.Lib_AppState;
15 |
16 | namespace LKY_OfficeTools.Common
17 | {
18 | internal class Com_PrivilegeOS
19 | {
20 | internal static bool IsRunByAdmin()
21 | {
22 | WindowsIdentity identity = WindowsIdentity.GetCurrent();
23 | WindowsPrincipal principal = new WindowsPrincipal(identity);
24 | return principal.IsInRole(WindowsBuiltInRole.Administrator);
25 | }
26 |
27 | internal static bool CanWriteProgramDataDir()
28 | {
29 | try
30 | {
31 | string time_sn = $"{DateTime.UtcNow.Hour}{DateTime.UtcNow.Minute}{DateTime.UtcNow.Second}{DateTime.UtcNow.Millisecond}";
32 | string test_file_dir = AppPath.Documents.Temp + $"\\{time_sn}";
33 | string test_file_path = test_file_dir + "\\time_sn.tmp";
34 | var isSuccess = Com_FileOS.Write.TextToFile(test_file_path, "test", false);
35 |
36 | //删除测试的文件和目录
37 | if (Directory.Exists(test_file_dir))
38 | {
39 | Directory.Delete(test_file_dir, true);
40 | }
41 |
42 | return isSuccess;
43 | }
44 | catch (Exception Ex)
45 | {
46 | new Log(Ex.ToString());
47 | return false;
48 | }
49 | }
50 |
51 | internal static void PrivilegeAttention()
52 | {
53 | new Log($"\n------> 正在进行 {AppAttribute.AppName} 权限检查 ...", ConsoleColor.DarkCyan);
54 |
55 | //提权检验,非提权,激活会出问题
56 | if (!IsRunByAdmin())
57 | {
58 | new Log($" × 权限错误,请以管理员身份运行此文件!", ConsoleColor.DarkRed);
59 |
60 | Current_StageType = ProcessStage.Finish_Fail; //设置为失败模式
61 |
62 | //退出提示
63 | KeyMsg.Quit(-1);
64 | }
65 |
66 | //ProgramData目录权限检查
67 | if (!CanWriteProgramDataDir())
68 | {
69 | //ProgramData目录缺少权限,已改用“我的文档”目录。服务维护流程已伴随关闭!
70 | Must_Use_PersonalDir = true;
71 | new Log($" * 已采用备用权限策略!", ConsoleColor.DarkMagenta);
72 | }
73 |
74 | new Log($" √ 已通过 {AppAttribute.AppName} 权限检查。", ConsoleColor.DarkGreen);
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/LKY_OfficeTools/Common/Com_ServiceOS.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * [LKY Office Tools] Copyright (C) 2022 - 2024 LiuKaiyuan Inc.
3 | *
4 | * FileName : Com_ServiceOS.cs
5 | * Developer: OdysseusYuan@foxmail.com (Odysseus.Yuan)
6 | */
7 |
8 | using System;
9 | using System.ServiceProcess;
10 | using System.Threading;
11 | using static LKY_OfficeTools.Lib.Lib_AppLog;
12 |
13 | namespace LKY_OfficeTools.Common
14 | {
15 | internal class Com_ServiceOS
16 | {
17 | internal class Query
18 | {
19 | internal static int RunState(string serv_name)
20 | {
21 | try
22 | {
23 | using (var control = new ServiceController(serv_name))
24 | {
25 | return (int)control.Status;
26 | }
27 | }
28 | catch (Exception Ex)
29 | {
30 | new Log(Ex.ToString());
31 | return 0;
32 | }
33 | }
34 |
35 | internal static bool IsCreated(string serv_name)
36 | {
37 | try
38 | {
39 | if (GetService(serv_name) != null)
40 | {
41 | //服务不为空,服务存在
42 | return true;
43 | }
44 | else
45 | {
46 | //服务为空,服务不存在
47 | return false;
48 | }
49 | }
50 | catch (Exception Ex)
51 | {
52 | new Log(Ex.ToString());
53 | return false;
54 | }
55 | }
56 |
57 | internal static ServiceController GetService(string serv_name)
58 | {
59 | try
60 | {
61 | ServiceController service_info = null; //即将获得的服务对象
62 | ServiceController[] services_list = ServiceController.GetServices(); //获得所有服务
63 | foreach (var now_service in services_list) //遍历搜索服务
64 | {
65 | if (now_service.ServiceName.ToLower() == serv_name.ToLower()) //全部取小写,防止判断麻烦
66 | {
67 | service_info = now_service;
68 | break;
69 | }
70 | }
71 |
72 | return service_info;
73 | }
74 | catch (Exception Ex)
75 | {
76 | new Log(Ex.ToString());
77 | return null;
78 | }
79 | }
80 |
81 | internal static bool CompareBinPath(string serv_name, string compare_path)
82 | {
83 | try
84 | {
85 | //服务未创建,不相等
86 | if (!IsCreated(serv_name))
87 | {
88 | return false;
89 | }
90 |
91 | string cmd_query = $"sc qc {serv_name}";
92 | string query_result = Com_ExeOS.Run.Cmd(cmd_query);
93 |
94 | //返回值为空,不相等
95 | if (string.IsNullOrEmpty(query_result))
96 | {
97 | return false;
98 | }
99 |
100 | if (query_result.Replace(@"\\", @"\").Contains(compare_path.Replace(@"\\", @"\"))) //替换两个斜杠,为单斜杠之后在比对
101 | {
102 | //包含指定路径(含命令行)
103 | return true;
104 | }
105 | else
106 | {
107 | //不包含指定路径(含命令行)
108 | return false;
109 | }
110 | }
111 | catch (Exception Ex)
112 | {
113 | new Log(Ex.ToString());
114 | return false;
115 | }
116 | }
117 |
118 | internal static bool CompareDescription(string serv_name, string compare_description)
119 | {
120 | try
121 | {
122 | //服务未创建,不相等
123 | if (!IsCreated(serv_name))
124 | {
125 | return false;
126 | }
127 |
128 | string cmd_query = $"sc qdescription {serv_name}";
129 | string query_result = Com_ExeOS.Run.Cmd(cmd_query);
130 |
131 | //返回值为空,不相等
132 | if (string.IsNullOrEmpty(query_result))
133 | {
134 | return false;
135 | }
136 |
137 | if (query_result.Contains(compare_description))
138 | {
139 | //包含描述
140 | return true;
141 | }
142 | else
143 | {
144 | //不包含描述
145 | return false;
146 | }
147 | }
148 | catch (Exception Ex)
149 | {
150 | new Log(Ex.ToString());
151 | return false;
152 | }
153 | }
154 | }
155 |
156 | internal class Action
157 | {
158 | internal static bool Start(string serv_name)
159 | {
160 | try
161 | {
162 | //未创建服务,不启动!
163 | if (!Query.IsCreated(serv_name))
164 | {
165 | throw new Exception($"启动服务 {serv_name} 时失败。未找到该服务!");
166 | }
167 |
168 | //已安装服务,开始启动
169 | using (var control = new ServiceController(serv_name))
170 | {
171 | //没有处于运行状态的服务,才运行。
172 | if (control.Status != ServiceControllerStatus.Running)
173 | {
174 | control.Start();
175 | }
176 |
177 | //判断状态,是否是开启了
178 | int wait_time = 0; //等待时间总计
179 | while (wait_time <= (10 * 1000)) //最多等待10秒
180 | {
181 | //获取服务状态
182 | if (Query.RunState(serv_name) == (int)ServiceControllerStatus.Running)
183 | {
184 | //已经处于运行状态
185 | return true;
186 | }
187 | else
188 | {
189 | //不是运行状态
190 | Thread.Sleep(1000); //延迟 1s 后,再度查询
191 | wait_time += 1000; //追加等待时间
192 | continue;
193 | }
194 | }
195 |
196 | //如果在轮询期间,没有返回true,那么最终返回false
197 | return false;
198 | }
199 | }
200 | catch (Exception Ex)
201 | {
202 | new Log(Ex.ToString());
203 | return false;
204 | }
205 | }
206 |
207 | internal static bool Stop(string serv_name)
208 | {
209 | try
210 | {
211 | //未创建服务,不能停止!
212 | if (!Query.IsCreated(serv_name))
213 | {
214 | throw new Exception($"停止服务 {serv_name} 时失败。未找到该服务!");
215 | }
216 |
217 | //已安装服务,开始停止
218 | using (var control = new ServiceController(serv_name))
219 | {
220 | //只要不是停止状态,就发送停止指令
221 | if (control.Status != ServiceControllerStatus.Stopped)
222 | {
223 | control.Stop();
224 | }
225 |
226 | //判断状态,是否是停止了
227 | int wait_time = 0; //等待时间总计
228 | while (wait_time <= (10 * 1000)) //最多等待10秒
229 | {
230 | //获取服务状态
231 | if (Query.RunState(serv_name) == (int)ServiceControllerStatus.Stopped)
232 | {
233 | //已经处于停止状态
234 | return true;
235 | }
236 | else
237 | {
238 | //不是停止状态
239 | Thread.Sleep(1000); //延迟 1s 后,再度查询
240 | wait_time += 1000; //追加等待时间
241 | continue;
242 | }
243 | }
244 |
245 | //如果在轮询期间,没有返回true,那么最终返回false
246 | return false;
247 | }
248 | }
249 | catch (Exception Ex)
250 | {
251 | new Log(Ex.ToString());
252 | return false;
253 | }
254 | }
255 |
256 | internal static bool Restart(string serv_name)
257 | {
258 | try
259 | {
260 | //未创建服务,不能停止!
261 | if (!Query.IsCreated(serv_name))
262 | {
263 | throw new Exception($"重启服务 {serv_name} 时失败。未找到该服务!");
264 | }
265 |
266 | //已安装服务,开始重启
267 | if (Stop(serv_name))
268 | {
269 | if (Start(serv_name))
270 | {
271 | return true; //当且仅当停止成功,开启成功,返回true。除此之外,均为false
272 | }
273 | }
274 |
275 | return false;
276 | }
277 | catch (Exception Ex)
278 | {
279 | new Log(Ex.ToString());
280 | return false;
281 | }
282 | }
283 | }
284 |
285 | internal class Config
286 | {
287 | internal static bool Create(string serv_name, string serv_runpath, string serv_displayname, string serv_description = null)
288 | {
289 | try
290 | {
291 | if (Query.IsCreated(serv_name))
292 | {
293 | //已经创建服务,直接返回真
294 | return true;
295 | }
296 | else
297 | {
298 | //未安装,开始安装
299 | string cmd_install = $"sc create \"{serv_name}\" binPath=\"{serv_runpath}\" start=auto DisplayName=\"{serv_displayname}\"";
300 | var install_result = Com_ExeOS.Run.Cmd(cmd_install);
301 |
302 | //非空判断,若返回值为空,则为假
303 | if (string.IsNullOrEmpty(install_result))
304 | {
305 | throw new Exception($"创建服务 {serv_name} 时,返回值为空!");
306 | }
307 |
308 | //判断是否安装成功
309 | if (install_result.Contains("成功") || install_result.ToLower().Contains("success"))
310 | {
311 | //描述信息不为空,配置描述信息
312 | if (!string.IsNullOrEmpty(serv_description))
313 | {
314 | Modify.Description(serv_name, serv_description);
315 | }
316 |
317 | //无论修改描述信息是否成功,均返回成功
318 | return true;
319 | }
320 | else
321 | {
322 | return false;
323 | }
324 | }
325 | }
326 | catch (Exception Ex)
327 | {
328 | new Log(Ex.ToString());
329 | return false;
330 | }
331 | }
332 |
333 | internal static bool Delete(string serv_name)
334 | {
335 | if (Query.IsCreated(serv_name))
336 | {
337 | //已经创建服务,才能删除
338 |
339 | //先停止服务
340 | if (!Action.Stop(serv_name))
341 | {
342 | throw new Exception($"服务 {serv_name} 因无法停止,导致卸载失败!");
343 | }
344 |
345 | string cmd_del = $"sc delete \"{serv_name}\"";
346 | var del_result = Com_ExeOS.Run.Cmd(cmd_del);
347 |
348 | //非空判断,若返回值为空,则为假
349 | if (string.IsNullOrEmpty(del_result))
350 | {
351 | throw new Exception($"删除服务 {serv_name} 时,返回值为空!");
352 | }
353 |
354 | //判断是否删除成功
355 | if (del_result.Contains("成功") || del_result.ToLower().Contains("success"))
356 | {
357 | return true;
358 | }
359 | else
360 | {
361 | throw new Exception($"删除服务 {serv_name} 失败!");
362 | }
363 | }
364 | else
365 | {
366 | throw new Exception($"没有找到名称为 {serv_name} 的服务,无法删除该服务!");
367 | }
368 | }
369 |
370 | internal class Modify
371 | {
372 | internal static bool BinPath(string serv_name, string serv_binpath)
373 | {
374 | try
375 | {
376 | if (Query.IsCreated(serv_name))
377 | {
378 | //已经创建服务,才进行修改
379 | string cmd_modify_binpath = $"sc config \"{serv_name}\" binPath=\"{serv_binpath}\"";
380 | var modify_result = Com_ExeOS.Run.Cmd(cmd_modify_binpath);
381 |
382 | //非空判断,若返回值为空,则为假
383 | if (string.IsNullOrEmpty(modify_result))
384 | {
385 | throw new Exception($"执行修改 {serv_name} binPath 参数时,返回值为空!");
386 | }
387 |
388 | //判断是否修改 binPath 成功
389 | if (modify_result.Contains("成功") || modify_result.ToLower().Contains("success"))
390 | {
391 | return true;
392 | }
393 | else
394 | {
395 | throw new Exception($"修改服务 {serv_name} 的 binPath 信息为 {serv_binpath} 失败!");
396 | }
397 | }
398 | else
399 | {
400 | throw new Exception($"尝试修改服务 {serv_name} 的 binPath 信息为 {serv_binpath},但该服务未安装!");
401 | }
402 | }
403 | catch (Exception Ex)
404 | {
405 | new Log(Ex.ToString());
406 | return false;
407 | }
408 | }
409 |
410 | internal static bool DisplayName(string serv_name, string serv_displayname)
411 | {
412 | try
413 | {
414 | if (Query.IsCreated(serv_name))
415 | {
416 | //已经创建服务,才进行修改
417 | string cmd_modify_displayname = $"sc config \"{serv_name}\" DisplayName=\"{serv_displayname}\"";
418 | var modify_result = Com_ExeOS.Run.Cmd(cmd_modify_displayname);
419 |
420 | //非空判断,若返回值为空,则为假
421 | if (string.IsNullOrEmpty(modify_result))
422 | {
423 | throw new Exception($"执行修改 {serv_name} DisplayName 参数时,返回值为空!");
424 | }
425 |
426 | //判断是否修改 DisplayName 成功
427 | if (modify_result.Contains("成功") || modify_result.ToLower().Contains("success"))
428 | {
429 | return true;
430 | }
431 | else
432 | {
433 | throw new Exception($"修改服务 {serv_name} 的 DisplayName 信息为 {serv_displayname} 失败!");
434 | }
435 | }
436 | else
437 | {
438 | throw new Exception($"尝试修改服务 {serv_name} 的 DisplayName 信息为 {serv_displayname},但该服务未安装!");
439 | }
440 | }
441 | catch (Exception Ex)
442 | {
443 | new Log(Ex.ToString());
444 | return false;
445 | }
446 | }
447 |
448 | internal static bool Description(string serv_name, string serv_description)
449 | {
450 | try
451 | {
452 | if (Query.IsCreated(serv_name))
453 | {
454 | //已经创建服务,才进行修改
455 | string cmd_modify_desc = $"sc description \"{serv_name}\" \"{serv_description}\"";
456 | var modify_result = Com_ExeOS.Run.Cmd(cmd_modify_desc);
457 |
458 | //非空判断,若返回值为空,则为假
459 | if (string.IsNullOrEmpty(modify_result))
460 | {
461 | throw new Exception($"执行修改 {serv_name} 描述信息时,返回值为空!");
462 | }
463 |
464 | //判断是否修改描述成功
465 | if (modify_result.Contains("成功") || modify_result.ToLower().Contains("success"))
466 | {
467 | return true;
468 | }
469 | else
470 | {
471 | throw new Exception($"修改服务 {serv_name} 的描述信息为 {serv_description} 失败!");
472 | }
473 | }
474 | else
475 | {
476 | throw new Exception($"尝试修改服务 {serv_name} 的描述信息为 {serv_description},但该服务未安装!");
477 | }
478 | }
479 | catch (Exception Ex)
480 | {
481 | new Log(Ex.ToString());
482 | return false;
483 | }
484 | }
485 | }
486 | }
487 | }
488 | }
489 |
--------------------------------------------------------------------------------
/LKY_OfficeTools/Common/Com_SystemOS.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * [LKY Office Tools] Copyright (C) 2022 - 2024 LiuKaiyuan Inc.
3 | *
4 | * FileName : Com_SystemOS.cs
5 | * Developer: OdysseusYuan@foxmail.com (Odysseus.Yuan)
6 | */
7 |
8 | using Microsoft.Win32;
9 | using System;
10 | using System.Collections.Generic;
11 | using System.Diagnostics;
12 | using System.IO;
13 | using static LKY_OfficeTools.Lib.Lib_AppLog;
14 |
15 | namespace LKY_OfficeTools.Common
16 | {
17 | internal class Com_SystemOS
18 | {
19 | internal class OSVersion
20 | {
21 | internal enum OSType
22 | {
23 | LowVersion,
24 | WinXP,
25 | WinVista,
26 | Win7, //支持.NET 4.8
27 | Win8_1, //支持.NET 4.8
28 | Win10, //1607开始,支持.NET 4.8
29 | Win11,
30 | UnKnow
31 | }
32 |
33 | internal static readonly IDictionary WinPublishType = new Dictionary
34 | {
35 | //win10版本号
36 | { "10240", "1507" },
37 | { "10586", "1511" },
38 | { "14393", "1607" }, //.NET 4.8从此版本开始支持
39 | { "15063", "1703" },
40 | { "16299", "1709" },
41 | { "17134", "1803" },
42 | { "17763", "1809" },
43 | { "18362", "1903" },
44 | { "18363", "1909" },
45 | { "19041", "2004" },
46 | { "19042", "20H2" },
47 | { "19043", "21H1" },
48 | { "19044", "21H2" },
49 | { "19045", "22H2" },
50 |
51 | //win11版本号
52 | { "22000", "21H2" },
53 | { "22621", "22H2" },
54 |
55 | //{ "1111111111111111", "LTSB" },
56 | //{ "1111111111111111", "LTSC" },
57 | //{ "1111111111111111", "ARM" },
58 | };
59 |
60 | internal static OSType GetPublishType()
61 | {
62 | try
63 | {
64 | Version ver = Environment.OSVersion.Version;
65 |
66 | if (ver.Major < 5)
67 | {
68 | return OSType.LowVersion;
69 | }
70 | else if (ver.Major == 5 && ver.Minor == 1)
71 | {
72 | return OSType.WinXP;
73 | }
74 | else if (ver.Major == 6 && ver.Minor == 0)
75 | {
76 | return OSType.WinVista;
77 | }
78 | else if (ver.Major == 6 && ver.Minor == 1)
79 | {
80 | return OSType.Win7;
81 | }
82 | else if (ver.Major == 6 && ver.Minor == 2)
83 | {
84 | return OSType.Win8_1;
85 | }
86 | else if (ver.Major == 10 && ver.Minor == 0) //正确获取win10版本号,需要在exe里面加入app.manifest
87 | {
88 | //检查注册表,因为win10和11的主版本号都为10,只能用buildID来判断了
89 | string curr_ver = Register.Read.ValueBySystem(RegistryHive.LocalMachine, @"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "CurrentBuild");
90 |
91 | if (!string.IsNullOrEmpty(curr_ver) && int.Parse(curr_ver) < 22000) //Win11目前内部版本号
92 | {
93 | return OSType.Win10;
94 | }
95 | else
96 | {
97 | return OSType.Win11;
98 | }
99 | }
100 | else
101 | {
102 | return OSType.UnKnow;
103 | }
104 | }
105 | catch (Exception Ex)
106 | {
107 | new Log(Ex.ToString());
108 | return OSType.UnKnow;
109 | }
110 | }
111 |
112 | internal static string GetBuildNumber(bool isCoreVersion = true)
113 | {
114 | try
115 | {
116 | //检查注册表
117 | string curr_mode = Register.Read.ValueBySystem(RegistryHive.LocalMachine, @"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "CurrentBuild");
118 |
119 | //为空返回未知
120 | if (string.IsNullOrEmpty(curr_mode))
121 | {
122 | return "unknow";
123 | }
124 |
125 | //判断返回的内容
126 | if (isCoreVersion) //返回内部版本号
127 | {
128 | return curr_mode;
129 | }
130 | else //返回发行版本
131 | {
132 | return WinPublishType[curr_mode];
133 | }
134 | }
135 | catch (Exception Ex)
136 | {
137 | new Log(Ex.ToString());
138 | return "error!";
139 | }
140 | }
141 | }
142 |
143 | internal class Register
144 | {
145 | internal class Read
146 | {
147 | internal static string Value(RegistryHive reg_root, RegistryView reg_view, string path, string key)
148 | {
149 | try
150 | {
151 | RegistryKey HK_Root = RegistryKey.OpenBaseKey(reg_root, reg_view);
152 |
153 | RegistryKey path_reg = HK_Root.OpenSubKey(path); //先获取路径
154 |
155 | if (path_reg == null)
156 | {
157 | //找不到注册表路径
158 | return null;
159 | }
160 | else
161 | {
162 | object value = path_reg.GetValue(key);
163 | if (value != null) //必须先判断不为null,否则会抛出异常
164 | {
165 | //一切正常
166 | return value.ToString();
167 | }
168 | else
169 | {
170 | //Key不存在或值为空
171 | return null;
172 | }
173 | }
174 | }
175 | catch (Exception Ex)
176 | {
177 | new Log(Ex.ToString());
178 | return null;
179 | }
180 | }
181 |
182 | internal static string ValueBySystem(RegistryHive reg_root, string path, string key)
183 | {
184 | try
185 | {
186 | if (Environment.Is64BitOperatingSystem)
187 | {
188 | //x64系统,访问x64注册表
189 | return Value(reg_root, RegistryView.Registry64, path, key);
190 | }
191 | else
192 | {
193 | //x32系统,访问x32注册表
194 | return Value(reg_root, RegistryView.Registry32, path, key);
195 | }
196 | }
197 | catch (Exception Ex)
198 | {
199 | new Log(Ex.ToString());
200 | return null;
201 | }
202 | }
203 |
204 | internal static List AllValues(RegistryHive reg_root, string path, string key)
205 | {
206 | try
207 | {
208 | List result = new List();
209 |
210 | //获取x32的结构值
211 | string value_x32 = Value(reg_root, RegistryView.Registry32, path, key);
212 | if (!string.IsNullOrWhiteSpace(value_x32))
213 | {
214 | result.Add(value_x32);
215 | }
216 |
217 | //获取x64的结构值(仅在当前计算机为 x64 系统时,才获取)
218 | if (Environment.Is64BitOperatingSystem)
219 | {
220 | string value_x64 = Value(reg_root, RegistryView.Registry64, path, key);
221 | if (!string.IsNullOrWhiteSpace(value_x64))
222 | {
223 | result.Add(value_x64);
224 | }
225 | }
226 |
227 | return result;
228 | }
229 | catch (Exception Ex)
230 | {
231 | new Log(Ex.ToString());
232 | return null;
233 | }
234 | }
235 | }
236 |
237 | internal static bool ExistItem(RegistryHive reg_root, RegistryView reg_view, string item_path)
238 | {
239 | try
240 | {
241 | RegistryKey reg = RegistryKey.OpenBaseKey(reg_root, reg_view);
242 | var result = reg.OpenSubKey(item_path);
243 |
244 | if (result != null)
245 | {
246 | return true;
247 | }
248 |
249 | result.Close();
250 |
251 | return false;
252 | }
253 | catch (Exception Ex)
254 | {
255 | new Log(Ex.ToString());
256 | return false;
257 | }
258 | }
259 |
260 | internal static bool DeleteItem(RegistryHive reg_root, RegistryView reg_view, string path, string item)
261 | {
262 | try
263 | {
264 | RegistryKey HK_Root = RegistryKey.OpenBaseKey(reg_root, reg_view);
265 | RegistryKey path_reg = HK_Root.OpenSubKey(path, true); //先获取路径,启动可写模式
266 |
267 | //找不到注册表路径,默认已删除,返回true
268 | if (path_reg == null)
269 | {
270 | return true;
271 | }
272 |
273 | path_reg.DeleteSubKeyTree(item, false);
274 |
275 | return true;
276 | }
277 | catch (Exception Ex)
278 | {
279 | new Log(Ex.ToString());
280 | return false;
281 | }
282 | }
283 |
284 | internal static bool ExportReg(string reg_path, string save_to)
285 | {
286 | try
287 | {
288 | //先删除已经存在的文件
289 | if (File.Exists(save_to))
290 | {
291 | File.Delete(save_to);
292 | }
293 |
294 | //开始导出
295 | Directory.CreateDirectory(new FileInfo(save_to).DirectoryName); //先创建文件所在目录
296 | Process.Start("regedit", $" /E \"{save_to}\" \"{reg_path}\"").WaitForExit();
297 |
298 | if (File.Exists(save_to))
299 | {
300 | return true;
301 | }
302 | else
303 | {
304 | return false;
305 | }
306 | }
307 | catch (Exception Ex)
308 | {
309 | new Log(Ex.ToString());
310 | return false;
311 | }
312 | }
313 | }
314 | }
315 | }
--------------------------------------------------------------------------------
/LKY_OfficeTools/Common/Com_TextOS.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * [LKY Office Tools] Copyright (C) 2022 - 2024 LiuKaiyuan Inc.
3 | *
4 | * FileName : Com_TextOS.cs
5 | * Developer: OdysseusYuan@foxmail.com (Odysseus.Yuan)
6 | */
7 |
8 | using System;
9 | using static LKY_OfficeTools.Lib.Lib_AppLog;
10 |
11 | namespace LKY_OfficeTools.Common
12 | {
13 | internal class Com_TextOS
14 | {
15 | internal static string GetCenterText(string str, string strLeft, string strRight)
16 | {
17 | try
18 | {
19 | if (str == null || str.Length == 0) return "";
20 | if (strLeft != "")
21 | {
22 | int indexLeft = str.IndexOf(strLeft);//左边字符串位置
23 | if (indexLeft < 0) return "";
24 | indexLeft = indexLeft + strLeft.Length;//左边字符串长度
25 | if (strRight != "")
26 | {
27 | int indexRight = str.IndexOf(strRight, indexLeft);//右边字符串位置
28 | if (indexRight < 0) return "";
29 | return str.Substring(indexLeft, indexRight - indexLeft);//indexRight - indexLeft是取中间字符串长度
30 | }
31 | else return str.Substring(indexLeft, str.Length - indexLeft);//取字符串右边
32 | }
33 | else
34 | {
35 | //取字符串左边
36 | int indexRight = str.IndexOf(strRight);
37 | if (indexRight <= 0) return "";
38 | else return str.Substring(0, indexRight);
39 | }
40 | }
41 | catch (Exception Ex)
42 | {
43 | new Log(Ex.ToString());
44 | return null;
45 | }
46 | }
47 |
48 | internal static int GetStringTimes(string str, string scan_str)
49 | {
50 | try
51 | {
52 | int index = 0;
53 | int count = 0;
54 | while ((index = str.IndexOf(scan_str, index)) != -1)
55 | {
56 | count++;
57 | index += scan_str.Length;
58 | }
59 | return count;
60 | }
61 | catch (Exception Ex)
62 | {
63 | new Log(Ex.ToString());
64 | return 0;
65 | }
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/LKY_OfficeTools/Common/Com_Timer.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * [LKY Office Tools] Copyright (C) 2022 - 2024 LiuKaiyuan Inc.
3 | *
4 | * FileName : Com_Timer.cs
5 | * Developer: OdysseusYuan@foxmail.com (Odysseus.Yuan)
6 | */
7 |
8 | using System;
9 | using System.Threading;
10 | using static LKY_OfficeTools.Lib.Lib_AppLog;
11 |
12 | namespace LKY_OfficeTools.Common
13 | {
14 | internal class Com_Timer
15 | {
16 | internal class Countdown_Timer
17 | {
18 | internal int Remaining_Time
19 | { get; set; }
20 |
21 | internal bool isRun
22 | { get; set; }
23 |
24 | internal void Start(int total_time)
25 | {
26 | try
27 | {
28 | //此处不放入线程,否则使用isRun判断是否在运行时,会导致isRun状态无法判断
29 | Remaining_Time = total_time;
30 | isRun = true;
31 |
32 | Thread time_t = new Thread(() =>
33 | {
34 | Update();
35 |
36 | //迭代完成后,自动停止运行
37 | isRun = false;
38 | });
39 |
40 | //time_t.SetApartmentState(ApartmentState.STA);
41 | time_t.Start();
42 | }
43 | catch (Exception Ex)
44 | {
45 | new Log(Ex.ToString());
46 | return;
47 | }
48 | }
49 |
50 | void Update()
51 | {
52 | try
53 | {
54 | //倒计时不为0,且给出运行指令
55 | if (Remaining_Time > 0 & isRun)
56 | {
57 | Thread.Sleep(1000);
58 | Remaining_Time--;
59 | Update(); //轮询继续
60 | }
61 | }
62 | catch (Exception Ex)
63 | {
64 | new Log(Ex.ToString());
65 | return;
66 | }
67 | }
68 |
69 | internal void Pause()
70 | {
71 | try
72 | {
73 | isRun = false;
74 | }
75 | catch (Exception Ex)
76 | {
77 | new Log(Ex.ToString());
78 | return;
79 | }
80 | }
81 |
82 | internal void Continue()
83 | {
84 | try
85 | {
86 | if (Remaining_Time != 0)
87 | {
88 | isRun = true;
89 | }
90 | }
91 | catch (Exception Ex)
92 | {
93 | new Log(Ex.ToString());
94 | return;
95 | }
96 | }
97 |
98 | internal void Stop()
99 | {
100 | try
101 | {
102 | Pause();
103 | Remaining_Time = 0;
104 | }
105 | catch (Exception Ex)
106 | {
107 | new Log(Ex.ToString());
108 | return;
109 | }
110 | }
111 | }
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/LKY_OfficeTools/Common/Com_WebOS.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * [LKY Office Tools] Copyright (C) 2022 - 2024 LiuKaiyuan Inc.
3 | *
4 | * FileName : Com_WebOS.cs
5 | * Developer: OdysseusYuan@foxmail.com (Odysseus.Yuan)
6 | */
7 |
8 | using System;
9 | using System.Net;
10 | using System.Text;
11 | using static LKY_OfficeTools.Lib.Lib_AppLog;
12 |
13 | namespace LKY_OfficeTools.Common
14 | {
15 | internal class Com_WebOS
16 | {
17 | internal static string Visit_WebClient(string url, Encoding encoding = null)
18 | {
19 | try
20 | {
21 | if (encoding == null)
22 | {
23 | encoding = Encoding.UTF8;
24 | }
25 |
26 | using (WebClient WC = new WebClient())
27 | {
28 | WC.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36");
29 | WC.Credentials = CredentialCache.DefaultCredentials;//获取或设置用于向Internet资源的请求进行身份验证的网络凭据
30 | Byte[] pageData = WC.DownloadData(url); //从指定网站下载数据
31 | return encoding.GetString(pageData);
32 | }
33 | }
34 | catch (Exception Ex)
35 | {
36 | new Log(Ex.ToString());
37 | return null;
38 | }
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/LKY_OfficeTools/LKY_OfficeTools.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {6D00F508-106A-42D1-BE0F-048762434E69}
8 | Exe
9 | LKY_OfficeTools
10 | LKY_OfficeTools
11 | v4.7.2
12 | 512
13 | true
14 | true
15 |
16 |
17 |
18 | AnyCPU
19 | true
20 | full
21 | false
22 | bin\Debug\
23 | DEBUG;TRACE
24 | prompt
25 | 4
26 | false
27 |
28 |
29 | AnyCPU
30 | pdbonly
31 | true
32 | bin\Release\
33 | TRACE
34 | prompt
35 | 4
36 | false
37 |
38 |
39 | x86
40 | bin\x86\Debug\
41 |
42 |
43 | x86
44 | bin\x86\Release\
45 |
46 |
47 | logo.ico
48 |
49 |
50 | Custom
51 |
52 |
53 | false
54 |
55 |
56 | Properties\app.manifest
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 | Component
96 |
97 |
98 | Lib_AppServiceHub.cs
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 | {000C1092-0000-0000-C000-000000000046}
133 | 1
134 | 0
135 | 1033
136 | tlbimp
137 | False
138 | True
139 |
140 |
141 |
142 |
--------------------------------------------------------------------------------
/LKY_OfficeTools/Lib/Lib_AppClosing.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * [LKY Office Tools] Copyright (C) 2022 - 2024 LiuKaiyuan Inc.
3 | *
4 | * FileName : Lib_AppClosing.cs
5 | * Developer: OdysseusYuan@foxmail.com (Odysseus.Yuan)
6 | */
7 |
8 | using System;
9 | using System.Runtime.InteropServices;
10 | using static LKY_OfficeTools.Common.Com_ExeOS.KillExe;
11 | using static LKY_OfficeTools.Lib.Lib_AppLog;
12 | using static LKY_OfficeTools.Lib.Lib_AppState;
13 |
14 | namespace LKY_OfficeTools.Lib
15 | {
16 | internal class Lib_AppClosing
17 | {
18 | internal class CloseWindow
19 | {
20 | internal delegate bool ControlCtrlDelegate(int CtrlType);
21 |
22 | [DllImport("kernel32.dll")]
23 | internal static extern bool SetConsoleCtrlHandler(ControlCtrlDelegate HandlerRoutine, bool Add);
24 |
25 | internal static ControlCtrlDelegate newDelegate = new ControlCtrlDelegate(HandlerRoutine);
26 |
27 | internal static bool HandlerRoutine(int CtrlType)
28 | {
29 | //只要程序不是已完成(无论成功与否),手动关闭,就会显示文字并打点
30 | if (Current_StageType != ProcessStage.Finish_Fail && Current_StageType != ProcessStage.Finish_Success)
31 | {
32 | new Log($"\n × 正在尝试 取消部署,请稍候 ...", ConsoleColor.DarkRed);
33 |
34 | Current_StageType = ProcessStage.Interrupt; //设置中断状态。非完成情况下,关闭,属于 中断部署 状态,此处用于停止 下载 office 进程
35 | Console.ForegroundColor = ConsoleColor.Gray; //重置颜色,如果第一次失败,颜色还是可以正常的
36 |
37 | //结束残存进程
38 | Lib_AppSdk.KillAllSdkProcess(KillMode.Try_Friendly);
39 |
40 | /*Pointing(ProcessStage.Interrupt); 暂停中断打点 */ //中断 点位。下载时触发该逻辑,打点会失败。
41 | }
42 | else
43 | {
44 | //完成状态时,清理文件夹
45 | Lib_AppSdk.Clean(); //清理SDK目录
46 | }
47 |
48 | return false;
49 | }
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/LKY_OfficeTools/Lib/Lib_AppCommand.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * [LKY Office Tools] Copyright (C) 2022 - 2024 LiuKaiyuan Inc.
3 | *
4 | * FileName : Lib_AppCommand.cs
5 | * Developer: OdysseusYuan@foxmail.com (Odysseus.Yuan)
6 | */
7 |
8 | using System;
9 | using static LKY_OfficeTools.Lib.Lib_AppLog;
10 | using static LKY_OfficeTools.Lib.Lib_AppState;
11 |
12 | namespace LKY_OfficeTools.Lib
13 | {
14 | internal class Lib_AppCommand
15 | {
16 | internal static ArgsFlag AppCommandFlag { get; set; }
17 |
18 | internal Lib_AppCommand(string[] args)
19 | {
20 | try
21 | {
22 | //非空判断
23 | if (args != null && args.Length > 0)
24 | {
25 | foreach (var now_arg in args)
26 | {
27 | //单独arg非空判断
28 | if (!string.IsNullOrWhiteSpace(now_arg))
29 | {
30 | //对于 /passive 模式,自动跳过所有需要确认的步骤
31 | if (now_arg.Contains("/passive"))
32 | {
33 | SkipAllConfirm();
34 | Current_RunMode = RunMode.Passive; //设置为被动模式
35 | break;
36 | }
37 | //服务模式。该模式 与 passive 是互斥的。
38 | else if (now_arg.Contains("/service"))
39 | {
40 | Current_RunMode = RunMode.Service; //设置为服务模式
41 |
42 | //以服务模式运行
43 | Lib_AppServiceConfig.Start(); //在Hub类库设置中,service模式将被添加passive标记。
44 |
45 | //找到服务模式,不再执行后续的
46 | Environment.Exit(-100);
47 | }
48 | //非服务、非被动模式
49 | else
50 | {
51 | Current_RunMode = RunMode.Manual; //设置为手动模式
52 |
53 | if (now_arg.ToLower().Contains("/none_welcome_confirm"))
54 | {
55 | AppCommandFlag |= ArgsFlag.None_Welcome_Confirm;
56 | }
57 |
58 | if (now_arg.ToLower().Contains("/ignore_manual_update_msg"))
59 | {
60 | AppCommandFlag |= ArgsFlag.Ignore_Manual_Update_Msg;
61 | }
62 |
63 | if (now_arg.ToLower().Contains("/auto_remove_conflict_office"))
64 | {
65 | AppCommandFlag |= ArgsFlag.Auto_Remove_Conflict_Office;
66 | }
67 |
68 | if (now_arg.ToLower().Contains("/none_finish_presskey"))
69 | {
70 | AppCommandFlag |= ArgsFlag.None_Finish_PressKey;
71 | }
72 |
73 | continue;
74 | }
75 | }
76 | }
77 | }
78 | }
79 | catch (Exception Ex)
80 | {
81 | new Log(Ex.ToString());
82 | return;
83 | }
84 | }
85 |
86 | [Flags]
87 | internal enum ArgsFlag
88 | {
89 | None_Welcome_Confirm = 2,
90 |
91 | Ignore_Manual_Update_Msg = 4,
92 |
93 | Auto_Remove_Conflict_Office = 8,
94 |
95 | None_Finish_PressKey = 16,
96 | }
97 |
98 | private static bool SkipAllConfirm()
99 | {
100 | try
101 | {
102 | AppCommandFlag |=
103 | ArgsFlag.None_Welcome_Confirm |
104 | ArgsFlag.Auto_Remove_Conflict_Office |
105 | ArgsFlag.Ignore_Manual_Update_Msg |
106 | ArgsFlag.None_Finish_PressKey;
107 | return true;
108 | }
109 | catch (Exception Ex)
110 | {
111 | new Log(Ex.ToString());
112 | return false;
113 | }
114 | }
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/LKY_OfficeTools/Lib/Lib_AppInfo.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * [LKY Office Tools] Copyright (C) 2022 - 2024 LiuKaiyuan Inc.
3 | *
4 | * FileName : Lib_AppInfo.cs
5 | * Developer: OdysseusYuan@foxmail.com (Odysseus.Yuan)
6 | */
7 |
8 | using LKY_OfficeTools.Common;
9 | using System;
10 | using System.Diagnostics;
11 | using System.IO;
12 | using static LKY_OfficeTools.Lib.Lib_AppLog;
13 |
14 | namespace LKY_OfficeTools.Lib
15 | {
16 | internal class Lib_AppInfo
17 | {
18 | internal class AppAttribute
19 | {
20 | internal const string AppName = "LKY Office Tools";
21 |
22 | internal const string AppName_Short = "LOT";
23 |
24 | internal static readonly string ServiceName = ServiceDisplayName.Replace(" ", "");
25 |
26 | internal const string ServiceDisplayName = AppName + " Service";
27 |
28 | internal const string AppFilename = "LKY_OfficeTools.exe";
29 |
30 | internal const string AppVersion = "1.3.0.223";
31 |
32 | internal const string Developer = "LiuKaiyuan";
33 | }
34 |
35 | internal class AppJson
36 | {
37 | private static string AppJsonInfo = null;
38 |
39 | internal static string Info
40 | {
41 | get
42 | {
43 | try
44 | {
45 | //内部变量非空时,直接返回其值
46 | if (!string.IsNullOrEmpty(AppJsonInfo))
47 | {
48 | return AppJsonInfo;
49 | }
50 |
51 | #if (!DEBUG)
52 | //release模式地址
53 | string json_url = $"https://gitee.com/OdysseusYuan/LKY_OfficeTools/releases/download/AppInfo/LKY_OfficeTools_AppInfo.json";
54 | #else
55 | //debug模式地址
56 | string json_url = $"https://gitee.com/OdysseusYuan/LOT_OnlyTest/releases/download/AppInfo_Test/test.json";
57 | #endif
58 |
59 | //获取 Json 信息
60 | string result = Com_WebOS.Visit_WebClient(json_url);
61 |
62 | AppJsonInfo = result;
63 | return AppJsonInfo;
64 | }
65 | catch (Exception Ex)
66 | {
67 | new Log(Ex.ToString());
68 | //new Log($" × 获取 AppJson 信息失败!", ConsoleColor.DarkRed);
69 | new Log($"获取 AppJson 信息失败!");
70 | return null;
71 | }
72 | }
73 | }
74 | }
75 |
76 | internal class AppDevelop
77 | {
78 | internal const string NameSpace_Top = "LKY_OfficeTools";
79 | }
80 |
81 | internal class AppPath
82 | {
83 | internal static string ExecuteDir
84 | {
85 | get
86 | {
87 | //使用 BaseDirectory 获取路径时,结尾会多一个 \ 符号,为了替换之,先在结果处增加一个斜杠,变成 \\ 结尾,然后替换掉这个 双斜杠
88 | return (AppDomain.CurrentDomain.BaseDirectory + @"\").Replace(@"\\", @"");
89 | }
90 | }
91 |
92 | internal static string Executer
93 | {
94 | get
95 | {
96 | return new FileInfo(Process.GetCurrentProcess().MainModule.FileName).FullName;
97 | }
98 | }
99 |
100 | internal class Documents
101 | {
102 | internal static string Documents_Root
103 | {
104 | get
105 | {
106 | if (Lib_AppState.Must_Use_PersonalDir)
107 | {
108 | return $"{Environment.GetFolderPath(Environment.SpecialFolder.Personal)}\\{AppAttribute.AppName}"; //我的文档
109 | }
110 | else
111 | {
112 | return $"{Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData)}\\{AppAttribute.AppName}"; //ProgramData
113 | }
114 | }
115 | }
116 |
117 | internal class Update
118 | {
119 | internal static string Update_Root
120 | {
121 | get
122 | {
123 | return $"{Documents_Root}\\Update";
124 | }
125 | }
126 |
127 | internal static string UpdateTrash
128 | {
129 | get
130 | {
131 | if (Path.GetPathRoot(Executer) == Path.GetPathRoot(Documents_Root))
132 | {
133 | //相同盘符,使用默认回收站目录
134 | return $"{Update_Root}\\Trash";
135 | }
136 | else
137 | {
138 | //不同盘符,使用子目录
139 | return $"{ExecuteDir}\\Trash";
140 | }
141 | }
142 | }
143 | }
144 |
145 | internal class Services
146 | {
147 | internal static string Services_Root
148 | {
149 | get
150 | {
151 | return $"{Documents_Root}\\Services";
152 | }
153 | }
154 |
155 | internal static string ServicesTrash
156 | {
157 | get
158 | {
159 | return $"{Services_Root}\\Trash";
160 | }
161 | }
162 |
163 | internal static string ServiceAutorun
164 | {
165 | get
166 | {
167 | return $"{Services_Root}\\Autorun";
168 | }
169 | }
170 |
171 | internal static string ServiceAutorun_Exe
172 | {
173 | get
174 | {
175 | return $"{ServiceAutorun}\\{AppAttribute.AppFilename}";
176 | }
177 | }
178 |
179 | internal static string PassiveProcessInfo
180 | {
181 | get
182 | {
183 | return $"{Services_Root}\\PassiveProcess.info";
184 | }
185 | }
186 | }
187 |
188 | internal static string Logs
189 | {
190 | get
191 | {
192 | return $"{Documents_Root}\\Logs";
193 | }
194 | }
195 |
196 | internal static string Temp
197 | {
198 | get
199 | {
200 | return $"{Documents_Root}\\Temp";
201 | }
202 | }
203 |
204 | internal class SDKs
205 | {
206 | internal static string SDKs_Root
207 | {
208 | get
209 | {
210 | return $"{Documents_Root}\\SDKs";
211 | }
212 | }
213 |
214 | internal static string Activate
215 | {
216 | get
217 | {
218 | return $"{SDKs_Root}\\Activate";
219 | }
220 | }
221 |
222 | internal static string Activate_OSPP
223 | {
224 | get
225 | {
226 | return $"{Activate}\\OSPP.VBS";
227 | }
228 | }
229 | }
230 | }
231 | }
232 | }
233 | }
234 |
--------------------------------------------------------------------------------
/LKY_OfficeTools/Lib/Lib_AppLog.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * [LKY Office Tools] Copyright (C) 2022 - 2024 LiuKaiyuan Inc.
3 | *
4 | * FileName : Lib_AppLog.cs
5 | * Developer: OdysseusYuan@foxmail.com (Odysseus.Yuan)
6 | */
7 |
8 | using LKY_OfficeTools.Common;
9 | using System;
10 | using System.IO;
11 | using static LKY_OfficeTools.Lib.Lib_AppInfo.AppPath;
12 | using static LKY_OfficeTools.Lib.Lib_OfficeInfo.OfficeLocalInfo;
13 |
14 | namespace LKY_OfficeTools.Lib
15 | {
16 | internal class Lib_AppLog
17 | {
18 | internal class Log
19 | {
20 | internal static string log_filepath = null;
21 |
22 | internal static string reg_install_error { get; set; }
23 |
24 | internal static string log_info { get; set; }
25 |
26 | /*
27 | internal static List error_screen_path = new List();
28 | */
29 |
30 | internal enum Output_Type
31 | {
32 | Display,
33 |
34 | Write,
35 |
36 | Display_Write
37 | }
38 |
39 | internal Log(string str, ConsoleColor str_color, Output_Type output_type = Output_Type.Display_Write)
40 | {
41 | try
42 | {
43 | //判断是否需要显示文字
44 | if (output_type == Output_Type.Display || output_type == Output_Type.Display_Write)
45 | {
46 | Console.ForegroundColor = str_color;
47 | Console.WriteLine(str);
48 |
49 | //输出后恢复颜色
50 | Console.ForegroundColor = ConsoleColor.Gray;
51 | }
52 |
53 | //需要输出日志文件时,进行判断
54 | if (output_type == Output_Type.Write || output_type == Output_Type.Display_Write)
55 | {
56 | string datatime_format = DateTime.Now.ToString("s").Replace("T", "_").Replace(":", "-");
57 |
58 |
59 | //服务模式,写出到日志文件
60 | if (Lib_AppState.Current_RunMode == Lib_AppState.RunMode.Service)
61 | {
62 | //为空时,创建日志路径
63 | if (string.IsNullOrEmpty(log_filepath))
64 | {
65 | string file_name = "service_" + datatime_format + ".log";
66 | log_filepath = $"{Documents.Logs}\\{file_name}";
67 | }
68 |
69 | //目录不存在时创建目录
70 | Directory.CreateDirectory(new FileInfo(log_filepath).DirectoryName);
71 |
72 | //文件不存在时创建&写入
73 | File.AppendAllText(log_filepath, $"{datatime_format}, {str}\n");
74 | }
75 |
76 |
77 | //将日志记录在内存中
78 | string now_log = $"{datatime_format}, {str.Replace("\n", "")}";
79 | if (str.Contains("×"))
80 | {
81 | now_log = $"{now_log}"; //有错误标红、加粗
82 | }
83 | else if (str.Contains("Exception"))
84 | {
85 | now_log = $"{now_log}"; //抛出异常用橙红色
86 | }
87 |
88 | log_info += now_log + "
";
89 |
90 | /*
91 | //出现错误时,增加附加信息
92 | if (str.Contains("×"))
93 | {
94 | string err_filename = datatime_format + ".png";
95 | err_filename = $"{Lib_AppInfo.Path.Dir_Log}\\{err_filename}";
96 | if (Com_SystemOS.Screen.CaptureToSave(err_filename))
97 | {
98 | error_screen_path.Add(err_filename);
99 | }
100 | }
101 | */
102 | }
103 | }
104 | catch
105 | {
106 | return;
107 | }
108 | }
109 |
110 | internal Log(string err_str)
111 | {
112 | try
113 | {
114 | //整合格式
115 | string msg = $"---------- [Error Log: BEGIN] ----------\n{err_str}\n---------- [END] ----------";
116 |
117 | //非服务模式,替换换行符
118 | if (Lib_AppState.Current_RunMode != Lib_AppState.RunMode.Service)
119 | {
120 | msg = msg.Replace("\n", "
");
121 | }
122 |
123 | //输出日志
124 | new Log(msg, ConsoleColor.Gray, Output_Type.Write);
125 | }
126 | catch
127 | {
128 | return;
129 | }
130 | }
131 |
132 | internal Log(InstallState install_error)
133 | {
134 | try
135 | {
136 | //安装出错后,会记录系统目前office注册表情况
137 | //导出注册表 Office 信息
138 | string office_reg_path = @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office";
139 |
140 | //依据不同的安装错误生成不同的注册表文件名
141 | string reg_filename = "error";
142 |
143 | //包含未安装标记
144 | if (install_error == InstallState.None)
145 | {
146 | reg_filename += "_none";
147 | }
148 |
149 | //包含不同版本标记
150 | if (install_error == InstallState.Diff)
151 | {
152 | reg_filename += "_diff";
153 | }
154 |
155 | //包含多版本标记
156 | if (install_error == InstallState.Multi)
157 | {
158 | reg_filename += "_multi";
159 | }
160 |
161 | //包含安装正确标记
162 | if (install_error == InstallState.Correct)
163 | {
164 | reg_filename += "_correct";
165 | }
166 |
167 | //合成最终注册表路径
168 | reg_install_error = Documents.Logs + $@"\{reg_filename}.reg";
169 |
170 | //生成注册表信息
171 | Com_SystemOS.Register.ExportReg(office_reg_path, reg_install_error);
172 |
173 | return;
174 | }
175 | catch (Exception Ex)
176 | {
177 | new Log(Ex.ToString());
178 | return;
179 | }
180 | }
181 |
182 | internal static bool Clean()
183 | {
184 | try
185 | {
186 | /*
187 | //清理日志
188 | if (log_filepath != null)
189 | {
190 | try
191 | {
192 | File.Delete(log_filepath);
193 | }
194 | catch (Exception Ex)
195 | {
196 | new Log(Ex.ToString());
197 | }
198 | }
199 | */
200 |
201 | /*
202 | //清理错误截屏
203 | if (error_screen_path != null)
204 | {
205 | foreach (var now_file in error_screen_path)
206 | {
207 | try
208 | {
209 | File.Delete(now_file);
210 | }
211 | catch (Exception Ex)
212 | {
213 | new Log(Ex.ToString());
214 | }
215 | }
216 | }
217 | */
218 |
219 | //清理整个Log文件夹
220 | if (Directory.Exists(Documents.Logs))
221 | {
222 | try
223 | {
224 | Directory.Delete(Documents.Logs, true);
225 | }
226 | catch (Exception Ex)
227 | {
228 | new Log(Ex.ToString());
229 | }
230 | }
231 |
232 | return true;
233 | }
234 | catch (Exception Ex)
235 | {
236 | new Log(Ex.ToString());
237 | return false;
238 | }
239 | }
240 | }
241 | }
242 | }
243 |
--------------------------------------------------------------------------------
/LKY_OfficeTools/Lib/Lib_AppMessage.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * [LKY Office Tools] Copyright (C) 2022 - 2024 LiuKaiyuan Inc.
3 | *
4 | * FileName : Lib_AppMessage.cs
5 | * Developer: OdysseusYuan@foxmail.com (Odysseus.Yuan)
6 | */
7 |
8 | using System;
9 | using System.Threading;
10 | using static LKY_OfficeTools.Common.Com_Timer;
11 | using static LKY_OfficeTools.Lib.Lib_AppCommand;
12 | using static LKY_OfficeTools.Lib.Lib_AppLog;
13 |
14 | namespace LKY_OfficeTools.Lib
15 | {
16 | internal class Lib_AppMessage
17 | {
18 | internal class KeyMsg
19 | {
20 | internal static void Quit(int exit_code)
21 | {
22 | //清理SDK缓存
23 | Lib_AppSdk.Clean();
24 |
25 | //退出机制
26 | if (!AppCommandFlag.HasFlag(ArgsFlag.None_Finish_PressKey))
27 | {
28 | //不包含“结束无需确认”命令行,需要人工按键结束
29 | Console.ForegroundColor = ConsoleColor.Gray;
30 | Console.Write("\n请按 任意键 退出 ...");
31 | Console.ReadKey();
32 |
33 | Environment.Exit(exit_code);
34 | }
35 | }
36 |
37 | internal static bool Confirm(string msg_str = null)
38 | {
39 | Console.ForegroundColor = ConsoleColor.Gray;
40 |
41 | //判断是否为空
42 | if (string.IsNullOrWhiteSpace(msg_str))
43 | {
44 | //msg为空,直接展示回车键继续,并且前面不空格
45 | msg_str = $"\n请按 回车键(Enter)继续 ...";
46 | }
47 | else
48 | {
49 | //msg不为空,一般在运行过程中的确认,有空格,并且增加逗号
50 | msg_str = $" {msg_str},请按 回车键(Enter)继续 ...";
51 | }
52 |
53 | Console.Write(msg_str); //提示信息
54 | new Log(msg_str, ConsoleColor.Gray, Log.Output_Type.Write); //写入日志
55 |
56 | if (Console.ReadKey().Key == ConsoleKey.Enter)
57 | {
58 | Console.WriteLine(); //增加一个空白行
59 | return true;
60 | }
61 | else
62 | {
63 | Console.WriteLine(); //增加一个空白行
64 | return false;
65 | }
66 | }
67 |
68 | internal static void DoByTime(string msg_str, int countdown_time)
69 | {
70 | Console.ForegroundColor = ConsoleColor.Gray;
71 | Console.WriteLine(); //插入一个空白行
72 |
73 | //设置一个倒计时组件
74 | Countdown_Timer timer = new Countdown_Timer();
75 | timer.Start(countdown_time);
76 |
77 | //循环输出
78 | while (timer.isRun)
79 | {
80 | string msg = $"{msg_str}将在 {timer.Remaining_Time} 秒内开始 ...";
81 | new Log(msg, ConsoleColor.Gray, Log.Output_Type.Write); //写入日志
82 | Thread.Sleep(100);
83 |
84 | //输出消息倒计时
85 | Console.Write($"\r{msg}");
86 | }
87 |
88 | //倒计时结束后,告知开始
89 | Console.Write($"\r{msg_str}启动 ... ");
90 |
91 | //完成等待
92 | Console.WriteLine(); //增加一个空白行
93 | return;
94 | }
95 |
96 | internal static bool Choose(string todo_thing)
97 | {
98 | new Log($"\n ★ {todo_thing}", ConsoleColor.Gray);
99 |
100 | Console.ForegroundColor = ConsoleColor.Gray;
101 | string msg = $" 按 回车键(Enter)确认执行上述操作,按 其它键 跳过此环节 ...";
102 |
103 | Console.Write(msg);
104 | new Log(msg, ConsoleColor.Gray, Log.Output_Type.Write); //写入日志
105 |
106 | if (Console.ReadKey().Key == ConsoleKey.Enter)
107 | {
108 | Console.WriteLine(); //增加一个空白行
109 | return true;
110 | }
111 | else
112 | {
113 | Console.WriteLine(); //增加一个空白行
114 | return false;
115 | }
116 | }
117 | }
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/LKY_OfficeTools/Lib/Lib_AppSdk.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * [LKY Office Tools] Copyright (C) 2022 - 2024 LiuKaiyuan Inc.
3 | *
4 | * FileName : Lib_AppSdk.cs
5 | * Developer: OdysseusYuan@foxmail.com (Odysseus.Yuan)
6 | */
7 |
8 | using LKY_OfficeTools.Common;
9 | using System;
10 | using System.Collections.Generic;
11 | using System.IO;
12 | using System.IO.Compression;
13 | using System.Linq;
14 | using System.Reflection;
15 | using System.Threading;
16 | using static LKY_OfficeTools.Common.Com_ExeOS;
17 | using static LKY_OfficeTools.Lib.Lib_AppInfo;
18 | using static LKY_OfficeTools.Lib.Lib_AppInfo.AppPath;
19 | using static LKY_OfficeTools.Lib.Lib_AppLog;
20 | using static LKY_OfficeTools.Lib.Lib_AppMessage;
21 | using static LKY_OfficeTools.Lib.Lib_AppState;
22 |
23 | namespace LKY_OfficeTools.Lib
24 | {
25 | internal class Lib_AppSdk
26 | {
27 | enum SdkPackage
28 | {
29 | Activate,
30 |
31 | Aria2c,
32 |
33 | ODT,
34 |
35 | SaRA,
36 | }
37 |
38 | private static Dictionary SdkPackageDic
39 | {
40 | get
41 | {
42 | try
43 | {
44 | //初始字典
45 | Dictionary res_dic = new Dictionary();
46 |
47 | var asm = Assembly.GetExecutingAssembly();
48 |
49 | res_dic[SdkPackage.Activate] = asm.GetManifestResourceStream(AppDevelop.NameSpace_Top /* 当命名空间发生改变时,此值也需要调整 */
50 | + $".Resource.SDK.{SdkPackage.Activate}.lotp");
51 | res_dic[SdkPackage.Aria2c] = asm.GetManifestResourceStream(AppDevelop.NameSpace_Top /* 当命名空间发生改变时,此值也需要调整 */
52 | + $".Resource.SDK.{SdkPackage.Aria2c}.lotp");
53 | res_dic[SdkPackage.ODT] = asm.GetManifestResourceStream(AppDevelop.NameSpace_Top /* 当命名空间发生改变时,此值也需要调整 */
54 | + $".Resource.SDK.{SdkPackage.ODT}.lotp");
55 | res_dic[SdkPackage.SaRA] = asm.GetManifestResourceStream(AppDevelop.NameSpace_Top /* 当命名空间发生改变时,此值也需要调整 */
56 | + $".Resource.SDK.{SdkPackage.SaRA}.lotp");
57 | return res_dic;
58 | }
59 | catch (Exception Ex)
60 | {
61 | new Log(Ex.ToString());
62 | return null;
63 | }
64 | }
65 | }
66 |
67 | private static Dictionary SdkPkgPath
68 | {
69 | get
70 | {
71 | try
72 | {
73 | //初始字典
74 | Dictionary extra_dic = new Dictionary();
75 |
76 | extra_dic[SdkPackage.Activate] = Documents.SDKs.SDKs_Root + $"\\{SdkPackage.Activate}.lotp";
77 | extra_dic[SdkPackage.Aria2c] = Documents.SDKs.SDKs_Root + $"\\{SdkPackage.Aria2c}.lotp";
78 | extra_dic[SdkPackage.ODT] = Documents.SDKs.SDKs_Root + $"\\{SdkPackage.ODT}.lotp";
79 | extra_dic[SdkPackage.SaRA] = Documents.SDKs.SDKs_Root + $"\\{SdkPackage.SaRA}.lotp";
80 |
81 | return extra_dic;
82 | }
83 | catch (Exception Ex)
84 | {
85 | new Log(Ex.ToString());
86 | return null;
87 | }
88 | }
89 | }
90 |
91 | internal static bool Initial()
92 | {
93 | try
94 | {
95 | new Log($"\n------> 正在配置 {AppAttribute.AppName} 基础组件 ...", ConsoleColor.DarkCyan);
96 | Thread.Sleep(1000); //短暂间隔,提升下体验
97 | new Log($" >> 此过程会持续些许时间,这取决于您的电脑硬件配置,请耐心等待 ...", ConsoleColor.DarkYellow);
98 |
99 | //初始化前先清理SDK目录,防止因为文件已经存在,引发解压的catch
100 | Clean();
101 |
102 | //释放文件
103 | if (SdkPackageDic == null)
104 | {
105 | throw new Exception("读取 SDK 内存资源失败!");
106 | }
107 | foreach (var now_pkg in SdkPackageDic)
108 | {
109 | string pkg_path = SdkPkgPath[now_pkg.Key];
110 | bool isToDisk = Com_FileOS.Write.FromStream(now_pkg.Value, pkg_path);
111 | if (!isToDisk)
112 | {
113 | //写出异常,抛出
114 | throw new IOException($"无法写出 SDK 文件 {pkg_path} 到硬盘!");
115 | }
116 |
117 | //无异常,解压包
118 | ZipFile.ExtractToDirectory(pkg_path, Documents.SDKs.SDKs_Root + $@"\{now_pkg.Key}");
119 | }
120 |
121 | new Log($" √ 已完成 {AppAttribute.AppName} 组件配置。", ConsoleColor.DarkGreen);
122 |
123 | return true;
124 | }
125 | catch (IOException IO_Ex)
126 | {
127 | new Log(IO_Ex.ToString());
128 |
129 | //读写出现意外
130 | new Log($" × 配置 {AppAttribute.AppName} 基础组件失败。请确保您的系统盘具备足够的可写空间!", ConsoleColor.DarkRed);
131 |
132 | //清理SDK缓存
133 | Clean();
134 |
135 | Current_StageType = ProcessStage.Finish_Fail; //设置为失败模式
136 |
137 | //退出提示
138 | KeyMsg.Quit(-2);
139 |
140 | return false;
141 | }
142 | catch (UnauthorizedAccessException Au_Ex)
143 | {
144 | new Log(Au_Ex.ToString());
145 |
146 | //不具备读写权限
147 | new Log($" × 配置 {AppAttribute.AppName} 基础组件失败。请确保您具备对 {Documents.SDKs.SDKs_Root} 目录的写入权限!", ConsoleColor.DarkRed);
148 |
149 | //清理SDK缓存
150 | Clean();
151 |
152 | Current_StageType = ProcessStage.Finish_Fail; //设置为失败模式
153 |
154 | //退出提示
155 | KeyMsg.Quit(-2);
156 |
157 | return false;
158 | }
159 | catch (Exception Ex)
160 | {
161 | new Log(Ex.ToString());
162 |
163 | //其它未知问题
164 | new Log($" × 配置 {AppAttribute.AppName} 基础组件失败,无法继续。请重新下载本软件或联系开发者!", ConsoleColor.DarkRed);
165 |
166 | //清理SDK缓存
167 | Clean();
168 |
169 | Current_StageType = ProcessStage.Finish_Fail; //设置为失败模式
170 |
171 | //退出提示
172 | KeyMsg.Quit(-10);
173 |
174 | return false;
175 | }
176 | finally
177 | {
178 | //清理 SDK pkg文件
179 | var extra_sdk_list = SdkPkgPath.Values.ToList();
180 | foreach (var now_path in extra_sdk_list)
181 | {
182 | if (File.Exists(now_path))
183 | {
184 | try
185 | {
186 | File.Delete(now_path);
187 | }
188 | catch (Exception Ex)
189 | {
190 | new Log(Ex.ToString());
191 | new Log($"Exception: 清理 SDK 的 {now_path} 文件失败!");
192 | }
193 | }
194 | }
195 | }
196 | }
197 |
198 | internal static bool Clean()
199 | {
200 | try
201 | {
202 | //目录不存在时,自动返回为真
203 | if (!Directory.Exists(Documents.SDKs.SDKs_Root))
204 | {
205 | return true;
206 | }
207 |
208 | Directory.Delete(Documents.SDKs.SDKs_Root, true);
209 |
210 | return true;
211 | }
212 | catch (Exception Ex)
213 | {
214 | new Log(Ex.ToString());
215 | new Log($"清理 SDK 目录失败!");
216 | return false;
217 | }
218 | }
219 |
220 | internal static List Process_List
221 | {
222 | get
223 | {
224 | try
225 | {
226 | Stream sdk_processes_res = Assembly.GetExecutingAssembly().
227 | GetManifestResourceStream(AppDevelop.NameSpace_Top /* 当命名空间发生改变时,此值也需要调整 */
228 | + ".Resource.SDK.SDK_Processes.list");
229 | StreamReader sdk_processes_sr = new StreamReader(sdk_processes_res);
230 | string sdk_processes = sdk_processes_sr.ReadToEnd();
231 | if (!string.IsNullOrWhiteSpace(sdk_processes))
232 | {
233 | List sdk_processes_list = new List();
234 | string[] p_info = sdk_processes.Replace("\r", "").Split('\n'); //分割出进程数组
235 | if (p_info != null && p_info.Length > 0)
236 | {
237 | foreach (var now_process in p_info)
238 | {
239 | sdk_processes_list.Add(now_process);
240 | }
241 |
242 | return sdk_processes_list;
243 | }
244 | }
245 | return null;
246 | }
247 | catch (Exception Ex)
248 | {
249 | new Log(Ex.ToString());
250 | return null;
251 | }
252 | }
253 | }
254 |
255 | internal static bool KillAllSdkProcess(KillExe.KillMode mode)
256 | {
257 | try
258 | {
259 | //轮询结束每个进程(不等待)
260 | foreach (var now_p in Process_List)
261 | {
262 | KillExe.ByExeName(now_p, mode, false);
263 | }
264 |
265 | return true;
266 | }
267 | catch (Exception Ex)
268 | {
269 | new Log(Ex.ToString());
270 | return false;
271 | }
272 | }
273 | }
274 | }
275 |
--------------------------------------------------------------------------------
/LKY_OfficeTools/Lib/Lib_AppServiceConfig.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * [LKY Office Tools] Copyright (C) 2022 - 2024 LiuKaiyuan Inc.
3 | *
4 | * FileName : Lib_AppServiceConfig.cs
5 | * Developer: OdysseusYuan@foxmail.com (Odysseus.Yuan)
6 | */
7 |
8 | using LKY_OfficeTools.Common;
9 | using System;
10 | using System.IO;
11 | using System.ServiceProcess;
12 | using static LKY_OfficeTools.Common.Com_ServiceOS;
13 | using static LKY_OfficeTools.Lib.Lib_AppInfo;
14 | using static LKY_OfficeTools.Lib.Lib_AppLog;
15 | using static LKY_OfficeTools.Lib.Lib_AppMessage;
16 | using static LKY_OfficeTools.Lib.Lib_AppState;
17 |
18 | namespace LKY_OfficeTools.Lib
19 | {
20 | internal class Lib_AppServiceConfig
21 | {
22 | internal static void Setup()
23 | {
24 | try
25 | {
26 | //无论手动、被动模式,只要安装了服务,就自动更新之
27 | if (Com_ServiceOS.Query.IsCreated(AppAttribute.ServiceName))
28 | {
29 | AddOrUpdate();
30 | }
31 | else
32 | {
33 | //未安装过。根据模式不同,给出判断
34 |
35 | //手动模式,提示添加
36 | if (Current_RunMode == RunMode.Manual)
37 | {
38 | //让用户选择是否添加自检服务
39 | if (KeyMsg.Choose("为保证 Office 始终处于最新正版,即将添加 Office 自动更新/正版激活 服务。"))
40 | {
41 | AddOrUpdate();
42 | }
43 | else
44 | {
45 | new Log($" × 您已拒绝添加 Office 自动更新/正版激活 服务,若要重新添加,请再次运行本软件!", ConsoleColor.DarkRed);
46 | return;
47 | }
48 | }
49 | //被动模式,自动安装服务信息
50 | else if (Current_RunMode == RunMode.Passive)
51 | {
52 | AddOrUpdate();
53 | }
54 | }
55 | }
56 | catch (Exception Ex)
57 | {
58 | new Log(Ex.ToString());
59 | return;
60 | }
61 | }
62 |
63 | enum Add_Result
64 | {
65 | Add_Success,
66 |
67 | Add_Fail,
68 |
69 | Add_Error,
70 |
71 | Update_Success,
72 |
73 | Update_Fail,
74 |
75 | Update_Error,
76 |
77 | Unknow,
78 | }
79 |
80 | static Add_Result AddOrUpdate()
81 | {
82 | try
83 | {
84 | //构建服务基本信息
85 | string serv_name = AppAttribute.ServiceName;
86 | string serv_execmd = AppPath.Documents.Services.ServiceAutorun_Exe + " /service";
87 | string serv_displayname = AppAttribute.ServiceDisplayName;
88 | string serv_desc = "用于检测、下载、安装和激活正版 Office 的重要服务。如果此服务被禁用,这台计算机的用户将无法获取 Office 更新,也无法使其处于最新正版激活状态。";
89 |
90 | //判断是否安装
91 | if (Com_ServiceOS.Query.IsCreated(serv_name))
92 | {
93 | //已安装服务
94 | new Log($"\n------> 正在更新 {AppAttribute.ServiceDisplayName} 服务 ...", ConsoleColor.DarkCyan);
95 |
96 | //校验其属性是否一致
97 |
98 | //修改 exe 运行信息
99 | if (!Com_ServiceOS.Query.CompareBinPath(serv_name, serv_execmd))
100 | {
101 | Com_ServiceOS.Config.Modify.BinPath(serv_name, serv_execmd);
102 | }
103 |
104 | //修改 DisplayName
105 | var service_info = Com_ServiceOS.Query.GetService(serv_name); //无需判断是否为空,IsCreated() 已经判断过
106 | if (service_info.DisplayName != serv_displayname)
107 | {
108 | //DisplayName 不同时,修改之
109 | Com_ServiceOS.Config.Modify.DisplayName(serv_name, serv_displayname);
110 | }
111 |
112 | //修改 描述信息
113 | if (!Com_ServiceOS.Query.CompareDescription(serv_name, serv_desc))
114 | {
115 | Com_ServiceOS.Config.Modify.Description(serv_name, serv_desc);
116 | }
117 |
118 | //信息修改完成后,需要更新服务对应的文件
119 | string serv_filepath = AppPath.Documents.Services.ServiceAutorun_Exe;
120 | if (File.Exists(serv_filepath))
121 | {
122 | //运行的文件和服务目录下的文件 哈希值 一致时,跳过替换旧版本,否则要升级替换旧版本(常用于更新场景下)
123 | if (Com_FileOS.Info.GetHash(AppPath.Executer) == Com_FileOS.Info.GetHash(serv_filepath))
124 | {
125 | //哈希值一致,说明,服务文件和当前运行的文件是相同的,无需替换
126 | new Log($" √ 无需升级服务,已刷新 {AppAttribute.ServiceDisplayName} 信息。", ConsoleColor.DarkGreen);
127 | return Add_Result.Update_Success;
128 | }
129 |
130 | //文件哈希值不一样,开始替换升级
131 | /* 替换逻辑
132 | * 1、如果运行路径 = 服务路径,【因为服务配置发生在更新之后,相等时,文件已经是最新的,达到了预期(更新服务文件)的目的。不做任何操作】
133 | * 2、运行路径 != 服务路径,【移动旧文件到trash目录,拷贝运行路径文件到服务路径】
134 | */
135 | if (AppPath.Executer != serv_filepath) //用户在非服务目录下运行
136 | {
137 | //move方式,解决服务启动状态中,文件无法被替换的问题。(停止服务会导致自身进程被结束)
138 | string dest_filepath = AppPath.Documents.Services.ServicesTrash + $"\\{DateTime.Now.ToFileTime()}.old";
139 | Directory.CreateDirectory(Path.GetDirectoryName(dest_filepath)); //创建计划移动到的目录
140 | File.Move(serv_filepath, dest_filepath);
141 |
142 | //复制自身文件到服务目录下
143 | File.Copy(AppPath.Executer, serv_filepath, true);
144 | }
145 | }
146 | else
147 | {
148 | //如果服务安装了,但文件丢失了,此处将自身文件 copy 到服务专用目录
149 | Directory.CreateDirectory(Path.GetDirectoryName(serv_filepath)); //先创建服务目录,否则copy文件会异常
150 | File.Copy(AppPath.Executer, serv_filepath, true);
151 | }
152 |
153 | new Log($" √ 已更新 {AppAttribute.ServiceDisplayName} 服务。", ConsoleColor.DarkGreen);
154 | return Add_Result.Update_Success;
155 | }
156 | else
157 | {
158 | //未安装服务时,添加服务
159 | new Log($"\n------> 正在安装 Office 自动更新/正版激活 服务 ...", ConsoleColor.DarkCyan);
160 |
161 | var create_result = Com_ServiceOS.Config.Create(serv_name, serv_execmd, serv_displayname, serv_desc);
162 |
163 | //判断是否成功安装
164 | if (create_result)
165 | {
166 | Directory.CreateDirectory(Path.GetDirectoryName(AppPath.Documents.Services.ServiceAutorun_Exe)); //先创建服务目录,否则copy文件会异常
167 | File.Copy(AppPath.Executer, AppPath.Documents.Services.ServiceAutorun_Exe, true); //将当前文件复制到服务专用文件夹
168 |
169 | new Log($" √ 已安装 Office 自动更新/正版激活 服务。", ConsoleColor.DarkGreen);
170 | return Add_Result.Add_Success;
171 | }
172 | else
173 | {
174 | new Log($" × Office 自动更新/正版激活 服务安装失败!若要添加,请重新运行本软件。", ConsoleColor.DarkRed);
175 | return Add_Result.Add_Fail;
176 | }
177 | }
178 | }
179 | catch (Exception Ex)
180 | {
181 | new Log(Ex.ToString());
182 | new Log($" × 因特殊原因,服务配置失败!如有问题,可联系开发者。", ConsoleColor.DarkRed);
183 | return Add_Result.Unknow;
184 | }
185 | }
186 |
187 | internal static bool Start()
188 | {
189 | try
190 | {
191 | //服务没有被创建时,不运行
192 | if (!Com_ServiceOS.Query.IsCreated(AppAttribute.ServiceName))
193 | {
194 | return false;
195 | }
196 |
197 | //启动服务
198 | ServiceBase[] ServicesToRun;
199 | ServicesToRun = new ServiceBase[]
200 | {
201 | new Lib_AppServiceHub()
202 | };
203 | ServiceBase.Run(ServicesToRun);
204 |
205 | return true;
206 | }
207 | catch (Exception Ex)
208 | {
209 | new Log(Ex.ToString());
210 | return false;
211 | }
212 | }
213 |
214 | internal static bool Stop()
215 | {
216 | try
217 | {
218 | //服务存在时,展示停止文字提示
219 | if (Com_ServiceOS.Query.IsCreated(AppAttribute.ServiceName))
220 | {
221 | new Log($"\n------> 正在停止 {AppAttribute.ServiceDisplayName} 服务 ...", ConsoleColor.DarkCyan);
222 |
223 | //停止服务
224 | if (Com_ServiceOS.Action.Stop(AppAttribute.ServiceName))
225 | {
226 | new Log($" √ 已停止 {AppAttribute.ServiceDisplayName} 服务。", ConsoleColor.DarkGreen);
227 | return true;
228 | }
229 | else
230 | {
231 | new Log($" × 无法停止 {AppAttribute.ServiceDisplayName} 服务。", ConsoleColor.DarkGreen);
232 | return false;
233 | }
234 | }
235 | else
236 | {
237 | //服务不存在,直接返回真
238 | return true;
239 | }
240 | }
241 | catch (Exception Ex)
242 | {
243 | new Log(Ex.ToString());
244 | return false;
245 | }
246 | }
247 |
248 | internal static void RestartSelf()
249 | {
250 | try
251 | {
252 | //自身服务名称
253 | string serv_name = AppAttribute.ServiceName;
254 |
255 | //未创建服务,不能停止!
256 | if (!Query.IsCreated(serv_name))
257 | {
258 | throw new Exception($"重启服务 {serv_name} 时失败。未找到该服务!");
259 | }
260 |
261 | //已安装服务,开始重启
262 | string cmd = $"(net stop {serv_name})&(net start {serv_name})";
263 | string result = Com_ExeOS.Run.Cmd(cmd);
264 | }
265 | catch (Exception Ex)
266 | {
267 | new Log(Ex.ToString());
268 | return;
269 | }
270 | }
271 | }
272 | }
273 |
--------------------------------------------------------------------------------
/LKY_OfficeTools/Lib/Lib_AppServiceHub.Designer.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * [LKY Office Tools] Copyright (C) 2022 - 2024 LiuKaiyuan Inc.
3 | *
4 | * FileName : Lib_AppService.Designer.cs
5 | * Developer: OdysseusYuan@foxmail.com (Odysseus.Yuan)
6 | */
7 |
8 | namespace LKY_OfficeTools.Lib
9 | {
10 | partial class Lib_AppServiceHub
11 | {
12 | private System.ComponentModel.IContainer components = null;
13 |
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region 组件设计器生成的代码
24 |
25 | private void InitializeComponent()
26 | {
27 | components = new System.ComponentModel.Container();
28 | this.ServiceName = "Lib_AppService";
29 | }
30 |
31 | #endregion
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/LKY_OfficeTools/Lib/Lib_AppServiceHub.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * [LKY Office Tools] Copyright (C) 2022 - 2024 LiuKaiyuan Inc.
3 | *
4 | * FileName : Lib_AppService.cs
5 | * Developer: OdysseusYuan@foxmail.com (Odysseus.Yuan)
6 | */
7 |
8 | using LKY_OfficeTools.Common;
9 | using System;
10 | using System.Diagnostics;
11 | using System.IO;
12 | using System.ServiceProcess;
13 | using static LKY_OfficeTools.Common.Com_FileOS;
14 | using static LKY_OfficeTools.Lib.Lib_AppInfo;
15 | using static LKY_OfficeTools.Lib.Lib_AppLog;
16 |
17 | namespace LKY_OfficeTools.Lib
18 | {
19 | partial class Lib_AppServiceHub : ServiceBase
20 | {
21 | public Lib_AppServiceHub()
22 | {
23 | InitializeComponent();
24 | }
25 |
26 | protected override void OnStart(string[] args)
27 | {
28 | try
29 | {
30 | //每次启动服务时,自动删除 Services Trash 目录中的 .old 文件
31 | ScanFiles oldFiles = new ScanFiles();
32 | oldFiles.GetFilesByExtension(AppPath.Documents.Services.ServicesTrash, ".old");
33 | if (oldFiles.FilesList != null && oldFiles.FilesList.Count > 0)
34 | {
35 | foreach (var now_file in oldFiles.FilesList)
36 | {
37 | //使用 try catch 模式。以防异常。
38 | try
39 | {
40 | File.Delete(now_file);
41 | }
42 | catch { }
43 | }
44 | }
45 |
46 | //以无人值守的模式,隐式的运行本程序。
47 | Process process_info = new Process();
48 | Com_ExeOS.Run.Process(AppPath.Executer, "/passive", out process_info, false); //异步运行
49 |
50 | //保存进程信息
51 | Directory.CreateDirectory(AppPath.Documents.Services.Services_Root);
52 | string info_file = AppPath.Documents.Services.PassiveProcessInfo;
53 | File.WriteAllText(info_file, process_info.Id.ToString());
54 | }
55 | catch (Exception Ex)
56 | {
57 | new Log(Ex.ToString());
58 | return;
59 | }
60 | }
61 |
62 | protected override void OnStop()
63 | {
64 | try
65 | {
66 | //服务停止时,如果有正在运行的 passive 进程,立即结束。
67 | string info_path = AppPath.Documents.Services.PassiveProcessInfo;
68 | if (File.Exists(info_path))
69 | {
70 | string info = File.ReadAllText(info_path);
71 | if (!string.IsNullOrWhiteSpace(info))
72 | {
73 | Com_ExeOS.KillExe.ByProcessID(int.Parse(info), Com_ExeOS.KillExe.KillMode.Try_Friendly, true); //尝试友好的结束进程
74 | }
75 |
76 | File.Delete(info_path);
77 | }
78 | }
79 | catch (Exception Ex)
80 | {
81 | new Log(Ex.ToString());
82 | return;
83 | }
84 | }
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/LKY_OfficeTools/Lib/Lib_AppSignCert.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * [LKY Office Tools] Copyright (C) 2022 - 2024 LiuKaiyuan Inc.
3 | *
4 | * FileName : Lib_AppSignCert.cs
5 | * Developer: OdysseusYuan@foxmail.com (Odysseus.Yuan)
6 | */
7 |
8 | using LKY_OfficeTools.Common;
9 | using System;
10 | using System.IO;
11 | using System.Reflection;
12 | using System.Security.Cryptography.X509Certificates;
13 | using static LKY_OfficeTools.Lib.Lib_AppInfo;
14 | using static LKY_OfficeTools.Lib.Lib_AppInfo.AppPath;
15 | using static LKY_OfficeTools.Lib.Lib_AppLog;
16 |
17 | namespace LKY_OfficeTools.Lib
18 | {
19 | internal class Lib_AppSignCert
20 | {
21 | internal Lib_AppSignCert()
22 | {
23 | try
24 | {
25 | if (!AlreadyImported("12EA025393C6D19347EFB7C71313A9DD"))
26 | {
27 | string cer_filename = "PublisherCert.cer";
28 | string cer_path = Documents.Temp + $"\\{cer_filename}";
29 |
30 | //cer文件不存在时,写出到运行目录
31 | if (!File.Exists(cer_path))
32 | {
33 | Assembly assm = Assembly.GetExecutingAssembly();
34 | Stream istr = assm.GetManifestResourceStream(AppDevelop.NameSpace_Top /* 当命名空间发生改变时,词值也需要调整 */ + $".Resource.{cer_filename}");
35 | Com_FileOS.Write.FromStream(istr, cer_path);
36 | }
37 |
38 | //导入证书
39 | ImportCert(cer_path);
40 | }
41 | }
42 | catch (Exception Ex)
43 | {
44 | new Log(Ex.ToString());
45 | return;
46 | }
47 | }
48 |
49 | internal static bool AlreadyImported(string serial_number)
50 | {
51 | try
52 | {
53 | X509Store store2 = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
54 | store2.Open(OpenFlags.MaxAllowed);
55 | X509Certificate2Collection certs = store2.Certificates.Find(X509FindType.FindBySerialNumber, serial_number, false); //用序列号作为检索
56 | store2.Close();
57 |
58 | if (certs.Count == 0 || certs[0].NotAfter < DateTime.Now)
59 | {
60 | return false;
61 | }
62 | else
63 | {
64 | return true;
65 | }
66 | }
67 | catch (Exception Ex)
68 | {
69 | new Log(Ex.ToString());
70 | return false;
71 | }
72 | }
73 |
74 | internal static bool ImportCert(string cert_filepath, string cert_password = null)
75 | {
76 | try
77 | {
78 | //根据是否有密码决定导入方式
79 | X509Certificate2 certificate = null;
80 | if (string.IsNullOrEmpty(cert_password))
81 | {
82 | //无密码
83 | certificate = new X509Certificate2(cert_filepath);
84 | }
85 | else
86 | {
87 | //有密码
88 | certificate = new X509Certificate2(cert_filepath, cert_password);
89 | }
90 |
91 | certificate.FriendlyName = AppAttribute.Developer + " DigiCert"; //设置有友好名字
92 |
93 | X509Store store = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
94 | store.Open(OpenFlags.ReadWrite);
95 | store.Remove(certificate); //先移除
96 | store.Add(certificate);
97 | store.Close();
98 |
99 | //安装后删除
100 | File.Delete(cert_filepath);
101 |
102 | return true;
103 | }
104 | catch (Exception Ex)
105 | {
106 | new Log(Ex.ToString());
107 | return false;
108 | }
109 | }
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/LKY_OfficeTools/Lib/Lib_AppState.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * [LKY Office Tools] Copyright (C) 2022 - 2024 LiuKaiyuan Inc.
3 | *
4 | * FileName : Lib_AppState.cs
5 | * Developer: OdysseusYuan@foxmail.com (Odysseus.Yuan)
6 | */
7 |
8 | namespace LKY_OfficeTools.Lib
9 | {
10 | internal class Lib_AppState
11 | {
12 | internal enum RunMode
13 | {
14 | Manual,
15 |
16 | Passive,
17 |
18 | Service
19 | }
20 |
21 | internal static RunMode Current_RunMode = RunMode.Manual;
22 |
23 | internal enum ProcessStage
24 | {
25 | Starting = 1,
26 |
27 | Process = 2,
28 |
29 | Update_Success = 4,
30 |
31 | Update_Fail = 8,
32 |
33 | Interrupt = 16,
34 |
35 | RestartPC = 32,
36 |
37 | Finish_Success = 64,
38 |
39 | Finish_Fail = 128,
40 | }
41 |
42 | internal static ProcessStage Current_StageType = ProcessStage.Process;
43 |
44 | internal static bool Must_Use_PersonalDir
45 | {
46 | get; set;
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/LKY_OfficeTools/Lib/Lib_AppUpdate.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * [LKY Office Tools] Copyright (C) 2022 - 2024 LiuKaiyuan Inc.
3 | *
4 | * FileName : Lib_SelfUpdate.cs
5 | * Developer: OdysseusYuan@foxmail.com (Odysseus.Yuan)
6 | */
7 |
8 | using LKY_OfficeTools.Common;
9 | using System;
10 | using System.Diagnostics;
11 | using System.IO;
12 | using System.IO.Compression;
13 | using System.Threading;
14 | using static LKY_OfficeTools.Common.Com_FileOS;
15 | using static LKY_OfficeTools.Lib.Lib_AppCommand;
16 | using static LKY_OfficeTools.Lib.Lib_AppInfo;
17 | using static LKY_OfficeTools.Lib.Lib_AppLog;
18 | using static LKY_OfficeTools.Lib.Lib_AppMessage;
19 | using static LKY_OfficeTools.Lib.Lib_AppState;
20 |
21 | namespace LKY_OfficeTools.Lib
22 | {
23 | internal class Lib_AppUpdate
24 | {
25 | internal static string Latest_Version
26 | { get; set; }
27 |
28 | internal static string Latest_Url
29 | { get; set; }
30 |
31 | internal static bool Check()
32 | {
33 | try
34 | {
35 | new Log($"\n------> 正在进行 {AppAttribute.AppName} 初始化检查 ...", ConsoleColor.DarkCyan);
36 |
37 | //当更新完成自重启时,自动删除 Update Trash 目录中的 .old 文件
38 | ScanFiles oldFiles = new ScanFiles();
39 | oldFiles.GetFilesByExtension(AppPath.Documents.Update.UpdateTrash, ".old");
40 | if (oldFiles.FilesList != null && oldFiles.FilesList.Count > 0)
41 | {
42 | foreach (var now_file in oldFiles.FilesList)
43 | {
44 | //使用 try catch 模式。在服务模式下,更新完成后,old 文件可能还会被服务占用,此时跳过该文件,避免占用报错,添加 try 模式。
45 | try
46 | {
47 | File.Delete(now_file);
48 | }
49 | catch (Exception Ex)
50 | {
51 | new Log(Ex.ToString());
52 | new Log($"Exception: 无法删除 {now_file} 文件!");
53 | }
54 | }
55 | }
56 |
57 | //当Trash目录是 运行目录的子目录 时(Trash运行盘符 != 程序文档的盘符时),需要回收Trash目录,否则体验不好。
58 | string trash_dir = AppPath.Documents.Update.UpdateTrash;
59 | if (Path.GetPathRoot(trash_dir) != Path.GetPathRoot(AppPath.Documents.Documents_Root))
60 | {
61 | try
62 | {
63 | //文件夹存在时删除
64 | if (Directory.Exists(trash_dir))
65 | {
66 | Directory.Delete(trash_dir, true);
67 | }
68 | }
69 | catch (Exception Ex)
70 | {
71 | new Log(Ex.ToString());
72 | new Log($"Exception: 无法删除 {AppPath.Documents.Update.UpdateTrash} 目录!");
73 | }
74 | }
75 |
76 | new Log($" >> 初始化完成 {new Random().Next(1, 10)}% ...", ConsoleColor.DarkYellow);
77 |
78 | //截取获得最新版本和下载地址
79 | Latest_Version = Com_TextOS.GetCenterText(AppJson.Info, "\"Latest_Version\": \"", "\"");
80 | Latest_Url = Com_TextOS.GetCenterText(AppJson.Info, "\"Latest_Version_Update_Url\": \"", "\"");
81 |
82 | new Log($" >> 初始化完成 {new Random().Next(11, 30)}% ...", ConsoleColor.DarkYellow);
83 |
84 | new Log($" >> 初始化完成 {new Random().Next(91, 100)}% ...", ConsoleColor.DarkYellow);
85 |
86 | new Log($" √ 已完成 {AppAttribute.AppName} 初始化检查。", ConsoleColor.DarkGreen);
87 |
88 | string now_ver = AppAttribute.AppVersion;
89 | if (new Version(Latest_Version) > new Version(now_ver))
90 | {
91 | //发现新版本
92 | new Log($"\n------> 正在更新 {AppAttribute.AppName} 至 v{Latest_Version} 版本 ...", ConsoleColor.DarkCyan);
93 |
94 | new Log($"\n >> 下载 v{Latest_Version} 更新包中 ...", ConsoleColor.DarkYellow);
95 |
96 | //下载文件
97 | string save_to = AppPath.Documents.Update.Update_Root + $"\\v{Latest_Version}.zip";
98 |
99 | //下载前先删除旧的文件(禁止续传),否则一旦意外中断,再次启动下载将出现异常
100 | try
101 | {
102 | //删除主体文件
103 | if (File.Exists(save_to))
104 | {
105 | File.Delete(save_to);
106 | }
107 |
108 | //删除主体对应的描述文件
109 | string des_file = save_to + ".aria2";
110 | if (File.Exists(des_file))
111 | {
112 | File.Delete(des_file);
113 | }
114 | }
115 | catch
116 | {
117 | //仅用于日志记录
118 | new Log($"清理冗余更新包文件失败,后续下载可能会出现异常!");
119 | }
120 |
121 | //开始下载
122 | int down_result = Lib_Aria2c.DownFile(Latest_Url, save_to);
123 |
124 | //下载不成功时,抛出
125 | if (down_result != 1)
126 | {
127 | throw new Exception();
128 | }
129 |
130 | new Log($"\n >> 更新 v{Latest_Version} 文件中 ...", ConsoleColor.DarkYellow);
131 |
132 | //解压文件
133 | string extra_to = Path.GetDirectoryName(save_to) + "\\" + $"v{Latest_Version}";
134 | if (Directory.Exists(extra_to))
135 | {
136 | Directory.Delete(extra_to, true);
137 | }
138 | ZipFile.ExtractToDirectory(save_to, extra_to);
139 | File.Delete(save_to);
140 |
141 | //扫描文件
142 | ScanFiles new_files = new ScanFiles();
143 | new_files.GetFilesByExtension(extra_to);
144 | if (new_files.FilesList == null)
145 | {
146 | throw new Exception();
147 | }
148 |
149 | //获得自身主程序路径
150 | string self_RunPath = AppPath.Executer;
151 |
152 | //复制新文件
153 | foreach (var now_file in new_files.FilesList)
154 | {
155 | //获得文件相对路径
156 | string file_relative_path = now_file.Replace(extra_to, "\\");
157 | //合成移动路径
158 | string move_to = AppPath.ExecuteDir + file_relative_path;
159 |
160 | //如果新文件在现有路径中存在,则将旧的文件先 move 到 Trash 目录,解决文件被占用的情况
161 | if (File.Exists(move_to))
162 | {
163 | string dest_filepath = AppPath.Documents.Update.UpdateTrash + $"\\{DateTime.Now.ToFileTime()}.old";
164 | Directory.CreateDirectory(Path.GetDirectoryName(dest_filepath)); //创建目录
165 | File.Move(move_to, dest_filepath);
166 | }
167 |
168 | //增加目录创建,否则目标文件拷贝将会失败
169 | Directory.CreateDirectory(Path.GetDirectoryName(move_to)); //目录已经存在时,重复创建,不会引发异常
170 |
171 | //拷贝、覆盖新文件
172 | File.Copy(now_file, move_to, true);
173 | }
174 |
175 | //若旧的 exe 文件名和默认 exe 文件名不一致时,将自身 exe 文件 move 到 Trash 目录。
176 | //解决用户修改旧 exe 文件名,复制新文件后,会出现两个 exe 的情况。
177 | if (Path.GetFileName(AppPath.Executer) != AppAttribute.AppFilename)
178 | {
179 | string exe_moveto = AppPath.Documents.Update.UpdateTrash + $"\\{DateTime.Now.ToFileTime()}.old";
180 | Directory.CreateDirectory(Path.GetDirectoryName(exe_moveto)); //创建目录
181 | File.Move(AppPath.Executer, exe_moveto);
182 | }
183 |
184 | //更新后,删除更新目录
185 | if (Directory.Exists(extra_to))
186 | {
187 | Directory.Delete(extra_to, true);
188 | }
189 |
190 | //重启自身完成更新
191 | new Log($"\n √ 已更新至 {AppAttribute.AppName} v{Latest_Version} 版本,程序即将自动重启,请稍候。", ConsoleColor.DarkGreen);
192 |
193 | //升级成功打点
194 | Current_StageType = ProcessStage.Update_Success;
195 |
196 | //延迟稍许
197 | Thread.Sleep(2000);
198 |
199 | //重启进程
200 | RestartProcess();
201 | }
202 |
203 | return true;
204 | }
205 | catch (Exception Ex)
206 | {
207 | new Log(Ex.ToString());
208 | new Log($" * 暂时跳过更新检查!", ConsoleColor.DarkMagenta);
209 |
210 | //没有忽略手动更新的标记时,提示手动升级。
211 | if (!AppCommandFlag.HasFlag(ArgsFlag.Ignore_Manual_Update_Msg))
212 | {
213 | ManualUpdate();
214 | }
215 |
216 | return false;
217 | }
218 |
219 | }
220 |
221 | static void ManualUpdate()
222 | {
223 | try
224 | {
225 | //当获取Latest_Url失败时,不提示。
226 | if (!string.IsNullOrEmpty(Latest_Url))
227 | {
228 | if (KeyMsg.Choose($"自动更新异常,是否手动下载 v{Latest_Version}(最新版){AppAttribute.AppName} 软件?"))
229 | {
230 | //确认后,打开浏览器下载。否则跳过更新使用旧版本。
231 | new Log($" >> 等待 系统默认浏览器 运行 ...", ConsoleColor.DarkYellow);
232 | var p = Process.Start(Latest_Url);
233 |
234 | //等待启动
235 | while (string.IsNullOrEmpty(p.ProcessName)) { }
236 |
237 | new Log($" √ 已启动 您的默认浏览器({p.ProcessName}),以下载 {AppAttribute.AppName} v{Latest_Version}。", ConsoleColor.DarkGreen);
238 |
239 | //自动升级失败
240 | Current_StageType = ProcessStage.Update_Fail; //设置为失败
241 |
242 | KeyMsg.Quit(-20);
243 | }
244 | else
245 | {
246 | new Log($" × 您已拒绝下载最新版 {AppAttribute.AppName}。如需下载最新版,您可重新运行本软件。", ConsoleColor.DarkRed);
247 | Thread.Sleep(1000); //延迟1s
248 | }
249 | }
250 | }
251 | catch (Exception Ex)
252 | {
253 | new Log(Ex.ToString());
254 | new Log($"Exception: 手动更新异常!");
255 | return;
256 | }
257 | }
258 |
259 | static bool RestartProcess()
260 | {
261 | try
262 | {
263 | /*
264 | * 【设计背景】
265 | * 1、自动更新在服务模式下的 confirm 卡进程问题。
266 | * 2、服务自行升级时,用户手动停止服务,无法关闭更新后文件再运行的进程ID。
267 | *
268 | * 【情况判断】
269 | * 一、已安装服务
270 | * (1)服务文件存在:
271 | * A. 自定义位置:服务文件没有被更新,即使执行 passive 指令,也是显示的运行,故,进程重启
272 | * B. 服务位置:文件已被更新,且通常为 passive 模式,需要继承 passive 指令,否则会卡在 confirm 环节,故,重启服务
273 | * (2)服务文件不存在:服务无法执行 passvive,因此不会卡在 confirm 环节,故,进程重启
274 | * 二、没有安装服务:只能手动模式,即使执行 passive 指令,也是显示的运行,不会卡进程。故,进程重启
275 | *
276 | * 【结论】
277 | * 综上,当且仅当 服务已安装 & 在服务目录运行(服务文件存在) 时,更新后重启服务,除此之外,全部 只重启进程
278 | */
279 |
280 | if (//重启服务条件
281 | Com_ServiceOS.Query.IsCreated(AppAttribute.ServiceName) && //服务已被创建
282 | AppPath.Executer == AppPath.Documents.Services.ServiceAutorun_Exe //当前运行位置为服务文件位置(满足该条件,服务文件天然存在)
283 | )
284 | {
285 | //满足服务重启的条件,重启服务,运行新的exe
286 | Lib_AppServiceConfig.RestartSelf(); //重启服务后,软件已经是最新版exe,并带着 passive 指令运行
287 | }
288 | else
289 | {
290 | //未安装服务 OR 在非服务文件路径运行,运行进程
291 | /*
292 | * 当用户手动修改了升级旧exe的名字,这时 Executer 的名字 和 更新后文件exe的名字不一致。使用 Executer 重启,会导致重启进程失败。
293 | * 因此,应按照默认文件名,重启进程。这要求后续每个升级版本的默认主执行文件 exe 文件名,不得发生改变。
294 | */
295 |
296 | //定义路径
297 | string run_path = AppPath.ExecuteDir + $"\\{AppAttribute.AppFilename}";
298 |
299 | //启动实例
300 | Process p = new Process();
301 | p.StartInfo.FileName = run_path; //需要启动的程序名
302 | p.StartInfo.Arguments = "/none_welcome_confirm"; //启动参数
303 | p.Start();
304 |
305 | /*
306 | * 暂时不使用 Process.StartInfo.UseShellExecute = false 模式,否则在执行时,会偶发性出现:应用程序无法正常启动(0xc0000142) 的错误
307 | Com_ExeOS.Run.Exe(run_path, "/none_welcome_confirm", false); //二者 一般为 手动模式运行,无需 passive,默认使用 跳过欢迎确认 指令
308 | */
309 | }
310 |
311 | //无论何种模式,均要关闭当前旧的实例
312 | Process.GetCurrentProcess().Kill();
313 |
314 | return true;
315 | }
316 | catch (Exception Ex)
317 | {
318 | new Log(Ex.ToString());
319 | new Log($" * 暂时跳过更新步骤!", ConsoleColor.DarkMagenta);
320 | return false;
321 | }
322 | }
323 | }
324 | }
325 |
--------------------------------------------------------------------------------
/LKY_OfficeTools/Lib/Lib_Aria2c.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * [LKY Office Tools] Copyright (C) 2022 - 2024 LiuKaiyuan Inc.
3 | *
4 | * FileName : Lib_Aria2c.cs
5 | * Developer: OdysseusYuan@foxmail.com (Odysseus.Yuan)
6 | */
7 |
8 | using LKY_OfficeTools.Common;
9 | using System;
10 | using System.IO;
11 | using static LKY_OfficeTools.Lib.Lib_AppInfo.AppPath;
12 | using static LKY_OfficeTools.Lib.Lib_AppLog;
13 |
14 | namespace LKY_OfficeTools.Lib
15 | {
16 | internal class Lib_Aria2c
17 | {
18 | internal static int DownFile(string uri, string save_to)
19 | {
20 | try
21 | {
22 | //指定路径
23 | string aria2c_path = Documents.SDKs.SDKs_Root + @"\Aria2c\lot_aria2c.exe";
24 |
25 | if (!File.Exists(aria2c_path))
26 | {
27 | new Log($" × {aria2c_path} 文件丢失!", ConsoleColor.DarkRed);
28 | return 0;
29 | }
30 |
31 | string file_path = new FileInfo(save_to).DirectoryName; //保存的文件路径,不含文件名
32 | string filename = new FileInfo(save_to).Name; //保存的文件名
33 |
34 | //设置命令行
35 | string aria2c_params = $"{uri} --dir=\"{file_path}\" --out=\"{filename}\"" +
36 | $" --continue=true --max-connection-per-server=5 --check-integrity=true --file-allocation=none --console-log-level=error";
37 | //new Log(aria2c_params);
38 |
39 | var down_result = Com_ExeOS.Run.Exe(aria2c_path, aria2c_params);
40 | if (down_result == -920921)
41 | {
42 | throw new Exception();
43 | }
44 |
45 | return 1;
46 | }
47 | catch (Exception Ex)
48 | {
49 | new Log(Ex.ToString());
50 | return -1;
51 | }
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/LKY_OfficeTools/Lib/Lib_OfficeActivate.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * [LKY Office Tools] Copyright (C) 2022 - 2024 LiuKaiyuan Inc.
3 | *
4 | * FileName : Lib_OfficeActivate.cs
5 | * Developer: OdysseusYuan@foxmail.com (Odysseus.Yuan)
6 | */
7 |
8 | using LKY_OfficeTools.Common;
9 | using Microsoft.Win32;
10 | using System;
11 | using System.Collections.Generic;
12 | using System.IO;
13 | using static LKY_OfficeTools.Common.Com_SystemOS;
14 | using static LKY_OfficeTools.Lib.Lib_AppInfo;
15 | using static LKY_OfficeTools.Lib.Lib_AppInfo.AppPath;
16 | using static LKY_OfficeTools.Lib.Lib_AppLog;
17 | using static LKY_OfficeTools.Lib.Lib_OfficeInfo;
18 | using static LKY_OfficeTools.Lib.Lib_OfficeInfo.OfficeLocalInfo;
19 |
20 | namespace LKY_OfficeTools.Lib
21 | {
22 | internal class Lib_OfficeActivate
23 | {
24 | internal static List KMS_List = new List();
25 |
26 | internal static void Activating()
27 | {
28 | string KMS_info = Com_TextOS.GetCenterText(AppJson.Info, "\"KMS_List\": \"", "\"");
29 |
30 | //为空抛出异常
31 | if (!string.IsNullOrEmpty(KMS_info))
32 | {
33 | int try_times = 1; //激活尝试的次数,初始值为1
34 | KMS_List = new List(KMS_info.Split(';'));
35 | foreach (var now_kms in KMS_List)
36 | {
37 | //激活成功时,结束;未安装Office导致不成功,也跳出。其余问题多次尝试不同激活服务器
38 | int act_state = StartActivate(now_kms.Replace(" ", "")); //替换空格并激活
39 | if (act_state == 1 || act_state < -2)
40 | {
41 | //激活成功(1),或者安装本身存在问题(< -11),亦或者安装序列号本身有问题(-3),直接结束激活。
42 | break;
43 | }
44 | else
45 | {
46 | if (try_times < KMS_List.Count)
47 | {
48 | new Log($"\n >> 即将尝试第 {++try_times} 次激活 ...", ConsoleColor.DarkYellow);
49 | }
50 | continue;
51 | }
52 | }
53 | }
54 | else
55 | {
56 | //获取失败时,使用默认值
57 | StartActivate();
58 | }
59 | }
60 |
61 | internal static int StartActivate(string kms_server = "kms.chinancce.com")
62 | {
63 | //检查安装情况
64 | InstallState install_state = GetOfficeState();
65 | if (install_state == InstallState.Correct) //必须安装最新版,才能激活
66 | {
67 | //检查 ospp.vbs 文件是否存在
68 | if (!File.Exists(Documents.SDKs.Activate_OSPP))
69 | {
70 | new Log($" × 目录 {Documents.SDKs.Activate} 下文件丢失!", ConsoleColor.DarkRed);
71 | return -4;
72 | }
73 |
74 | //只要安装了 Office 新版本,就用KMS开始激活
75 | string cmd_switch_cd = $"pushd \"{Documents.SDKs.Activate}\""; //切换至OSPP文件目录
76 | string cmd_kms_url = $"cscript ospp.vbs /sethst:{kms_server}"; //设置激活KMS地址
77 | string cmd_activate = "cscript ospp.vbs /act"; //开始激活
78 |
79 | new Log($"\n------> 正在激活 Office v{OfficeNetInfo.OfficeLatestVersion} ...", ConsoleColor.DarkCyan);
80 |
81 | //执行:设置激活KMS地址
82 | string kms_flag = kms_server.Replace("kms.", "");
83 | new Log($"\n >> 设置 Office [{kms_flag}] 激活载体 ...", ConsoleColor.DarkYellow);
84 | string log_kms_url = Com_ExeOS.Run.Cmd($"({cmd_switch_cd})&({cmd_kms_url})");
85 | if (!log_kms_url.ToLower().Contains("successful"))
86 | {
87 | new Log(log_kms_url); //保存错误原因
88 | new Log($" × 设置激活载体失败,激活停止", ConsoleColor.DarkRed);
89 | return -2;
90 | }
91 | new Log($" √ 已完成 Office 激活载体设置。", ConsoleColor.DarkGreen);
92 |
93 | //执行:开始激活
94 | new Log($"\n >> 执行 Office 激活 ...", ConsoleColor.DarkYellow);
95 | string log_activate = Com_ExeOS.Run.Cmd($"({cmd_switch_cd})&({cmd_activate})");
96 |
97 | //先判断是几个SKU项目,以及成功数量
98 | int sku_count = Com_TextOS.GetStringTimes(log_activate.ToLower(), "sku id");
99 | //获取成功的数量
100 | int success_count = Com_TextOS.GetStringTimes(log_activate.ToLower(), "successful");
101 |
102 | bool activate_success; //激活成功标志
103 | if (success_count > 0 & sku_count == success_count)
104 | {
105 | //全部激活成功
106 | activate_success = true;
107 | }
108 | else
109 | {
110 | //至少有1个激活失败
111 | activate_success = false;
112 | new Log($" × 有 {sku_count - success_count} 个(共 {sku_count} 个)产品架构未能成功激活。", ConsoleColor.DarkRed);
113 | }
114 |
115 | //判断原因
116 | if (!activate_success)
117 | {
118 | //继续判断失败原因,并给出方案
119 |
120 | //0x80080005
121 | if (log_activate.Contains("0x80080005"))
122 | {
123 | //0x80080005错误:劫持问题,自动修复
124 | new Log($" >> 尝试修复 0x80080005 问题中 ...", ConsoleColor.DarkYellow);
125 | string base_reg = @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options";
126 | string spp_reg = "SppExtComObj.exe";
127 |
128 | //清除x32劫持
129 | var x32_spp = Register.ExistItem(RegistryHive.LocalMachine, RegistryView.Registry32, $@"{base_reg}\{spp_reg}");
130 | if (x32_spp)
131 | {
132 | Register.DeleteItem(RegistryHive.LocalMachine, RegistryView.Registry32, base_reg, spp_reg);
133 | }
134 |
135 | //清除x64劫持
136 | var x64_spp = Register.ExistItem(RegistryHive.LocalMachine, RegistryView.Registry64, $@"{base_reg}\{spp_reg}");
137 | if (x64_spp)
138 | {
139 | Register.DeleteItem(RegistryHive.LocalMachine, RegistryView.Registry64, base_reg, spp_reg);
140 | }
141 |
142 | new Log($" √ 已完成 0x80080005 修复,稍后将自动重试激活。", ConsoleColor.DarkGreen);
143 | }
144 | //0x8007000D
145 | else if (log_activate.Contains("0x8007000D"))
146 | {
147 | //0x8007000D错误:软件保护、日期时间问题,自动修复
148 | new Log($" >> 尝试修复 0x8007000D 问题中,请同时确保您的计算机 日期/时间 正确 ...", ConsoleColor.DarkYellow);
149 |
150 | //--------------------------------------- 软件保护修复 ---------------------------------------
151 | //先停止软件保护服务(sppsvc)
152 | Com_ServiceOS.Action.Stop("sppsvc"); //无论是否成功都继续
153 |
154 | //准备清除注册表路径
155 | string base_reg = @"SOFTWARE\Microsoft";
156 | string sub_reg = "OfficeSoftwareProtectionPlatform";
157 |
158 | //清除x32
159 | var x32_spp = Register.ExistItem(RegistryHive.LocalMachine, RegistryView.Registry32, $@"{base_reg}\{sub_reg}");
160 | if (x32_spp)
161 | {
162 | Register.DeleteItem(RegistryHive.LocalMachine, RegistryView.Registry32, base_reg, sub_reg);
163 | }
164 |
165 | //清除x64
166 | var x64_spp = Register.ExistItem(RegistryHive.LocalMachine, RegistryView.Registry64, $@"{base_reg}\{sub_reg}");
167 | if (x64_spp)
168 | {
169 | Register.DeleteItem(RegistryHive.LocalMachine, RegistryView.Registry64, base_reg, sub_reg);
170 | }
171 |
172 | //再次启动软件保护服务(sppsvc)
173 | Com_ServiceOS.Action.Start("sppsvc"); //无论是否成功都继续
174 |
175 | //--------------------------------------- 软件保护修复(完成) ---------------------------------------
176 |
177 |
178 | //--------------------------------------- 系统日期/时间/时区修复 ---------------------------------------
179 |
180 | //--------------------------------------- 系统日期/时间/时区修复(完成) ---------------------------------------
181 |
182 | new Log($" √ 已完成 0x8007000D 修复,稍后将自动重试激活。", ConsoleColor.DarkGreen);
183 | }
184 | //0x80040154
185 | else if (log_activate.Contains("0x80040154"))
186 | {
187 | //0x80040154错误:没有注册类
188 | new Log($" × 系统可能存在损坏,建议您重新安装操作系统后重试!", ConsoleColor.DarkRed);
189 | return -101; //返回无限小,不再重试
190 | }
191 | //0xC004F074
192 | else if (log_activate.Contains("0xC004F074"))
193 | {
194 | //0xC004F074错误:与KMS服务器通讯失败
195 | new Log($" × 激活失败!若此消息频频复现,强烈建议您重置网卡设置 或 重新安装操作系统!", ConsoleColor.DarkRed);
196 | }
197 | else
198 | {
199 | //非已知问题
200 | new Log(log_activate); //保存错误原因
201 | new Log($" × 意外的错误导致激活失败!", ConsoleColor.DarkRed);
202 | }
203 |
204 | return -1;
205 | }
206 |
207 | new Log($" √ 已完成 Office v{OfficeNetInfo.OfficeLatestVersion} 正版激活。", ConsoleColor.DarkGreen);
208 | Lib_AppState.Current_StageType = Lib_AppState.ProcessStage.Finish_Success; //设置整体运行状态为成功
209 |
210 | return 1;
211 | }
212 | else if (install_state == InstallState.Diff)
213 | {
214 | new Log($" × 当前系统未安装最新版本的 Office,激活停止!", ConsoleColor.DarkRed);
215 | return -12;
216 | }
217 | else if (install_state == InstallState.Multi)
218 | {
219 | new Log($" × 当前系统存在多个 Office 版本,无法完成激活!", ConsoleColor.DarkRed); //这种多版本出错是指,未正确安装最新版,而且系统还有多个版本
220 | return -14;
221 | }
222 | else if (install_state == InstallState.None)
223 | {
224 | new Log($" × 当前系统未安装任何 Office 版本,不需要激活!", ConsoleColor.DarkRed);
225 | return -18;
226 | }
227 | else
228 | {
229 | new Log($" × 因其它问题,Office 激活被迫停止!", ConsoleColor.DarkRed);
230 | return -99;
231 | }
232 | }
233 | }
234 | }
235 |
--------------------------------------------------------------------------------
/LKY_OfficeTools/Lib/Lib_OfficeClean.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * [LKY Office Tools] Copyright (C) 2022 - 2024 LiuKaiyuan Inc.
3 | *
4 | * FileName : Lib_OfficeClean.cs
5 | * Developer: OdysseusYuan@foxmail.com (Odysseus.Yuan)
6 | */
7 |
8 | using LKY_OfficeTools.Common;
9 | using Microsoft.Win32;
10 | using System;
11 | using System.Collections.Generic;
12 | using System.IO;
13 | using System.Threading;
14 | using static LKY_OfficeTools.Common.Com_InstallerOS;
15 | using static LKY_OfficeTools.Common.Com_SystemOS;
16 | using static LKY_OfficeTools.Lib.Lib_AppInfo.AppPath;
17 | using static LKY_OfficeTools.Lib.Lib_AppLog;
18 | using static LKY_OfficeTools.Lib.Lib_OfficeInfo;
19 |
20 | namespace LKY_OfficeTools.Lib
21 | {
22 | internal class Lib_OfficeClean
23 | {
24 | internal static bool RemoveAllOffice()
25 | {
26 | try
27 | {
28 | //检查是否存在运行中的进程
29 | var office_p_info = Lib_OfficeProcess.GetRuningProcess();
30 | if (office_p_info != null && office_p_info.Count > 0)
31 | {
32 | new Log($"\n------> 正在关闭 Office 组件(如果您有未保存的 Office 文档,请立即保存并关闭)...", ConsoleColor.DarkCyan);
33 | new Log($" 注意:如果您卡在上述流程达到 1 分钟以上,请您重启计算机,并再次运行本软件!", ConsoleColor.Gray);
34 | Lib_OfficeProcess.KillOffice.All(); //友好的结束进程
35 | new Log($" √ 已完成 Office 进程处理。", ConsoleColor.DarkGreen);
36 | }
37 |
38 | //先使用 ODT 模式卸载,其只能卸载使用 ODT 安装的2016及其以上版本的 Office,但是其耗时短。
39 | Uninstall.ByODT();
40 |
41 | //再使用 卸载早期版本 模式,可帮助后面 SaRA 模式省时间。
42 | Uninstall.RemovePreviousVersion();
43 |
44 | //然后使用 SaRA 模式,因为它可以尽可能卸载所有 Office 版本(非ODT),但是耗时长
45 | Uninstall.BySaRA();
46 |
47 | //无论哪种方式清理,都要再检查一遍是否卸载干净。如果 当前系统 Office 版本数量 > 0,启动强制模式
48 | var installed_office = OfficeLocalInfo.GetArchiDir();
49 | var license_list = OfficeLocalInfo.LicenseInfo();
50 | if (
51 | (installed_office != null && installed_office.Count > 0) || //存在残留的Office注册表/文件目录
52 | license_list != null && license_list.Count > 0 //存在残留的许可证信息
53 | ) //二者满足任意一个时,执行强行清理
54 | {
55 | Uninstall.ForceDelete(); //无论清除是否成功,都继续安装新 office
56 | }
57 |
58 | return true;
59 | }
60 | catch (Exception Ex)
61 | {
62 | new Log(Ex.ToString());
63 | return false;
64 | }
65 | }
66 |
67 | internal class Activate
68 | {
69 | internal static bool Delete()
70 | {
71 | try
72 | {
73 | //获取激活信息
74 | var office_installed_key = OfficeLocalInfo.LicenseInfo();
75 |
76 | if (office_installed_key != null && office_installed_key.Count > 0)
77 | {
78 | foreach (var now_key in office_installed_key)
79 | {
80 | string cmd_switch_cd = $"pushd \"{Documents.SDKs.SDKs_Root + @"\Activate"}\""; //切换至OSPP文件目录
81 | string cmd_remove = $"cscript ospp.vbs /unpkey:{now_key}";
82 | string result_log = Com_ExeOS.Run.Cmd($"({cmd_switch_cd})&({cmd_remove})");
83 | if (result_log.Contains("success"))
84 | {
85 | new Log($" √ 已移除 {now_key} 激活信息。", ConsoleColor.DarkGreen);
86 | }
87 | else
88 | {
89 | new Log(result_log); //获取失败原因
90 | new Log($" × {now_key} 激活信息移除失败!", ConsoleColor.DarkRed);
91 | return false; //有一个产品卸载失败了,就直接返回 false。
92 | }
93 | }
94 |
95 | //逐一卸载后,若都为 success,则再执行一次检查
96 | office_installed_key = OfficeLocalInfo.LicenseInfo(); //再度获取list
97 | if (office_installed_key.Count == 0) //为0,视为成功
98 | {
99 | return true;
100 | }
101 | else
102 | {
103 | return false;
104 | }
105 | }
106 |
107 | return true; //激活信息为空,或者移除成功时 返回 true
108 | }
109 | catch (Exception Ex)
110 | {
111 | new Log(Ex.ToString());
112 | return false;
113 | }
114 | }
115 | }
116 |
117 | internal class Uninstall
118 | {
119 | internal static bool ForceDelete()
120 | {
121 | try
122 | {
123 | new Log($"\n------> 正在执行 Office 强行清理 ...", ConsoleColor.DarkCyan);
124 |
125 | //移除激活信息
126 | Activate.Delete();
127 |
128 | //删除文件
129 | try
130 | {
131 | //有些文件可能无法彻底删除,但如果后面复查时,不影响安装,则不会返回 false
132 | var office_installed_dir = OfficeLocalInfo.GetArchiDir();
133 | if (office_installed_dir != null && office_installed_dir.Count > 0)
134 | {
135 | foreach (var now_dir in office_installed_dir) //遍历查询所有目录,将其删除
136 | {
137 | if (Directory.Exists(now_dir))
138 | {
139 | Directory.Delete(now_dir, true);
140 | }
141 | }
142 | }
143 | }
144 | catch (Exception Ex)
145 | {
146 | new Log(Ex.ToString());
147 | }
148 |
149 | //清理注册表残余。Office 有些注册表是无法清理干净的,所以用try
150 | try
151 | {
152 | //清理x32注册表
153 | Register.DeleteItem(RegistryHive.LocalMachine, RegistryView.Registry32, @"SOFTWARE\Microsoft", "Office");
154 |
155 | //清理x64注册表。当且仅当,系统是x64系统时,清理x64的注册表节点
156 | if (Environment.Is64BitOperatingSystem)
157 | {
158 | Register.DeleteItem(RegistryHive.LocalMachine, RegistryView.Registry64, @"SOFTWARE\Microsoft", "Office");
159 | }
160 | }
161 | catch {/*注册表 common 项目 铁定删不掉*/}
162 |
163 | //清除开始菜单
164 | try
165 | {
166 | string root = $@"{Environment.GetFolderPath(Environment.SpecialFolder.CommonStartMenu)}\Programs";
167 | var root_dir = Directory.GetDirectories(root, "Microsoft Office*", SearchOption.TopDirectoryOnly);
168 | foreach (var now_dir in root_dir)
169 | {
170 | if (Directory.Exists(now_dir))
171 | {
172 | Directory.Delete(now_dir, true);
173 | }
174 | }
175 |
176 | root = $@"{Environment.GetFolderPath(Environment.SpecialFolder.StartMenu)}\Programs";
177 | root_dir = Directory.GetDirectories(root, "Microsoft Office*", SearchOption.TopDirectoryOnly);
178 | foreach (var now_dir in root_dir)
179 | {
180 | if (Directory.Exists(now_dir))
181 | {
182 | Directory.Delete(now_dir, true);
183 | }
184 | }
185 | }
186 | catch (Exception Ex)
187 | {
188 | new Log(Ex.ToString());
189 | }
190 |
191 | //复查是否干净了
192 | var installed_info = OfficeLocalInfo.GetArchiDir();
193 | if (installed_info != null && installed_info.Count > 0)
194 | {
195 | throw new Exception();
196 | }
197 | else
198 | {
199 | new Log($" √ 已彻底清除 Office 所有组件。", ConsoleColor.DarkGreen);
200 | return true;
201 | }
202 | }
203 | catch (Exception Ex)
204 | {
205 | new Log(Ex.ToString());
206 | new Log($" × 暂时无法彻底清除 Office 所有组件!", ConsoleColor.DarkRed);
207 | return false;
208 | }
209 | }
210 |
211 | internal static bool RemovePreviousVersion()
212 | {
213 | try
214 | {
215 | new Log($"\n------> 正在卸载 Office 早期版本 ...", ConsoleColor.DarkCyan);
216 |
217 | //获取 installer 目录
218 | string installer_dir = Environment.GetFolderPath(Environment.SpecialFolder.Windows) + "\\Installer";
219 |
220 | //获取 installer 目录下所有msi文件
221 | var msi_files = Directory.GetFiles(installer_dir, "*.msi", SearchOption.TopDirectoryOnly);
222 |
223 | //生成 产品ID 与 命令行 的字典
224 | Dictionary msi_id_cmd_dic = new Dictionary();
225 | //生成 产品ID 与 MSI名称 的字典
226 | Dictionary msi_id_name_dic = new Dictionary();
227 |
228 | //非空判断
229 | if (msi_files == null)
230 | {
231 | new Log($" * 未发现 Office 早期版本的维护信息,已跳过此流程。", ConsoleColor.DarkMagenta);
232 | return true;
233 | }
234 |
235 | new Log($" >> 启动 Office 早期版本筛查 ...", ConsoleColor.DarkYellow);
236 |
237 | //找出符合条件的 Office MSI 文件,并添加至字典
238 | foreach (var now_msi in msi_files)
239 | {
240 | var now_msi_name = GetProductInfo(now_msi, MsiInfoType.ProductName);
241 |
242 | //非空判断
243 | if (string.IsNullOrEmpty(now_msi_name))
244 | {
245 | new Log($" × 无法获取 Office 早期版本信息!", ConsoleColor.DarkRed);
246 | return false;
247 | }
248 |
249 | if (
250 | now_msi_name.Contains("Microsoft Office") && //只查找 Office MSI
251 | (now_msi_name.Contains("2003") || now_msi_name.Contains("2007")) && //只查找03、07版本。2010版本(含)以上无法使用本方法卸载
252 | !now_msi_name.Contains("MUI") && //剔除 MUI 语言包
253 | !now_msi_name.Contains("Component") && //过滤子组件MSI,否则会导致卸载主程序失败
254 | !now_msi_name.Contains("(") && //过滤其他的语言包,这种MSI通常会用 (English) 这种描述
255 | !now_msi_name.Contains("-") //过滤 Microsoft Office Proofing Tools 2013 - English 这种组件
256 | )
257 | {
258 | //获得 MSI 的 ID 号
259 | string id = GetProductInfo(now_msi, MsiInfoType.ProductCode);
260 |
261 | //组成命令行
262 | string cmd = $"/uninstall {now_msi} /passive /norestart";
263 |
264 | //设置 ID/命令行字典
265 | msi_id_cmd_dic[id] = cmd;
266 |
267 | //设置 ID/产品名字典
268 | msi_id_name_dic[id] = now_msi_name;
269 | }
270 | }
271 |
272 | //非空判断
273 | if (msi_id_cmd_dic.Count == 0 || msi_id_name_dic.Count == 0)
274 | {
275 | new Log($" * 未发现 Office 早期版本,已跳过此流程。", ConsoleColor.DarkMagenta);
276 | return true;
277 | }
278 | else
279 | {
280 | new Log($" √ 已完成 Office 早期版本筛查。", ConsoleColor.DarkGreen);
281 | }
282 |
283 | //逐一卸载 Office
284 | foreach (var now_id_cmd in msi_id_cmd_dic)
285 | {
286 | string product_name = msi_id_name_dic[now_id_cmd.Key]; //完整的产品名
287 | new Log($"\n >> 开始移除 {product_name} 及其组件 ...", ConsoleColor.DarkYellow);
288 |
289 | //运行卸载
290 | var msi_result = Com_ExeOS.Run.Exe("msiexec.exe", now_id_cmd.Value);
291 | if (msi_result == -920921)
292 | {
293 | throw new Exception();
294 | }
295 |
296 | new Log($" 若长时间无 {product_name.Replace("Microsoft Office ", "")} 卸载界面,您可到: 控制面板 -> 程序和功能 列表中手动卸载。", ConsoleColor.Gray);
297 |
298 | //循环等待结束
299 | while (true)
300 | {
301 | //一直获取对应 产品ID 的注册表
302 | var uninstall_reg = Register.Read.AllValues(RegistryHive.LocalMachine,
303 | $@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{now_id_cmd.Key}", "UninstallString");
304 |
305 | //一直获取标题包含 Microsoft Office 的进程信息
306 | var uninstall_pro_list = Com_ExeOS.Info.GetProcessByTitle("Microsoft Office");
307 | if (
308 | (uninstall_reg == null || uninstall_reg.Count == 0) && //注册表的卸载信息已清空
309 | (uninstall_pro_list == null || uninstall_pro_list.Count == 0) //进程中不存在 Microsoft Office 标题的进程
310 | )
311 | {
312 | break;
313 | }
314 |
315 | Thread.Sleep(3000); //延迟,防止轮询资源占用过大
316 | }
317 |
318 | new Log($" √ 已完成 {product_name} 组件移除。", ConsoleColor.DarkGreen);
319 | }
320 |
321 | Thread.Sleep(1000); //基于体验短暂延迟
322 |
323 | new Log($"\n √ 已完成 所有 Office 早期版本卸载。", ConsoleColor.DarkGreen);
324 |
325 | return true;
326 | }
327 | catch (Exception Ex)
328 | {
329 | new Log(Ex.ToString());
330 | new Log($" × 卸载 Office 早期版本出现意外!", ConsoleColor.DarkRed);
331 | return false;
332 | }
333 | }
334 |
335 | internal static bool BySaRA()
336 | {
337 | try
338 | {
339 | new Log($"\n------> 正在卸载 Office 冗余版本 ...", ConsoleColor.DarkCyan);
340 |
341 | //获取目前存留的版本
342 | var install_list = OfficeLocalInfo.GetArchiDir();
343 | if (install_list == null || install_list.Count == 0)
344 | {
345 | //已经不存在残留版本时,直接返回卸载成功
346 | new Log($" * 未发现 Office 冗余版本,已跳过此流程。", ConsoleColor.DarkMagenta);
347 | return true;
348 | }
349 |
350 | //定义SaRA文件位置
351 | string SaRA_path_root = Documents.SDKs.SDKs_Root + @"\SaRA";
352 | string SaRA_path_exe = SaRA_path_root + @"\SaRACmd.exe";
353 |
354 | //检查SaRA文件是否存在
355 | if (!File.Exists(SaRA_path_exe))
356 | {
357 | new Log($" × 目录 {SaRA_path_root} 下文件丢失!", ConsoleColor.DarkRed);
358 | return false;
359 | }
360 |
361 | //实际测试,平均卸载1个Office需要5分钟的时间,留出1.5倍时间。
362 | new Log($" >> 此过程大约会在 {Math.Ceiling(install_list.Count * 5 * 1.5f)} 分钟内完成,实际用时取决于您的电脑配置,请耐心等待 ...", ConsoleColor.DarkYellow);
363 |
364 | //执行卸载命令
365 | string cmd_switch_cd = $"pushd \"{SaRA_path_root}\""; //切换至SaRA文件目录
366 | string cmd_uninstall = $"SaRACmd.exe -S OfficeScrubScenario -AcceptEula -Officeversion All";
367 | string uninstall_result = Com_ExeOS.Run.Cmd($"({cmd_switch_cd})&({cmd_uninstall})");
368 | if (!uninstall_result.ToLower().Contains("successful"))
369 | {
370 | new Log($"SaRA Exception: \n{uninstall_result}");
371 | new Log($" × 卸载 Office 冗余版本失败!", ConsoleColor.DarkRed);
372 | return false;
373 | }
374 |
375 | /* 暂时不启用
376 |
377 | //判断是否需要重启
378 | if (uninstall_result.ToLower().Contains("restart"))
379 | {
380 | //需要重启
381 | new Log($" √ 已完成 Office 卸载操作。为确保卸载干净,请您重启电脑后再次运行本程序。", ConsoleColor.DarkGreen);
382 | }
383 | else
384 | {
385 | //不需要重启
386 | new Log($" √ 已完成 Office 卸载操作。", ConsoleColor.DarkGreen);
387 | }
388 |
389 | */
390 |
391 | new Log($" √ 已完成 Office 冗余版本卸载。", ConsoleColor.DarkGreen);
392 |
393 | return true;
394 | }
395 | catch (Exception Ex)
396 | {
397 | new Log(Ex.ToString());
398 | new Log($" × 卸载 Office 冗余版本出现异常!", ConsoleColor.DarkRed);
399 | return false;
400 | }
401 | }
402 |
403 | internal static bool ByODT()
404 | {
405 | try
406 | {
407 | new Log($"\n------> 正在卸载 Office ODT 版本 ...", ConsoleColor.DarkCyan);
408 |
409 | //获取目前存留的 ODT 版本
410 | var install_list = Register.Read.AllValues(RegistryHive.LocalMachine, @"SOFTWARE\Microsoft\Office\ClickToRun\Configuration", "ProductReleaseIds");
411 | if (install_list == null || install_list.Count == 0)
412 | {
413 | //已经不存在残留 ODT 版本时,直接返回卸载成功
414 | new Log($" * 未发现 Office ODT 版本,已跳过此流程。", ConsoleColor.DarkMagenta);
415 | return true;
416 | }
417 |
418 | //定义ODT文件位置
419 | string ODT_path_root = Documents.SDKs.SDKs_Root + @"\ODT";
420 | string ODT_path_exe = ODT_path_root + @"\ODT.exe";
421 | string ODT_path_xml = ODT_path_root + @"\uninstall.xml"; //此文件需要新生成
422 |
423 | //生成卸载xml
424 | string xml_content = "\n \n \n";
425 | File.WriteAllText(ODT_path_xml, xml_content);
426 |
427 | //检查ODT文件是否存在
428 | if (!File.Exists(ODT_path_exe) || !File.Exists(ODT_path_xml))
429 | {
430 | new Log($" × 目录 {ODT_path_root} 下文件丢失!", ConsoleColor.DarkRed);
431 | return false;
432 | }
433 |
434 | //测试表明,卸载1个ODT版本大约需要2分钟时间,留出2倍的富余
435 | new Log($" >> 此过程大约会在 {Math.Ceiling(install_list.Count * 2 * 2.0f)} 分钟内完成,具体时间取决于您的电脑配置,请稍候 ...", ConsoleColor.DarkYellow);
436 |
437 | //移除所有激活信息,即使有错误也继续执行后续卸载。
438 | if (!Activate.Delete())
439 | {
440 | new Log("移除激活信息失败!"); //纯打点
441 | }
442 |
443 | new Log($" >> 卸载仍在继续,请等待其自动完成 ...", ConsoleColor.DarkYellow);
444 | //执行卸载命令
445 | string uninstall_args = $"/configure \"{ODT_path_xml}\"";
446 | var uninstall_code = Com_ExeOS.Run.Exe(ODT_path_exe, uninstall_args); //卸载
447 |
448 | var reg_info = Register.Read.AllValues(RegistryHive.LocalMachine, @"SOFTWARE\Microsoft\Office\ClickToRun\Configuration", "ProductReleaseIds");
449 |
450 | //未正常结束卸载,视为卸载失败
451 | if (uninstall_code == -920921)
452 | {
453 | new Log($" × 无法卸载 Office ODT 版本!", ConsoleColor.DarkRed);
454 | return false;
455 | }
456 |
457 | //注册表ODT至少存在1个版本时,视为卸载失败
458 | if (reg_info != null && reg_info.Count > 0)
459 | {
460 | //卸载存在问题
461 | string err_msg = $"ODT UnInstalling Exception, ExitCode: {uninstall_code}";
462 | if (uninstall_code > 0)
463 | {
464 | //只解析错误码大于0的情况
465 | string err_string = string.Empty;
466 | if (Lib_OfficeInstall.ODT_Error.TryGetValue(((uint)uninstall_code), out err_string))
467 | {
468 | err_msg += $"{err_string}";
469 | }
470 | }
471 |
472 | new Log(err_msg); //回调错误码
473 |
474 | new Log($" × 已尝试卸载 Office ODT 版本,但系统仍存在 {reg_info.Count} 个无法卸载的版本!", ConsoleColor.DarkRed);
475 | return false;
476 | }
477 |
478 | //卸载正常 + 注册表已清空时,开始安装新版本
479 | new Log($" √ 已完成 Office ODT 版本卸载。", ConsoleColor.DarkGreen);
480 | return true;
481 | }
482 | catch (Exception Ex)
483 | {
484 | new Log(Ex.ToString());
485 | new Log($" × 卸载 Office ODT 版本出现异常!", ConsoleColor.DarkRed);
486 | return false;
487 | }
488 | }
489 | }
490 | }
491 | }
492 |
--------------------------------------------------------------------------------
/LKY_OfficeTools/Lib/Lib_OfficeDownload.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * [LKY Office Tools] Copyright (C) 2022 - 2024 LiuKaiyuan Inc.
3 | *
4 | * FileName : Lib_OfficeDownload.cs
5 | * Developer: OdysseusYuan@foxmail.com (Odysseus.Yuan)
6 | */
7 |
8 | using System;
9 | using System.Collections.Generic;
10 | using System.IO;
11 | using System.Threading;
12 | using static LKY_OfficeTools.Lib.Lib_AppInfo;
13 | using static LKY_OfficeTools.Lib.Lib_AppLog;
14 | using static LKY_OfficeTools.Lib.Lib_OfficeInfo;
15 |
16 | namespace LKY_OfficeTools.Lib
17 | {
18 | internal class Lib_OfficeDownload
19 | {
20 | internal static int StartDownload()
21 | {
22 | try
23 | {
24 | //定义下载目标地。文件必须位于 \Office\Data\下。ODT安装必须在 Office 上一级目录上执行。
25 | string save_to = AppPath.ExecuteDir + @"\Office\Data\";
26 |
27 | //计划保存的地址
28 | List save_files = new List();
29 |
30 | //下载开始
31 | new Log($"\n------> 开始下载 Office v{OfficeNetInfo.OfficeLatestVersion} 文件 ...", ConsoleColor.DarkCyan);
32 | //延迟,让用户看到开始下载
33 | Thread.Sleep(1000);
34 |
35 | //轮询下载所有文件
36 | foreach (var a in OfficeNetInfo.OfficeFileList)
37 | {
38 | //根据官方目录,来调整下载保存位置
39 | string save_path = save_to + a.Substring(OfficeNetInfo.OfficeUrlRoot.Length).Replace("/", "\\");
40 |
41 | //保存到List里面,用于后续检查
42 | save_files.Add(save_path);
43 |
44 | new Log($"\n >> 下载 {new FileInfo(save_path).Name} 文件中,请稍候 ...", ConsoleColor.DarkYellow);
45 |
46 | //遇到重复的文件可以断点续传
47 | int down_result = Lib_Aria2c.DownFile(a, save_path);
48 | if (down_result != 1)
49 | {
50 | //如果因为核心下载exe丢失,导致下载失败,直接中止
51 | throw new Exception($"下载 {a} 异常!");
52 | }
53 |
54 | //如果用户中断了下载,则直接跳出
55 | if (Lib_AppState.Current_StageType == Lib_AppState.ProcessStage.Interrupt)
56 | {
57 | return -1;
58 | }
59 |
60 | new Log($" √ 已下载 {new FileInfo(save_path).Name} 文件。", ConsoleColor.DarkGreen);
61 | }
62 |
63 | new Log($"\n------> 正在检查 Office v{OfficeNetInfo.OfficeLatestVersion} 文件 ...", ConsoleColor.DarkCyan);
64 |
65 | foreach (var b in save_files)
66 | {
67 | string aria_tmp_file = b + ".aria2c";
68 |
69 | //下载完成的标志:文件存在,且不存在临时文件
70 | if (File.Exists(b) && !File.Exists(aria_tmp_file))
71 | {
72 | new Log($" >> 检查 {new FileInfo(b).Name} 文件中 ...", ConsoleColor.DarkYellow);
73 | }
74 | else
75 | {
76 | new Log($" >> 文件 {new FileInfo(b).Name} 存在异常,重试中 ...", ConsoleColor.DarkRed);
77 | return StartDownload();
78 | }
79 | }
80 |
81 | new Log($" √ 已完成 Office v{OfficeNetInfo.OfficeLatestVersion} 下载。", ConsoleColor.DarkGreen);
82 |
83 | return 1;
84 | }
85 | catch (Exception Ex)
86 | {
87 | new Log(Ex.ToString());
88 | return 0;
89 | }
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/LKY_OfficeTools/Lib/Lib_OfficeProcess.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * [LKY Office Tools] Copyright (C) 2022 - 2024 LiuKaiyuan Inc.
3 | *
4 | * FileName : Lib_OfficeProcess.cs
5 | * Developer: OdysseusYuan@foxmail.com (Odysseus.Yuan)
6 | */
7 |
8 | using LKY_OfficeTools.Common;
9 | using System;
10 | using System.Collections.Generic;
11 | using System.IO;
12 | using System.Reflection;
13 | using static LKY_OfficeTools.Common.Com_ExeOS.KillExe;
14 | using static LKY_OfficeTools.Lib.Lib_AppInfo;
15 | using static LKY_OfficeTools.Lib.Lib_AppLog;
16 |
17 | namespace LKY_OfficeTools.Lib
18 | {
19 | internal class Lib_OfficeProcess
20 | {
21 | internal static List Process_List
22 | {
23 | get
24 | {
25 | try
26 | {
27 | Stream office_processes_res = Assembly.GetExecutingAssembly().
28 | GetManifestResourceStream(AppDevelop.NameSpace_Top /* 当命名空间发生改变时,此值也需要调整 */
29 | + ".Resource.Office_Processes.list");
30 | StreamReader office_processes_sr = new StreamReader(office_processes_res);
31 | string office_processes = office_processes_sr.ReadToEnd();
32 | if (!string.IsNullOrWhiteSpace(office_processes))
33 | {
34 | List office_processes_list = new List();
35 | string[] p_info = office_processes.Replace("\r", "").Split('\n'); //分割出进程数组
36 | if (p_info != null && p_info.Length > 0)
37 | {
38 | foreach (var now_process in p_info)
39 | {
40 | office_processes_list.Add(now_process);
41 | }
42 |
43 | return office_processes_list;
44 | }
45 | }
46 | return null;
47 | }
48 | catch (Exception Ex)
49 | {
50 | new Log(Ex.ToString());
51 | return null;
52 | }
53 | }
54 | }
55 |
56 | internal static List GetRuningProcess()
57 | {
58 | try
59 | {
60 | List runing_office_process = new List();
61 | foreach (var now_p in Process_List)
62 | {
63 | if (Com_ExeOS.Info.IsRun(now_p))
64 | {
65 | runing_office_process.Add(now_p);
66 | }
67 | }
68 |
69 | return runing_office_process;
70 | }
71 | catch (Exception Ex)
72 | {
73 | new Log(Ex.ToString());
74 | return null;
75 | }
76 | }
77 |
78 | internal class KillOffice
79 | {
80 | internal static bool All()
81 | {
82 | try
83 | {
84 | //轮询结束每个进程(等待其结束)
85 | foreach (var now_p in Process_List)
86 | {
87 | //new Log($" >> 等待 {now_p.ToLower()} 进程关闭中 ...", ConsoleColor.DarkYellow);
88 | Com_ExeOS.KillExe.ByExeName(now_p, KillMode.Try_Friendly, true);
89 | }
90 |
91 | return true;
92 | }
93 | catch (Exception Ex)
94 | {
95 | new Log(Ex.ToString());
96 | return false;
97 | }
98 | }
99 | }
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/LKY_OfficeTools/OfficeTools.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * [LKY Office Tools] Copyright (C) 2022 - 2024 LiuKaiyuan Inc.
3 | *
4 | * FileName : OfficeTools.cs
5 | * Developer: OdysseusYuan@foxmail.com (Odysseus.Yuan)
6 | */
7 |
8 | using LKY_OfficeTools.Common;
9 | using LKY_OfficeTools.Lib;
10 | using System;
11 | using System.Text;
12 | using static LKY_OfficeTools.Lib.Lib_AppClosing;
13 | using static LKY_OfficeTools.Lib.Lib_AppCommand;
14 | using static LKY_OfficeTools.Lib.Lib_AppInfo;
15 | using static LKY_OfficeTools.Lib.Lib_AppLog;
16 | using static LKY_OfficeTools.Lib.Lib_AppMessage;
17 | using static LKY_OfficeTools.Lib.Lib_AppState;
18 |
19 | namespace LKY_OfficeTools
20 | {
21 | internal class OfficeTools
22 | {
23 | static void Main(string[] args)
24 | {
25 | //命令行检测
26 | new Lib_AppCommand(args);
27 |
28 | //设定编码,解决英文系统乱码问题
29 | Console.OutputEncoding = Encoding.GetEncoding("gbk"); //必须在启动模式判断之后再进行本函数执行。否则服务模式将引发 1053 错误!
30 |
31 | //中断检测
32 | CloseWindow.SetConsoleCtrlHandler(CloseWindow.newDelegate, true);
33 |
34 | //启动
35 | Entry();
36 | }
37 |
38 | private static void Entry()
39 | {
40 | //欢迎话术
41 | Console.Title = $"{AppAttribute.AppName} v{AppAttribute.AppVersion}";
42 | new Log($"{AppAttribute.AppName} [版本 {AppAttribute.AppVersion}]\n" +
43 | $"版权所有(C)LiuKaiyuan (Odysseus.Yuan)。保留所有权利。\n\n" +
44 | $"探讨 {AppAttribute.AppName} 相关内容,可发送邮件至:OdysseusYuan@foxmail.com", ConsoleColor.Gray);
45 |
46 | //清理冗余信息
47 | Log.Clean();
48 |
49 | //数字签名证书检查
50 | new Lib_AppSignCert();
51 |
52 | //确认系统情况
53 | if (int.Parse(Com_SystemOS.OSVersion.GetBuildNumber()) < 15063)
54 | {
55 | //小于 Win10 1703 的操作系统,激活存在失败问题
56 | new Log($"\n × 请将当前操作系统升级至 Windows 10 (1703) 或其以上版本,否则 Office 无法进行正版激活!", ConsoleColor.DarkRed);
57 |
58 | //退出提示
59 | KeyMsg.Quit(-4);
60 |
61 | return;
62 | }
63 |
64 | //确认联网情况
65 | if (!Com_NetworkOS.Check.IsConnected)
66 | {
67 | new Log($"\n × 请确保当前电脑可正常访问互联网!", ConsoleColor.DarkRed);
68 |
69 | //退出提示
70 | KeyMsg.Quit(-5);
71 |
72 | return;
73 | }
74 |
75 | //根据命令行判断是否等待用户,没有标记时,执行倒计时等待
76 | if (!AppCommandFlag.HasFlag(ArgsFlag.None_Welcome_Confirm))
77 | {
78 | KeyMsg.DoByTime($"部署", 5);
79 | }
80 |
81 | //权限检查
82 | Com_PrivilegeOS.PrivilegeAttention();
83 |
84 | //SDK初始化
85 | Lib_AppSdk.Initial();
86 |
87 | //更新检查
88 | Lib_AppUpdate.Check();
89 |
90 | //继续
91 | new Lib_OfficeInstall();
92 |
93 | //部署成功时,提示是否配置为服务
94 | if (Current_StageType == ProcessStage.Finish_Success)
95 | {
96 | //被强制使用“我的文档”目录时,往往因为权限问题才使用,此时禁用服务配置
97 | if (!Must_Use_PersonalDir)
98 | {
99 | //配置服务
100 | Lib_AppServiceConfig.Setup();
101 | }
102 |
103 | //结论
104 | new Log($"\n √ 您已成功完成 {AppAttribute.AppName} 所有流程,感谢您的使用。", ConsoleColor.DarkGreen);
105 | }
106 | //部署失败,提示错误信息
107 | else if (Current_StageType == ProcessStage.Finish_Fail)
108 | {
109 | //结论
110 | new Log($"\n × 当前部署存在失败环节,您可在稍后重试运行!", ConsoleColor.DarkRed);
111 | }
112 |
113 | //退出提示
114 | KeyMsg.Quit(0);
115 |
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/LKY_OfficeTools/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * [LKY Office Tools] Copyright (C) 2022 - 2024 LiuKaiyuan Inc.
3 | *
4 | * FileName : AssemblyInfo.cs
5 | * Developer: OdysseusYuan@foxmail.com (Odysseus.Yuan)
6 | */
7 |
8 | using System.Reflection;
9 | using System.Runtime.InteropServices;
10 | using static LKY_OfficeTools.Lib.Lib_AppInfo;
11 |
12 | // 有关程序集的一般信息由以下
13 | // 控制。更改这些特性值可修改
14 | // 与程序集关联的信息。
15 | [assembly: AssemblyTitle(AppAttribute.AppName)]
16 | [assembly: AssemblyDescription("")]
17 | [assembly: AssemblyConfiguration("")]
18 | [assembly: AssemblyCompany(AppAttribute.Developer)]
19 | [assembly: AssemblyProduct(AppAttribute.AppName)]
20 | [assembly: AssemblyCopyright("Copyright (C) 2022 - 2024 LiuKaiyuan. All rights reserved.")]
21 | [assembly: AssemblyTrademark("")]
22 | [assembly: AssemblyCulture("")]
23 |
24 | // 将 ComVisible 设置为 false 会使此程序集中的类型
25 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
26 | //请将此类型的 ComVisible 特性设置为 true。
27 | [assembly: ComVisible(false)]
28 |
29 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
30 | [assembly: Guid("6d00f508-106a-42d1-be0f-048762434e69")]
31 |
32 | // 程序集的版本信息由下列四个值组成:
33 | //
34 | // 主版本
35 | // 次版本
36 | // 生成号
37 | // 修订号
38 | //
39 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
40 | //通过使用 "*",如下所示:
41 | // [assembly: AssemblyVersion("1.0.*")]
42 | [assembly: AssemblyVersion(AppAttribute.AppVersion)]
43 | [assembly: AssemblyFileVersion(AppAttribute.AppVersion)]
44 |
--------------------------------------------------------------------------------
/LKY_OfficeTools/Properties/app.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | Windows 10
41 |
42 |
43 |
44 |
50 |
58 |
59 |
73 |
--------------------------------------------------------------------------------
/LKY_OfficeTools/Resource/Json/OfficeChannels.txt:
--------------------------------------------------------------------------------
1 | [{"name":"CurrentPreview","displayName":"Current Channel (Preview)","alternateNames":["InsiderSlow","FirstReleaseCurrent","Insiders"],"baseUrl":"http://officecdn.microsoft.com/pr/64256afe-f5d9-4f86-8936-8840a6a4f5be","updates":[{"version":"2205","legacyVersion":"16.0.15225.20092","build":"15225.20092","pubTime":"2022-05-09T18:27:07.22Z"},{"version":"2204","legacyVersion":"16.0.15128.20206","build":"15128.20206","pubTime":"2022-05-04T16:25:00.447Z"}],"latestUpdateVersion":"16.0.15225.20092"},{"name":"SemiAnnualPreview","displayName":"Semi-Annual Enterprise Channel (Preview)","alternateNames":["FirstReleaseDeferred","Targeted"],"baseUrl":"http://officecdn.microsoft.com/pr/b8f9b850-328d-4355-9145-c59439a0c4cf","updates":[{"version":"2202","legacyVersion":"16.0.14931.20392","build":"14931.20392","pubTime":"2022-05-10T17:06:07.17Z"},{"version":"2202","legacyVersion":"16.0.14931.20274","build":"14931.20274","pubTime":"2022-04-12T08:40:50.223Z"}],"latestUpdateVersion":"16.0.14931.20392"},{"name":"SemiAnnual","displayName":"Semi-Annual Enterprise Channel","alternateNames":["Deferred","Broad"],"baseUrl":"http://officecdn.microsoft.com/pr/7ffbc6bf-bc32-4f92-8982-f9dd17fd3114","updates":[{"version":"2108","legacyVersion":"16.0.14326.20962","build":"14326.20962","pubTime":"2022-05-10T07:33:01.94Z"},{"version":"2108","legacyVersion":"16.0.14326.20910","build":"14326.20910","pubTime":"2022-04-12T07:24:22.143Z"},{"version":"2108","legacyVersion":"16.0.14326.20852","build":"14326.20852","pubTime":"2022-03-08T08:39:08.78Z"},{"version":"2108","legacyVersion":"16.0.14326.20784","build":"14326.20784","pubTime":"2022-02-08T08:23:35.403Z"},{"version":"2108","legacyVersion":"16.0.14326.20738","build":"14326.20738","pubTime":"2022-01-11T08:25:14.823Z"},{"version":"2102","legacyVersion":"16.0.13801.21334","build":"13801.21334","pubTime":"2022-05-10T07:43:05.187Z"},{"version":"2102","legacyVersion":"16.0.13801.21278","build":"13801.21278","pubTime":"2022-04-12T07:37:56.357Z"},{"version":"2102","legacyVersion":"16.0.13801.21214","build":"13801.21214","pubTime":"2022-03-08T18:46:47.31Z"},{"version":"2102","legacyVersion":"16.0.13801.21156","build":"13801.21156","pubTime":"2022-02-08T08:36:32.94Z"},{"version":"2102","legacyVersion":"16.0.13801.21106","build":"13801.21106","pubTime":"2022-01-11T08:38:46.807Z"},{"version":"2102","legacyVersion":"16.0.13801.21092","build":"13801.21092","pubTime":"2021-12-16T21:03:44.23Z"},{"version":"2102","legacyVersion":"16.0.13801.21050","build":"13801.21050","pubTime":"2021-11-09T08:31:32.263Z"},{"version":"2102","legacyVersion":"16.0.13801.21004","build":"13801.21004","pubTime":"2021-10-12T07:27:18.663Z"},{"version":"2102","legacyVersion":"16.0.13801.20960","build":"13801.20960","pubTime":"2021-09-14T07:35:07.46Z"},{"version":"2102","legacyVersion":"16.0.13801.20864","build":"13801.20864","pubTime":"2021-08-10T07:29:05.727Z"},{"version":"2102","legacyVersion":"16.0.13801.20808","build":"13801.20808","pubTime":"2021-07-13T07:25:30.66Z"}],"latestUpdateVersion":"16.0.14326.20962"},{"name":"Current","displayName":"Current Channel","alternateNames":["Current","Monthly"],"baseUrl":"http://officecdn.microsoft.com/pr/492350f6-3a01-4f97-b9c0-c7c6ddf67d60","updates":[{"version":"2204","legacyVersion":"16.0.15128.20224","build":"15128.20224","pubTime":"2022-05-10T07:37:41.747Z"},{"version":"2204","legacyVersion":"16.0.15128.20178","build":"15128.20178","pubTime":"2022-04-26T22:07:27.363Z"}],"latestUpdateVersion":"16.0.15128.20224"},{"name":"PerpetualVL2019","displayName":"Office 2019 Perpetual Enterprise","alternateNames":["Perpetual2019"],"baseUrl":"http://officecdn.microsoft.com/pr/f2e724c1-748f-4b47-8fb8-8e0d210e9208","updates":[{"version":"LTSB2018","legacyVersion":"16.0.10386.20017","build":"10386.20017","pubTime":"2022-05-10T13:17:03.267Z"},{"version":"LTSB2018","legacyVersion":"16.0.10385.20027","build":"10385.20027","pubTime":"2022-04-12T13:18:24.81Z"},{"version":"LTSB2018","legacyVersion":"16.0.10384.20023","build":"10384.20023","pubTime":"2022-03-08T14:17:24.187Z"},{"version":"LTSB2018","legacyVersion":"16.0.10383.20027","build":"10383.20027","pubTime":"2022-02-08T14:17:19.753Z"},{"version":"LTSB2018","legacyVersion":"16.0.10382.20034","build":"10382.20034","pubTime":"2022-01-11T20:08:33.663Z"},{"version":"LTSB2018","legacyVersion":"16.0.10382.20010","build":"10382.20010","pubTime":"2021-12-20T18:57:20.533Z"},{"version":"LTSB2018","legacyVersion":"16.0.10380.20037","build":"10380.20037","pubTime":"2021-11-09T14:17:03.803Z"},{"version":"LTSB2018","legacyVersion":"16.0.10379.20043","build":"10379.20043","pubTime":"2021-10-12T13:30:53.57Z"},{"version":"LTSB2018","legacyVersion":"16.0.10378.20029","build":"10378.20029","pubTime":"2021-09-14T08:14:18.733Z"},{"version":"LTSB2018","legacyVersion":"16.0.10377.20023","build":"10377.20023","pubTime":"2021-08-10T13:19:17.46Z"},{"version":"LTSB2018","legacyVersion":"16.0.10376.20033","build":"10376.20033","pubTime":"2021-07-13T12:48:19Z"},{"version":"LTSB2018","legacyVersion":"16.0.10375.20036","build":"10375.20036","pubTime":"2021-06-08T12:48:30.98Z"},{"version":"LTSB2018","legacyVersion":"16.0.10374.20040","build":"10374.20040","pubTime":"2021-05-11T12:55:45.37Z"},{"version":"LTSB2018","legacyVersion":"16.0.10373.20050","build":"10373.20050","pubTime":"2021-04-13T13:19:21.94Z"},{"version":"LTSB2018","legacyVersion":"16.0.10372.20060","build":"10372.20060","pubTime":"2021-03-09T14:35:43.8Z"},{"version":"LTSB2018","legacyVersion":"16.0.10371.20060","build":"10371.20060","pubTime":"2021-02-09T14:34:38.107Z"},{"version":"LTSB2018","legacyVersion":"16.0.10370.20052","build":"10370.20052","pubTime":"2021-01-12T14:35:21.603Z"},{"version":"LTSB2018","legacyVersion":"16.0.10369.20032","build":"10369.20032","pubTime":"2020-12-08T15:34:15.573Z"},{"version":"LTSB2018","legacyVersion":"16.0.10368.20035","build":"10368.20035","pubTime":"2020-11-10T19:44:32.977Z"},{"version":"LTSB2018","legacyVersion":"16.0.10367.20048","build":"10367.20048","pubTime":"2020-10-13T16:05:46.547Z"},{"version":"LTSB2018","legacyVersion":"16.0.10366.20016","build":"10366.20016","pubTime":"2020-09-08T14:35:02.527Z"},{"version":"LTSB2018","legacyVersion":"16.0.10364.20059","build":"10364.20059","pubTime":"2020-08-11T14:34:44.503Z"},{"version":"LTSB2018","legacyVersion":"16.0.10363.20015","build":"10363.20015","pubTime":"2020-07-14T16:41:01.31Z"},{"version":"LTSB2018","legacyVersion":"16.0.10361.20002","build":"10361.20002","pubTime":"2020-06-09T16:08:24.84Z"},{"version":"LTSB2018","legacyVersion":"16.0.10359.20023","build":"10359.20023","pubTime":"2020-05-12T14:41:12.863Z"}],"latestUpdateVersion":"16.0.10386.20017"},{"name":"PerpetualVL2021","displayName":"Office 2021 Perpetual Enterprise","alternateNames":["Perpetual2021"],"baseUrl":"http://officecdn.microsoft.com/pr/5030841d-c919-4594-8d2d-84ae4f96e58e","updates":[{"version":"LTSB2021","legacyVersion":"16.0.14332.20303","build":"14332.20303","pubTime":"2022-05-10T13:22:45.863Z"},{"version":"LTSB2021","legacyVersion":"16.0.14332.20281","build":"14332.20281","pubTime":"2022-04-12T14:06:33.337Z"},{"version":"LTSB2021","legacyVersion":"16.0.14332.20255","build":"14332.20255","pubTime":"2022-03-08T14:13:36.797Z"},{"version":"LTSB2021","legacyVersion":"16.0.14332.20238","build":"14332.20238","pubTime":"2022-02-08T14:13:02.427Z"},{"version":"LTSB2021","legacyVersion":"16.0.14332.20216","build":"14332.20216","pubTime":"2022-01-11T19:16:03.15Z"},{"version":"LTSB2021","legacyVersion":"16.0.14332.20176","build":"14332.20176","pubTime":"2021-11-09T14:13:41.687Z"},{"version":"LTSB2021","legacyVersion":"16.0.14332.20145","build":"14332.20145","pubTime":"2021-10-12T15:19:08.937Z"},{"version":"LTSB2021","legacyVersion":"16.0.14332.20110","build":"14332.20110","pubTime":"2021-09-15T19:51:58.963Z"},{"version":"LTSB2021","legacyVersion":"16.0.14332.20099","build":"14332.20099","pubTime":"2021-09-07T17:28:23.277Z"},{"version":"LTSB2021","legacyVersion":"16.0.14332.20077","build":"14332.20077","pubTime":"2021-08-30T23:12:05.21Z"},{"version":"LTSB2021","legacyVersion":"16.0.14332.20058","build":"14332.20058","pubTime":"2021-08-23T19:56:34.247Z"},{"version":"LTSB2021","legacyVersion":"16.0.14332.20033","build":"14332.20033","pubTime":"2021-08-16T18:30:31.74Z"},{"version":"LTSB2021","legacyVersion":"16.0.14332.20011","build":"14332.20011","pubTime":"2021-08-10T23:12:09.037Z"},{"version":"LTSB2021","legacyVersion":"16.0.14332.20003","build":"14332.20003","pubTime":"2021-08-04T17:27:53.7Z"}],"latestUpdateVersion":"16.0.14332.20303"},{"name":"MonthlyEnterprise","displayName":"Monthly Enterprise Channel","alternateNames":["MonthlyEnterprise"],"baseUrl":"http://officecdn.microsoft.com/pr/55336b82-a18d-4dd6-b5f6-9e5095c314a6","updates":[{"version":"2203","legacyVersion":"16.0.15028.20248","build":"15028.20248","pubTime":"2022-05-10T07:26:01.423Z"},{"version":"2202","legacyVersion":"16.0.14931.20392","build":"14931.20392","pubTime":"2022-05-10T17:12:35.443Z"}],"latestUpdateVersion":"16.0.15028.20248"}]
--------------------------------------------------------------------------------
/LKY_OfficeTools/Resource/Office_Processes.list:
--------------------------------------------------------------------------------
1 | EXCEL
2 | GROOVE
3 | INFOPATH
4 | lync
5 | MSACCESS
6 | msoev
7 | msotd
8 | MSOUC
9 | MSPUB
10 | MSQRY32
11 | MSTORE
12 | OcPubMgr
13 | OIS
14 | OLCFG
15 | ONENOTE
16 | ORGCHART
17 | OUTLOOK
18 | POWERPNT
19 | SCANPST
20 | SETLANG
21 | Teams
22 | WINWORD
--------------------------------------------------------------------------------
/LKY_OfficeTools/Resource/PublisherCert.cer:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OdysseusYuan/LKY_OfficeTools/6f9a1bd471918f3310e6be4a6d7f42d0d6e467cf/LKY_OfficeTools/Resource/PublisherCert.cer
--------------------------------------------------------------------------------
/LKY_OfficeTools/Resource/SDK/Activate.lotp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OdysseusYuan/LKY_OfficeTools/6f9a1bd471918f3310e6be4a6d7f42d0d6e467cf/LKY_OfficeTools/Resource/SDK/Activate.lotp
--------------------------------------------------------------------------------
/LKY_OfficeTools/Resource/SDK/Aria2c.lotp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OdysseusYuan/LKY_OfficeTools/6f9a1bd471918f3310e6be4a6d7f42d0d6e467cf/LKY_OfficeTools/Resource/SDK/Aria2c.lotp
--------------------------------------------------------------------------------
/LKY_OfficeTools/Resource/SDK/ODT.lotp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OdysseusYuan/LKY_OfficeTools/6f9a1bd471918f3310e6be4a6d7f42d0d6e467cf/LKY_OfficeTools/Resource/SDK/ODT.lotp
--------------------------------------------------------------------------------
/LKY_OfficeTools/Resource/SDK/SDK_Processes.list:
--------------------------------------------------------------------------------
1 | OSPPREARM
2 | lot_aria2c
3 | ODT
4 | cleanospp_64
5 | cleanospp_86
6 | SaRACmd
7 | OfficeClickToRun
8 | OfficeC2RClient
--------------------------------------------------------------------------------
/LKY_OfficeTools/Resource/SDK/SaRA.lotp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OdysseusYuan/LKY_OfficeTools/6f9a1bd471918f3310e6be4a6d7f42d0d6e467cf/LKY_OfficeTools/Resource/SDK/SaRA.lotp
--------------------------------------------------------------------------------
/LKY_OfficeTools/logo.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OdysseusYuan/LKY_OfficeTools/6f9a1bd471918f3310e6be4a6d7f42d0d6e467cf/LKY_OfficeTools/logo.ico
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #
2 |
3 | ## LKY Office Tools
4 | > 一键自动化 下载、安装、激活 Office 的利器。绿色、开源、安全、无毒。
5 |
6 | 目前包含的功能:
7 | - 一键快速下载、安装、激活最新版 Microsoft Office 软件。
8 | - 用户可在安装 Word、PPT、Excel 的同时,根据软件提示,自助安装其它组件,包括:
9 | Outlook、OneNote、Access、Visio、Project、Publisher、Teams、OneDrive、Lync/Skype。
10 | - 工具可自动识别不同的操作系统架构,自动下载适配版本的 Office。
11 | - 本工具激活 Office 的方式为正版激活模式,不会篡改任何系统文件。
12 | - 当系统中存在多个冗余 Office 版本时,本工具在用户同意的情况下,可实现自动升级。
13 |
14 | ## 使用方法
15 | - 下载形如:LKY_OfficeTools_v*.zip 的压缩包,最新版地址:https://github.com/OdysseusYuan/LKY_OfficeTools/releases/latest
16 | - 解压下载好的 zip 压缩包,运行解压后目录下的 LKY_OfficeTools.exe 文件即可完成部署。
17 |
18 | ## 运行环境
19 | - 为保证安装、激活可以最大限度成功,请您尽可能在新装系统后(或从未安装过 Microsoft Office 软件的系统中)运行本工具。
20 | - 目前已经在 Windows 10(1703) 及以上版本进行了测试,均可在其 x86、x64 完美安装正版 Office 并激活。
21 | - 应 Office 官方要求,系统中只能部署唯一架构类型,故本工具部署时,会征求用户同意,由其自行决定是否卸载其它架构。
22 | - 2016年7月及其之前发布的 Windows 系统(即:Windows 10(1703) 之前的系统),因其架构过于陈旧,其已经不再支持安装最新的正版 Office。
23 |
24 | ## 开源说明
25 | - 欢迎广大开发者、爱好者们 Fork、PR 本仓库。参考、引用、转发、二次开发本开源库时,请注明来源。
26 | - 本工具自动激活功能,仅用于给大家无偿的学习编程开发能力之用,如需商业办公使用,请从微软官网购买商业许可。
27 | - 任何自然人、企业、机构等,不得使用任何直接或间接的方式将其商业化,违犯成员需要为此承担全部法律责任。
28 | - 当前工具将持续进行迭代更新和维护,迭代过程中不排除在各种因素综合下,可能产生计算机运行的各种情况。
29 |
30 | ## 版权保护
31 | - 软件已获多项著作权(含修改保护):软著登字第10549507号、软著登字第10895737号、软著登字第10850084号、软著登字第11497426号、软著登字第11573194号等。
32 |
33 | ## 关于
34 | - 如有建议、疑惑等,大家可以发邮件至 [OdysseusYuan@foxmail.com](mailto:OdysseusYuan@foxmail.com) 交流探讨。
35 | - © 2022 - 2024 LiuKaiyuan (Odysseus.Yuan). All Rights Reserved.
36 |
--------------------------------------------------------------------------------