Передача массива объектов из C# в VBA Excel

У меня есть консольное приложение C# и Dll. Я зарегистрировал dll как COM через взаимодействие. Я использовал

  1. COM Видимое свойство, GUID и т. д.
  2. Установите информацию о сборке, информацию о сборке, чтобы зарегистрировать ее в 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

Вероятно, это связано с excel.Run. Можете ли вы вызвать ThisWorkbook.GetListofObjects1 напрямую?

GSerg 27.07.2024 12:00

Я не думаю, что понимаю. Вы имеете в виду вызов этого в коде VBA из другой функции, чтобы проверить, работает ли он, я имею в виду?

Dee 27.07.2024 12:57

Нет, я имею в виду, если вы поместите ссылку на свою книгу в переменную dynamic и вызовете ее напрямую как wb.GetListofObjects1.

GSerg 27.07.2024 13:29

Когда я попробовал так, как вы упомянули, он даже не дошел до линии UBound. Программа зависает на секунду, а затем я получаю исключение System.Runtime.InteropServices.COMException: «Ошибка удаленного вызова процедуры. (Исключение из HRESULT: 0x800706BE)». Быстрый поиск в Google показывает, что что-то не так со сторонним компонентом COM (здесь есть dll), но, похоже, он работает нормально...

Dee 27.07.2024 13:46
Цитата: Это означает, что вы не можете передавать объекты в макросы с помощью метода Run. Вам придется сделать это по-другому: рассмотрите возможность вызова VBA для получения данных.
Hans Passant 28.07.2024 12:59

@HansPassant, мне удалось передать один объект без проблем. Итак, возможно, вы упомянули, почему это работает, но не массив. Я попытаюсь получить массив через саму dll с помощью вызова VBA, как вы упомянули, и обновлю вопрос, если это сработает. Большое спасибо!

Dee 28.07.2024 17:39

Я также видел этот пост вначале, где ОП смог отправить массив объектов и просмотреть их (хотя они не пытались печатать или пытаться выполнять какие-либо другие манипуляции с самим листом Excel, и у них была другая проблема)

Dee 28.07.2024 18:54

Вы тоже пробовали использовать это ArrayList?

GSerg 29.07.2024 14:03

Я попробовал еще раз с помощью ArrayList, установил временный CollClass, и это сработало. Код заработал после того, как я переписал большую часть функции и попробовал еще раз. Это сработало. Спасибо за помощь.

Dee 29.07.2024 18:14
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
9
136
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Изучив немного больше, я добавил 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

Другие вопросы по теме