├── .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 | --------------------------------------------------------------------------------