/// <summary> /// Removes the dependency of the referenced file from the <paramref name="targetProject"/>. /// </summary> /// <param name="targetProject"><see cref="ExcelVbaProject"/> to remove reference from.</param> /// <param name="reference"><see cref="ExcelVbaReference"/> to remove.</param> /// <returns></returns> public bool TryRemoveReference(ref ExcelVbaProject targetProject, ExcelVbaReference reference) { try { _logger.Log($"Removing reference \"{reference.Name}\" from \"{targetProject.Name}\""); targetProject.References.Remove(reference); return(true); } catch (Exception ex) { throw; } }
/// <summary> /// Create an empty VBA project. /// </summary> public void CreateVBAProject() { #if !MONO && !CORECLR if (_vba != null || _package.Package.PartExists(new Uri(ExcelVbaProject.PartUri, UriKind.Relative))) { throw (new InvalidOperationException("VBA project already exists.")); } _vba = new ExcelVbaProject(this); _vba.Create(); #else throw new NotSupportedException("Creating a VBA project is not supported under Mono."); #endif }
public void Dispose() { _sharedStrings.Clear(); _sharedStringsList.Clear(); _sharedStrings = null; _sharedStringsList = null; _vba = null; _worksheets.Dispose(); _package = null; _worksheets = null; _properties = null; _formulaParser = null; }
/// <summary> /// Attempts to add the <paramref name="modules"/> to the <paramref name="targetProject"/>. This overwrites the <paramref name="targetProject"/>'s internal <see cref="ExcelVbaProject.Modules"/> collection, as it doesn't support a "Merge" operation. /// </summary> /// <param name="targetProject"><see cref="ExcelVbaProject"/> to "merge" <paramref name="modules"/> into.</param> /// <param name="modules">Collection of <see cref="ExcelVBAModule"/>s to merge into <paramref name="targetProject"/></param> /// <returns></returns> public bool TryAddToProject(ref ExcelVbaProject targetProject, IEnumerable <ExcelVBAModule> modules) { // Could create instance of _list and actually add to the collection, rather than replacing it entirely. // This would require a rewrite of TryMergeModules as it currently collects the targetProject's modules as well. try { // Let's get reflecting! Set the internal collection of modules on the target. targetProject.Modules.GetType().GetField("_list", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(targetProject.Modules, modules.ToList()); _logger.Log($"Added the following to target \"{targetProject.Name}\":\n\t{String.Join("\n\t", modules.Select(x => x.Name))}"); return(true); } catch (Exception ex) { throw; } }
/// <summary> /// Merges required non-Excel file references that are referenced by referenced files. /// </summary> /// <param name="project"></param> /// <param name="references"></param> /// <remarks>For example, if a reference needs Microsoft Scripting Runtime 5.3, we want the resulting bundled project to have it as well.</remarks> /// <returns></returns> public bool TryMergeSystemReferences(ref ExcelVbaProject project, IEnumerable <ExcelVbaReference> references) { foreach (var reference in references) { // Should not be adding Excel files if (reference.ReferenceRecordID == 14) { continue; } // No need to add the same reference. if (project.References.Any(x => x.Libid.Equals(reference.Libid, StringComparison.CurrentCultureIgnoreCase) && x.Name.Equals(reference.Name, StringComparison.CurrentCultureIgnoreCase))) { continue; } project.References.Add(reference); } return(true); }
/// <summary> /// Returns two distinct sets of references from the <see cref="ExcelVbaProject"/> <paramref name="project"/>, system references and Excel file references. /// </summary> /// <param name="project"><see cref="ExcelVbaProject"/> to extract references from.</param> /// <returns></returns> public (IEnumerable <ExcelVbaReference> System, IEnumerable <ExcelVbaReference> Excel) GetReferences(ExcelVbaProject project) { var systemReferences = project.References.Where(x => x.ReferenceRecordID != 14).ToList(); var excelReferences = project.References.Where(x => x.ReferenceRecordID == 14).ToList(); if (excelReferences.Count > 0) { _logger.Log($"Found References:\n\t{String.Join("\n\t", excelReferences.Select(x => x.Name))}"); } else { _logger.Log($"No references found for {project.Name}"); } return(systemReferences, excelReferences); }
/// <summary> /// Gathers all modules and class modules from the <paramref name="sourceProject"/> and <paramref name="targetProject"/> and merges them together. /// </summary> /// <param name="sourceProject">Project containing modules to be merged into <paramref name="targetProject"/>.</param> /// <param name="targetProject">Project containing existing modules.</param> /// <param name="modules">Combined modules.</param> /// <remarks>This will replace early binding references with <paramref name="sourceProject"/> module name if found, and will prompt if a module with the same name but different code exists.</remarks> /// <returns>True if merge was successful.</returns> public bool TryMergeModules(ExcelVbaProject sourceProject, ExcelVbaProject targetProject, out IEnumerable <ExcelVBAModule> modules) { try { //// Get all modules, classes, and user forms from each project var sourceItems = sourceProject.Modules.Where(x => x.Type == eModuleType.Module || x.Type == eModuleType.Class).ToList(); var targetItems = targetProject.Modules.Where(x => x.Type == eModuleType.Module || x.Type == eModuleType.Class || x.Type == eModuleType.Designer).ToList(); var removeFromSource = new List <ExcelVBAModule>(); var removeFromTarget = new List <ExcelVBAModule>(); if (_onlyMergeUsed) { foreach (var source in sourceItems) { if (!targetItems.Any(x => x.Code.Contains(source.Name)) && !sourceItems.Any(x => x.Code.Contains(source.Name))) { removeFromSource.Add(source); } } } foreach (var targetItem in targetItems) { // Remove early binding reference since code will be local. if (targetItem.Code.Contains($"{sourceProject.Name}.")) { targetItem.Code = targetItem.Code.Replace($"{sourceProject.Name}.", ""); } if (targetItem.Code.Contains($"{targetProject.Name}.")) { targetItem.Code = targetItem.Code.Replace($"{targetProject.Name}.", ""); } // If name and code are the same, remove it from the source so it doesn't duplicate on merge. if (sourceItems.Any(x => x.Name == targetItem.Name && x.Code == targetItem.Code)) { removeFromSource.Add(sourceItems.Single(x => x.Name == targetItem.Name)); } // If a module of the same name exists in both projects, but the code differs, use default or prompt user for action. if (sourceItems.Any(x => x.Name == targetItem.Name && x.Code != targetItem.Code)) { try { var consolePresent = Console.WindowHeight > 0; } catch { throw new ArgumentException($"The source \"{sourceProject.Name}\" and target \"{targetProject.Name}\" have a {targetItem.Type} with the same name \"{targetItem.Name}\" and different code. Please remove from one or the other and run again."); } ConsoleColor backColor = Console.BackgroundColor, foreColor = Console.ForegroundColor; Console.BackgroundColor = ConsoleColor.Yellow; Console.ForegroundColor = ConsoleColor.Black; if (!_alwaysUseSource) { Console.WriteLine($"The source \"{sourceProject.Name}\" and target \"{targetProject.Name}\" have a {targetItem.Type} with the same name \"{targetItem.Name}\" and different code. Please advise: 0 to use source, 1 to keep target."); } if (_alwaysUseSource || Console.ReadLine().ToString() == "0") { removeFromTarget.Add(targetItem); } else { removeFromSource.Add(sourceItems.Single(x => x.Name == targetItem.Name)); } Console.BackgroundColor = backColor; Console.ForegroundColor = foreColor; } } foreach (var item in removeFromTarget) { targetItems.Remove(item); } foreach (var item in removeFromSource) { sourceItems.Remove(item); } //// Change the name of the source objects to contain the source's VBAProject name //foreach (var item in sourceItems) //{ // var name = $"{sourceProject.Name}_{item.Name}"; // item.Name = name; //} _logger.Log($"Merging source:\n\t{String.Join("\n\t", sourceItems.Select(x => x.Name))}\nWith Target:\n\t{String.Join("\n\t", targetItems.Select(x => x.Name))}"); // Put them together modules = targetItems.Concat(sourceItems); _logger.Log($"Merge complete:\n\t{String.Join("\n\t", modules.Select(x => x.Name))}"); return(true); } catch (Exception ex) { throw; } }