Repository navigation
Expand file tree
/
Copy pathExcelExporterService.cs
More file actions
143 lines (121 loc) · 5.12 KB
/
Copy pathExcelExporterService.cs
File metadata and controls
143 lines (121 loc) · 5.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
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
96
97
98
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
133
134
135
136
137
138
139
140
141
142
143
// VbaExporterService.cs
using System;
using System.IO;
using System.IO.Compression;
using Excel = Microsoft.Office.Interop.Excel;
using VBIDE = Microsoft.Vbe.Interop;
namespace ExcelExporter.Services
{
public class ExportOptions
{
public bool ExportModules { get; set; } = true;
public bool ExportClasses { get; set; } = true;
public bool ExportForms { get; set; } = true;
public bool CreateZipArchive { get; set; } = false;
}
public class ExcelExporterService
{
/// <summary>
/// Exports VBA components from an Excel workbook based on options.
/// Returns the path to the output directory (or ZIP file if requested).
/// </summary>
public string ExportVbaFromExcel(string excelFilePath, ExportOptions options)
{
if (string.IsNullOrWhiteSpace(excelFilePath))
throw new ArgumentException("Excel file path is required.", nameof(excelFilePath));
if (!File.Exists(excelFilePath))
throw new FileNotFoundException("Excel file not found.", excelFilePath);
if (!options.ExportModules && !options.ExportClasses && !options.ExportForms)
throw new InvalidOperationException("At least one export type must be selected.");
Excel.Application excelApp = null;
Excel.Workbook workbook = null;
try
{
excelApp = new Excel.Application
{
Visible = false,
DisplayAlerts = false,
AutomationSecurity = Microsoft.Office.Core.MsoAutomationSecurity.msoAutomationSecurityLow
};
workbook = excelApp.Workbooks.Open(excelFilePath);
// Verify VBA project access
try
{
_ = workbook.VBProject;
}
catch (Exception ex)
{
throw new InvalidOperationException(
"Cannot access VBA project. Enable 'Trust access to the VBA project object model' in Excel Trust Center.", ex);
}
string outputDir = GetOutputDirectory(workbook);
Directory.CreateDirectory(outputDir);
ExportComponents(workbook, outputDir, options);
if (options.CreateZipArchive)
{
string zipPath = Path.Combine(workbook.Path,
Path.GetFileNameWithoutExtension(workbook.Name) + " Modules.zip");
if (File.Exists(zipPath))
File.Delete(zipPath);
ZipFile.CreateFromDirectory(outputDir, zipPath);
return zipPath;
}
return outputDir;
}
finally
{
// Proper COM cleanup
if (workbook != null)
{
workbook.Close(SaveChanges: false);
System.Runtime.InteropServices.Marshal.ReleaseComObject(workbook);
}
if (excelApp != null)
{
excelApp.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(excelApp);
}
// Force GC to help release COM objects
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
private void ExportComponents(Excel.Workbook workbook, string destDir, ExportOptions options)
{
foreach (VBIDE.VBComponent comp in workbook.VBProject.VBComponents)
{
if (comp.CodeModule.CountOfLines <= 0) continue;
string extension = null;
bool shouldExport = false;
switch (comp.Type)
{
case VBIDE.vbext_ComponentType.vbext_ct_StdModule:
shouldExport = options.ExportModules;
extension = ".bas";
break;
case VBIDE.vbext_ComponentType.vbext_ct_ClassModule:
case VBIDE.vbext_ComponentType.vbext_ct_Document:
shouldExport = options.ExportClasses;
extension = ".cls";
break;
case VBIDE.vbext_ComponentType.vbext_ct_MSForm:
shouldExport = options.ExportForms;
extension = ".frm";
break;
default:
continue;
}
if (!shouldExport) continue;
string filePath = Path.Combine(destDir, comp.Name + extension);
if (File.Exists(filePath)) File.Delete(filePath);
comp.Export(filePath);
// ✅ .frx is auto-exported by Excel if it exists
}
}
private string GetOutputDirectory(Excel.Workbook workbook)
{
string name = Path.GetFileNameWithoutExtension(workbook.Name);
return Path.Combine(workbook.Path, $"{name} Modules");
}
}
}