Я пишу надстройку COM для VBE, и одна из основных функций включает в себя выполнение существующего кода VBA при нажатии кнопки командной строки.
Код - это код модульного тестирования, написанный пользователем, в стандартном (.bas) модуле, который выглядит примерно так:
Option Explicit Option Private Module '@TestModule Private Assert As New Rubberduck.AssertClass '@TestMethod Public Sub TestMethod1() 'TODO: Rename test On Error GoTo TestFail 'Arrange: 'Act: 'Assert: Assert.Inconclusive TestExit: Exit Sub TestFail: Assert.Fail "Test raised an error: #" & Err.Number & " - " & Err.Description End Sub
Итак, у меня есть этот код, который получает текущий экземпляр объекта host Application
:
protected HostApplicationBase(string applicationName)
{
Application = (TApplication)Marshal.GetActiveObject(applicationName + ".Application");
}
Здесь класс ExcelApp
:
public class ExcelApp : HostApplicationBase<Microsoft.Office.Interop.Excel.Application>
{
public ExcelApp() : base("Excel") { }
public override void Run(QualifiedMemberName qualifiedMemberName)
{
var call = GenerateMethodCall(qualifiedMemberName);
Application.Run(call);
}
protected virtual string GenerateMethodCall(QualifiedMemberName qualifiedMemberName)
{
return qualifiedMemberName.ToString();
}
}
Работает как шарм. У меня есть аналогичный код для WordApp
, PowerPointApp
и AccessApp
тоже.
Проблема заключается в том, что объект Outlook Application
не предоставляет метод Run
, поэтому я, ну, застрял.
Как я могу выполнить код VBA из надстройки COM для VBE без Application.Run
?
Этот ответ ссылается на сообщение в блоге MSDN, которое выглядит многообещающим, поэтому я попробовал это:
public class OutlookApp : HostApplicationBase<Microsoft.Office.Interop.Outlook.Application>
{
public OutlookApp() : base("Outlook") { }
public override void Run(QualifiedMemberName qualifiedMemberName)
{
var app = Application.GetType();
app.InvokeMember(qualifiedMemberName.MemberName, BindingFlags.InvokeMethod, null, Application, null);
}
}
Но тогда лучшее, что я получаю, это COMException
, который говорит "неизвестное имя", и процесс OUTLOOK.EXE, выходящий с кодом -1073741819 (0xc0000005) "Нарушение прав доступа" - и он взрывается так же хорошо, как и Excel тоже.
UPDATE
Этот код VBA работает, если я помещаю TestMethod1
внутрь ThisOutlookSession
:
Outlook.Application.TestMethod1
Обратите внимание, что TestMethod1
не указан как член Outlook.Application
в VBA IntelliSense.. но как-то это срабатывает.
Вопрос в том, как я могу сделать эту работу с Reflection?