Модули класса VBA имеют только два режима создания экземпляров: закрытый и общедоступный. Таким образом, вы даже не можете создать их экземпляр в другом проекте VB (A), не говоря уже о C #.
Однако ничто не мешает вам иметь стандартный модуль, который действует как фабрика классов. Таким образом, если ваш модуль класса Foo
, то в стандартном модуле вы можете иметь метод NewFoo
, который создает для вас новый Foo
и возвращает его вызывающей стороне. Объект Foo
, очевидно, должен был бы быть открытым для общественности.
[Ваш метод NewFoo
может принимать параметры, поэтому вы можете моделировать параметризованные конструкторы, которые недоступны в VBA.]
РЕДАКТИРОВАТЬ : подробности о том, как вызвать функцию VBA (в стандартном модуле) из C # и получить возвращаемое значение, используя Application.Run
.
private static object RunMacro(Excel.Application excelApp, string macroName, object[] parameters)
{
Type applicationType = excelApp.GetType();
ArrayList arguments = new ArrayList();
arguments.Add(macroName);
if (parameters != null)
arguments.AddRange(parameters);
try
{
return applicationType.InvokeMember("Run", BindingFlags.Default | BindingFlags.InvokeMethod, null, excelApp, arguments.ToArray());
}
catch (TargetInvocationException ex)
{
COMException comException = ex.InnerException as COMException;
if (comException != null)
{
// These errors are raised by Excel if the macro does not exist
if ( (comException.ErrorCode == -2146827284)
|| (comException.ErrorCode == 1004))
throw new ApplicationException(string.Format("The macro '{0}' does not exist.", macroName), ex);
}
throw ex;
}
}
Обратите внимание, что вы можете опустить все, что попытаться ... поймать вещи - все, что он делает, это обрабатывает конкретную ошибку, где макрос не существует, и вызывает более значимое исключение в этом случае.
object
, возвращаемый функцией, может быть приведен к любому типу, который вам нужен. Например:
object o = RunMacro(excelApp, "MyModule.MyFunc", new object[] { "param1", 2 });
if (o is string)
{
string s = (string) o;
Console.WriteLine(s);
}
Предполагая, что функция на самом деле возвращает экземпляр вашего объекта класса, определенного VBA, вы можете вызывать методы этого объекта таким же образом, снова используя InvokeMember
:
object o = RunMacro(excelApp, "MyModule.MyFunc", new object[] { "param1", 2 });
// assume o is an instance of your class, and that it has a method called Test that takes no arguments
o.GetType().InvokeMember("Run", BindingFlags.Default | BindingFlags.InvokeMethod, null, o, new string[] {"Test"});
Если вы делаете много таких вызовов, то, очевидно, вы можете скрыть ужасные детали, создав методы-обертки, чтобы сделать вызов для вас.
Обратите внимание, что я набрал большую часть из памяти, поэтому я полностью ожидаю, что там будут синтаксические, логические и, возможно, даже фактические ошибки: -)