У меня есть консольное приложение C# и Dll. Я зарегистрировал dll как COM через взаимодействие. Я использовал
Я ссылался на эту dll в коде VBA.
Я создал список объектов для этого класса в консольном приложении, преобразовал его в массив, а затем использовал Excel.Run
для отправки массива пользовательских объектов в код VBA.
Я могу получить доступ к свойствам массива в VBA, например LBound
и UBound
. Но я не могу получить доступ к каждому отдельному объекту в массиве.
Код C# выглядит следующим образом:
using System;
using System.Runtime.InteropServices;
namespace Save_as_excel_classes
{
[Guid("0BA8F8DE-8F0A-4D7E-9DDB-8AED42943BDA")]
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
public class CollClass
{
[ComVisible(true)]
public string NameValue { get; set; }
}
}
Консольное приложение выглядит следующим образом:
using Microsoft.Office.Interop.Excel;
using Save_as_excel_classes;
using System;
using System.Collections;
using System.Collections.Generic;
using _Excel = Microsoft.Office.Interop.Excel;
namespace ConsoleApp1
{
internal class Program
{
static void Main(string[] args)
{
Application excel = new _Excel.Application();
try
{
string fileName = "D:\\Book2.xlsm";
Workbook wb;
Worksheet ws;
int sheetNumber = 1;
excel.Visible = true;
wb = excel.Workbooks.Open(fileName);
ws = wb.Worksheets[sheetNumber];
ws = wb.Worksheets[sheetNumber];
var collVals = new List<CollClass>();
collVals.Add(new CollClass() { NameValue = "ABC" });
collVals.Add(new CollClass() { NameValue = "DEF" });
collVals.Add(new CollClass() { NameValue = "GHI" });
collVals.Add(new CollClass() { NameValue = "KLM" });
CollClass[] arr = collVals.ToArray();
excel.Run("ThisWorkbook.GetListofObjects1", arr);
}
catch (Exception ex)
{
}
finally
{
excel.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(excel);
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(excel);
}
}
}
}
Сторона VBA выглядит так: я просто пытаюсь установить NameValue
в ячейку.
Public Function GetListofObjects1(ByRef objColl() As collClass)
MsgBox "Inside GetListofObjects function" + " Hurray!"
Range("C3").Value = LBound(objColl)
Range("C4").Value = UBound(objColl)
Range("C5").Value = objColl(0).NameValue
End Function
Я искал различные вопросы на StackOverflow и форумах, но не знаю, что делаю неправильно. Каждый раз, когда я запускаю консольное приложение, Excel открывается, появляется окно сообщения, а затем происходит сбой и перезапуск. Я также получаю исключение в консольном приложении С# следующим образом после выполнения строк LBound и UBound. Это происходит только для Range("C5").Value = objColl(0).NameValue
«System.Runtime.InteropServices.COMException: 'Произошло исключение. (Исключение из HRESULT: 0x80020009 (DISP_E_EXCEPTION))'»
Я получаю правильный NameValue
, когда отправляю один объект вместо массива. Вот как раз с массивом видимо и происходят все проблемы.
Вероятно, это очень простое решение, но я занимаюсь этим уже более полутора дней и, похоже, не могу в этом разобраться.
Редактировать:
Я добавил в dll еще один класс CollClassArray
, который будет содержать только один CollClass
массив. Когда я передаю объект CollClassArray
через команду Run
и пытаюсь получить доступ к массиву внутри него, я получаю сообщение об ошибке: неправильное количество аргументов или недопустимое использование свойства рядом с CollArray(0)
.
Public Function GetListOfObjects1(array as CollClassArray)
Dim objColl as CollClass
Set objColl = array.CollArray(0).NameValue
End Function
Я не думаю, что понимаю. Вы имеете в виду вызов этого в коде VBA из другой функции, чтобы проверить, работает ли он, я имею в виду?
Нет, я имею в виду, если вы поместите ссылку на свою книгу в переменную dynamic
и вызовете ее напрямую как wb.GetListofObjects1
.
Когда я попробовал так, как вы упомянули, он даже не дошел до линии UBound. Программа зависает на секунду, а затем я получаю исключение System.Runtime.InteropServices.COMException: «Ошибка удаленного вызова процедуры. (Исключение из HRESULT: 0x800706BE)». Быстрый поиск в Google показывает, что что-то не так со сторонним компонентом COM (здесь есть dll), но, похоже, он работает нормально...
@HansPassant, мне удалось передать один объект без проблем. Итак, возможно, вы упомянули, почему это работает, но не массив. Я попытаюсь получить массив через саму dll с помощью вызова VBA, как вы упомянули, и обновлю вопрос, если это сработает. Большое спасибо!
Я также видел этот пост вначале, где ОП смог отправить массив объектов и просмотреть их (хотя они не пытались печатать или пытаться выполнять какие-либо другие манипуляции с самим листом Excel, и у них была другая проблема)
Вы тоже пробовали использовать это ArrayList
?
Я попробовал еще раз с помощью ArrayList
, установил временный CollClass, и это сработало. Код заработал после того, как я переписал большую часть функции и попробовал еще раз. Это сработало. Спасибо за помощь.
Изучив немного больше, я добавил mscorlib
в качестве ссылки в код VBA. Я использовал mscorlib.ArrayList
и смог получить доступ к элементам ArrayList
.
Код С#: с ArrayList
static void Main(string[] args)
{
Application excel = new _Excel.Application();
try
{
string fileName = "D:\\Book2.xlsm";
dynamic wb;
Worksheet ws;
int sheetNumber = 1;
excel.Visible = true;
wb = excel.Workbooks.Open(fileName);
ws = wb.Worksheets[sheetNumber];
var collVals = new List<CollClass>();
collVals.Add(new CollClass() { NameValue = "ABC", NumberValue = 2 });
collVals.Add(new CollClass() { NameValue = "DEF", NumberValue = 4 });
collVals.Add(new CollClass() { NameValue = "GHI", NumberValue = 6 });
collVals.Add(new CollClass() { NameValue = "KLM", NumberValue = 8 });
CollClass[] arr = collVals.ToArray();
ArrayList list = new ArrayList();
list.AddRange(arr);
excel.Run("ThisWorkbook.SetC5", list);
}
catch (Exception ex)
{
}
finally
{
excel.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(excel);
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(excel);
}
}
Код VBA:
Public Function setC5(coll As mscorlib.ArrayList)
MsgBox "Inside this function"
Dim count As Integer
Dim coll2(), coll1 As collClass
Dim number As Integer
number = coll.count
Range("C6") = number
Set coll1 = coll(0)
Range("C5").Value = coll1.NameValue
End Function
Вероятно, это связано с
excel.Run
. Можете ли вы вызватьThisWorkbook.GetListofObjects1
напрямую?