private static void PatchTest() { var targetPath = @"..\..\..\Patchwork.Tests.Target\bin\debug\Patchwork.Tests.Target.dll";; var dir = Path.GetDirectoryName(targetPath); var fn = Path.GetFileNameWithoutExtension(targetPath); var ext = Path.GetExtension(targetPath); var newFileName = string.Format("{0}.patched{1}", fn, ext); var newTarget = Path.Combine(dir, newFileName); File.Copy(targetPath, newTarget, true); var patcher = new AssemblyPatcher(newTarget, log: Log); var patchPath = typeof(Patchwork.Tests.Patch.TestClass).Assembly.Location; var maker = new ManifestCreator(); var manifest = maker.CreateManifest(patchPath); patcher.PatchManifest(manifest, null); patcher.WriteTo(newTarget); Log.Information("Loading assembly into memory..."); var loaded = Assembly.LoadFrom(newTarget); Log.Information("Invoking method"); var module = loaded.GetModules()[0]; var types = module.FindTypes((typ, o) => typ.Name.Contains("EntryPoint"), null); var foundType = types.Single(); var method = foundType.GetMethod("StandardTests"); try { var ret = method.Invoke(null, null); Log.Information("Result: {@Result}", ret); } catch (TargetInvocationException ex) { throw ex.InnerException; } Console.ReadKey(); }
/// <exception cref="T:PatchworkLauncher.PatchingProcessException">Cannot patch manifest during the patching process</exception> public static void TryPatchManifest(this AssemblyPatcher patcher, PatchInstruction patch, PatchGroup patchGroup, ProgressObject patchProgress) { try { patcher.PatchManifest(patch.Patch, patchProgress.ToMonitor()); } catch (PatchException patchException) { throw new PatchingProcessException(patchException) { AssociatedInstruction = patch, AssociatedPatchGroup = patchGroup, Step = PatchProcessingStep.ApplyingSpecificPatch }; } }
private void ApplyInstructions(IEnumerable <PatchGroup> patchGroups, ProgressObject po) { //TODO: Use a different progress tracking system and make the entire patching operation more recoverable and fault-tolerant. //TODO: Refactor this method. patchGroups = patchGroups.ToList(); var appInfo = AppInfo; var logger = Logger; var fileProgress = new ProgressObject(); po.Child.Value = fileProgress; var patchProgress = new ProgressObject(); fileProgress.Child.Value = patchProgress; var myAttributesAssembly = typeof(AppInfo).Assembly; var attributesAssemblyName = Path.GetFileName(myAttributesAssembly.Location); var history = new List <XmlFileHistory>(); po.TaskTitle.Value = "Patching Game"; po.TaskText.Value = appInfo.AppName; po.Total.Value = patchGroups.Count(); foreach (var patchGroup in patchGroups) { var patchCount = patchGroup.Instructions.Count; po.TaskTitle.Value = $"Patching {appInfo.AppName}"; var targetFile = patchGroup.TargetPath; po.TaskText.Value = Path.GetFileName(targetFile); //Note that Path.Combine(FILENAME, "..", OTHER_FILENAME) doesn't work on Mono but does work on .NET. var dir = Path.GetDirectoryName(targetFile); var localAssemblyName = Path.Combine(dir, attributesAssemblyName); var copy = true; fileProgress.TaskTitle.Value = "Patching File"; fileProgress.Total.Value = 2 + patchCount; fileProgress.Current.Value++; var backupModified = PatchingHelper.GetBackupForModified(targetFile); var backupOrig = PatchingHelper.GetBackupForOriginal(targetFile); fileProgress.TaskText.Value = "Applying Patch"; if (!PatchingHelper.DoesFileMatchPatchList(backupModified, targetFile, patchGroup.Instructions) || Preferences.AlwaysPatch) { if (File.Exists(localAssemblyName)) { try { var localAssembly = AssemblyCache.Default.ReadAssembly(localAssemblyName); if (localAssembly.GetAssemblyMetadataString() == myAttributesAssembly.GetAssemblyMetadataString()) { copy = false; } } catch (Exception ex) { Logger.Warning(ex, $"Failed to read local attributes assembly so it will be overwritten."); //if reading the assembly failed for any reason, just ignore... } } if (copy) { File.Copy(myAttributesAssembly.Location, localAssemblyName, true); } var patcher = new AssemblyPatcher(targetFile, logger) { EmbedHistory = true }; foreach (var patch in patchGroup.Instructions) { try { patcher.PatchManifest(patch.Patch, patchProgress.ToMonitor()); } catch (PatchException ex) { throw new PatchingProcessException(ex) { AssociatedInstruction = patch, AssociatedPatchGroup = patchGroup, Step = PatchProcessingStep.ApplyingSpecificPatch }; } fileProgress.Current.Value++; } patchProgress.TaskText.Value = ""; patchProgress.TaskTitle.Value = ""; fileProgress.Current.Value++; fileProgress.TaskText.Value = "Writing Assembly"; if (Environment.OSVersion.Platform == PlatformID.Win32NT) { fileProgress.TaskText.Value = "Running PEVerify..."; var targetFolder = Path.GetDirectoryName(targetFile); try { var peOutput = patcher.RunPeVerify(new PEVerifyInput { AssemblyResolutionFolder = targetFolder, IgnoreErrors = AppInfo.IgnorePEVerifyErrors.ToList() }); logger.Information(peOutput.Output); } catch (Exception ex) { logger.Error(ex, "Failed to run PEVerify on the assembly."); } } try { patcher.WriteTo(backupModified); } catch (Exception ex) { throw new PatchingProcessException(ex) { AssociatedInstruction = null, AssociatedPatchGroup = patchGroup, Step = PatchProcessingStep.WritingToFile }; } } else { fileProgress.Current.Value += patchCount; } try { PatchingHelper.SwitchFilesSafely(backupModified, targetFile, backupOrig); } catch (Exception ex) { throw new PatchingProcessException(ex) { AssociatedInstruction = null, AssociatedPatchGroup = patchGroup, Step = PatchProcessingStep.PerformingSwitch }; } AssemblyCache.Default.ClearCache(); po.Current.Value++; } }
private void ApplyInstructions(IEnumerable<PatchGroup> patchGroups, ProgressObject po) { //TODO: Use a different progress tracking system and make the entire patching operation more recoverable and fault-tolerant. //TODO: Refactor this method. patchGroups = patchGroups.ToList(); var appInfo = AppInfo; var logger = Logger; var fileProgress = new ProgressObject(); po.Child.Value = fileProgress; var patchProgress = new ProgressObject(); fileProgress.Child.Value = patchProgress; var myAttributesAssembly = typeof (AppInfo).Assembly; var attributesAssemblyName = Path.GetFileName(myAttributesAssembly.Location); var history = new List<XmlFileHistory>(); po.TaskTitle.Value = "Patching Game"; po.TaskText.Value = appInfo.AppName; po.Total.Value = patchGroups.Count(); foreach (var patchGroup in patchGroups) { var patchCount = patchGroup.Instructions.Count; po.TaskTitle.Value = $"Patching {appInfo.AppName}"; var targetFile = patchGroup.TargetPath; po.TaskText.Value = Path.GetFileName(targetFile); //Note that Path.Combine(FILENAME, "..", OTHER_FILENAME) doesn't work on Mono but does work on .NET. var dir = Path.GetDirectoryName(targetFile); var localAssemblyName = Path.Combine(dir, attributesAssemblyName); var copy = true; fileProgress.TaskTitle.Value = "Patching File"; fileProgress.Total.Value = 2 + patchCount; fileProgress.Current.Value++; var backupModified = PatchingHelper.GetBackupForModified(targetFile); var backupOrig = PatchingHelper.GetBackupForOriginal(targetFile); fileProgress.TaskText.Value = "Applying Patch"; if (!PatchingHelper.DoesFileMatchPatchList(backupModified, targetFile, patchGroup.Instructions) || Preferences.AlwaysPatch) { if (File.Exists(localAssemblyName)) { try { var localAssembly = AssemblyCache.Default.ReadAssembly(localAssemblyName); if (localAssembly.GetAssemblyMetadataString() == myAttributesAssembly.GetAssemblyMetadataString()) { copy = false; } } catch (Exception ex) { Logger.Warning(ex, $"Failed to read local attributes assembly so it will be overwritten."); //if reading the assembly failed for any reason, just ignore... } } if (copy) { File.Copy(myAttributesAssembly.Location, localAssemblyName, true); } var patcher = new AssemblyPatcher(targetFile, logger) { EmbedHistory = true }; foreach (var patch in patchGroup.Instructions) { try { patcher.PatchManifest(patch.Patch, patchProgress.ToMonitor()); } catch (PatchException ex) { throw new PatchingProcessException(ex) { AssociatedInstruction = patch, AssociatedPatchGroup = patchGroup, Step = PatchProcessingStep.ApplyingSpecificPatch }; } fileProgress.Current.Value++; } patchProgress.TaskText.Value = ""; patchProgress.TaskTitle.Value = ""; fileProgress.Current.Value++; fileProgress.TaskText.Value = "Writing Assembly"; if (Environment.OSVersion.Platform == PlatformID.Win32NT) { fileProgress.TaskText.Value = "Running PEVerify..."; var targetFolder = Path.GetDirectoryName(targetFile); try { var peOutput = patcher.RunPeVerify(new PEVerifyInput { AssemblyResolutionFolder = targetFolder, IgnoreErrors = AppInfo.IgnorePEVerifyErrors.ToList() }); logger.Information(peOutput.Output); } catch (Exception ex) { logger.Error(ex, "Failed to run PEVerify on the assembly."); } } try { patcher.WriteTo(backupModified); } catch (Exception ex) { throw new PatchingProcessException(ex) { AssociatedInstruction = null, AssociatedPatchGroup = patchGroup, Step = PatchProcessingStep.WritingToFile }; } } else { fileProgress.Current.Value += patchCount; } try { PatchingHelper.SwitchFilesSafely(backupModified, targetFile, backupOrig); } catch (Exception ex) { throw new PatchingProcessException(ex) { AssociatedInstruction = null, AssociatedPatchGroup = patchGroup, Step = PatchProcessingStep.PerformingSwitch }; } AssemblyCache.Default.ClearCache(); po.Current.Value++; } }