Программное выполнение Excel Macro на удаленной машине с веб-сайта
У меня есть веб-сайт, где пользователи генерируют отчет Excel с использованием макроса, когда я пытаюсь запустить его на своем локальном компьютере, он отлично генерирует и запускает макрос в Excel. Когда я публикую его на сервере и в то же время буду зайти на него (открытый сеанс RDP) и попытаюсь запустить его из браузера за пределами этого сервера, он также будет работать, как и ожидалось. Проблема возникает, когда я вышел из системы на сервере (RDP), а затем запустил его в браузере за пределами сервера (т.е. с моей машины), макрос не запускается, но создает мой Excel.
Это код, который я использую
public class Report
{
protected Workbook Workbook { get; set; }
protected Application Excel { get; set; }
public void RunReport()
{
// Launch Excel on the server
Excel = new Application
{
DisplayAlerts = false,
ScreenUpdating = false,
Visible = false
};
// Load the workbook template
Workbook = Excel.Workbooks.Open(@"D:\Book1.xlt");
// Execute macros that generates the report, if any
ExecuteMacros();
Workbook.SaveAs(@"D:\Ray'sTesting.xls", XlFileFormat.xlExcel8);
QuitExcel();
}
private void QuitExcel()
{
if (Workbook != null)
{
Workbook.Close(false);
Marshal.ReleaseComObject(Workbook);
}
if (Excel != null)
{
Excel.Quit();
Marshal.ReleaseComObject(Excel);
}
}
private void ExecuteMacros()
{
const string legacyModuleName = "Module1";
const string legacyMacroName = "myMacro";
bool legacyMacroExists = false;
try
{
var legacyMacroModule = Workbook.VBProject.VBComponents.Item(legacyModuleName);
if (legacyMacroModule != null)
{
int legacyMacroStartLine = legacyMacroModule.CodeModule.ProcStartLine[legacyMacroName, Microsoft.Vbe.Interop.vbext_ProcKind.vbext_pk_Proc];
legacyMacroExists = legacyMacroStartLine > 0;
}
}
catch (Exception)
{
legacyMacroExists = false;
}
if (!legacyMacroExists)
{
return;
}
// VBA code for the dynamic macro that calls the CI2 legacy macro
var moduleCode = new StringBuilder();
moduleCode.AppendLine("Public Sub LaunchLegacyMacro()");
moduleCode.AppendLine(string.Format("{0}.{1}", legacyModuleName, legacyMacroName));
moduleCode.AppendLine("End Sub");
// Add the dynamic macro to the ThisWorkbook module
var workbookMainModule = Workbook.VBProject.VBComponents.Item("ThisWorkbook");
workbookMainModule.CodeModule.AddFromString(moduleCode.ToString());
// Execute the dynamic macro
Microsoft.VisualBasic.Interaction.CallByName(Workbook, "LaunchLegacyMacro", Microsoft.VisualBasic.CallType.Method, new object[] { });
}
}
1 ответ
Я получил эту работу, редактируя реестр каждый раз, когда мы запускаем макрос Excel
private static void ModifyExcelSecuritySettings()
{
// Make sure we have programmatic access to the project to run macros
using (var key = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Office\14.0\Excel\Security", true))
{
if (key != null)
{
if ((int)key.GetValue("AccessVBOM", 0) != 1)
{
key.SetValue("AccessVBOM", 1);
}
key.Close();
}
}
}
Так что код должен выглядеть так
public void RunReport()
{
ModifyExcelSecuritySettings();
// Launch Excel on the server
Excel = new Application
{
DisplayAlerts = false,
ScreenUpdating = false,
Visible = false
};
.....
Я также создал пост в блоге для полного решения, которое вы можете просмотреть здесь