Взаимодействие Microsoft Excel с приложениями .NET - позднее
От: Аноним Гасанов Ровшан Закариевич  
Дата: 12.07.05 06:56
Оценка: 230 (9) +1
Статья:
Взаимодействие Microsoft Excel с приложениями .NET — позднее связывание
Автор(ы): Гасанов Ровшан Закариевич
Дата: 17.11.2005
Статья рассказывает о динамическом взаимодействии с Excel посредством OLE Automation и рефлексии.
Требуется знание С#.


Авторы:
Гасанов Ровшан Закариевич

Аннотация:
Статья рассказывает о динамическом взаимодействии с Excel посредством OLE Automation и рефлексии.
Требуется знание С#.
Re: Взаимодействие Microsoft Excel с приложениями .NET - поз
От: nzeemin Россия http://nzeemin.livejournal.com/
Дата: 12.07.05 07:12
Оценка: 13 (2)
Здравствуйте, Гасанов Ровшан Закариевич, Вы писали:

ГРЗ>Статья:

ГРЗ>Взаимодействие Microsoft Excel с приложениями .NET — позднее связывание
Автор(ы): Гасанов Ровшан Закариевич
Дата: 17.11.2005
Статья рассказывает о динамическом взаимодействии с Excel посредством OLE Automation и рефлексии.
Требуется знание С#.


Насколько я понял, это просто более новая версия статьи:
http://www.gotdotnet.ru/LearnDotNet/Misc/156928.aspx

P.S. Тема PIA (Primary Interop Assemblies) не раскрыта.
Re: Взаимодействие Microsoft Excel с приложениями .NET - поз
От: Аноним  
Дата: 12.07.05 08:48
Оценка:
Здравствуйте, Гасанов Ровшан Закариевич, Вы писали:

А я всегда взаимодействовал с ексцелем и кучей других приложений за одно генерацией html страничек. А совсем давно — comma-separated + шаблон. А зачем всё остальное нужно вообще — это только лишние проблемы с СОМ interop и версиями оффиса и других приложений у клиента?

Неужели всё это нужно только

ради использования двух-трех методов

?
Re[2]: Взаимодействие Microsoft Excel с приложениями .NET -
От: Аноним  
Дата: 15.07.05 13:22
Оценка:
Здравствуйте, nzeemin, Вы писали:

N>Здравствуйте, Гасанов Ровшан Закариевич, Вы писали:


ГРЗ>>Статья:

ГРЗ>>Взаимодействие Microsoft Excel с приложениями .NET — позднее связывание
Автор(ы): Гасанов Ровшан Закариевич
Дата: 17.11.2005
Статья рассказывает о динамическом взаимодействии с Excel посредством OLE Automation и рефлексии.
Требуется знание С#.


N>Насколько я понял, это просто более новая версия статьи:

N>http://www.gotdotnet.ru/LearnDotNet/Misc/156928.aspx

N>P.S. Тема PIA (Primary Interop Assemblies) не раскрыта.



Да, это обновленный вариант, который был специально подготовлен для журнала RSDN.

По поводу PIA — это те же DLL, которые можно получить с помощью утилиты tlbimp.exe, просто подготовленные Microsoft отдельно. Тема статьи — Позднее связывание, поэтому рассмотрение PIA выходит за рамки материала. При позднем связывании не нужны никакие заранее скомпилированные классы-посредники, все создается на этапе выполнения.
Re[2]: Взаимодействие Microsoft Excel с приложениями .NET -
От: Andrbig  
Дата: 15.07.05 13:56
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, Гасанов Ровшан Закариевич, Вы писали:


А>А я всегда взаимодействовал с ексцелем и кучей других приложений за одно генерацией html страничек. А совсем давно — comma-separated + шаблон. А зачем всё остальное нужно вообще — это только лишние проблемы с СОМ interop и версиями оффиса и других приложений у клиента?


А>Неужели всё это нужно только

А>ради использования двух-трех методов

?


И трех-четырех версий excel. 97, 2000, 2003 имеют несовместимые интеропы (или что-то в этом духе). На этом форуме кто-то уже бился с различными excel, поищи.
Re: Взаимодействие Microsoft Excel с приложениями .NET - поз
От: Арташес Россия  
Дата: 20.11.05 13:34
Оценка:
У меня еще такой вопрос (прошу не бить — я новичок )

А где использовалось пространство имен ?

using System.Reflection;


У меня получилось открыть и экспортировать в эксель и без Reflections,
или это нужно для перехвата событий? ( А где конкретно? )

Спасибо
Арташес
Re: Взаимодействие Microsoft Excel с приложениями .NET - поз
От: bo Россия  
Дата: 21.11.05 12:11
Оценка:
От себя немного добавлю к статье...

Полезно написать библиотеку с классами-обвязками объектов Excel'a, например:
public class Excel : IDisposable
{
    object    _comObject=null;

    public Excel()
    {
        Type excelType=Type.GetTypeFromProgID("Excel.Application");
        _comObject=Activator.CreateInstance(excelType);
    }

...
}

public class Workbook
{
    object _comObject;

    internal Workbook(object ComObject)
    {
        _comObject=ComObject;
    }

    public string Name //пример обращения к свойству
    {
        get
        {
            return (string)_comObject.GetType().InvokeMember("Name", BindingFlags.GetProperty, null, _comObject, new object[0]);
        }
        set
        {
            _comObject.GetType().InvokeMember("Name", BindingFlags.SetProperty, null, _comObject, new object[]{value});
        }
    }

    public void SaveAs(string fileName) //пример обращения к методу
    {
        _comObject.GetType().InvokeMember("SaveAs", BindingFlags.InvokeMethod, null, _comObject, new object[]{fileName});
    }


...
}

public class Range
{
    object _comObject=null;

    internal Range(object ComObject)
    {
        _comObject=ComObject;
    }
...
}

и так далее.

Для "портирования" объектов и методов Excel'a в дотнет достаточно либо посмотреть помощь по VBA в самом Excel'e, либо открыть Reflector'ом созданную студией interop-сборку для объектов того же Excel'a.


Для обращения к спискам объектов используются самописные коллекции:
public class WorkbooksCollection : ICollection
{
    object    _comObject;

    internal WorkbooksCollection(object ExcelObject)
    {
        _comObject=ExcelObject.GetType().InvokeMember("Workbooks", BindingFlags.GetProperty, null, ExcelObject, new object[0]);
    }

    public Workbook this[int index] //обращение к элементу коллеции по индексу
    {
        get
        {
            try
            {
                return new Workbook(_comObject.GetType().InvokeMember("Item", BindingFlags.GetProperty, null, _comObject, new object[]{index}));
            }
            catch(Exception)
            {
                return null;
            }
        }
    }

    public Workbook this[string name] //обращение к элементу коллеции по имени
    {
        get
        {
            try
            {
            return new Workbook(_comObject.GetType().InvokeMember("Item", BindingFlags.GetProperty, null, _comObject, new object[]{name}));
            }
            catch
            {
                return null;
            }
        }
    }

...
}


Как видно из приведённых примеров, все классы (в том числе и коллекции) имеют "указатель" на соответствующий COM-объект и все обращения к методам proxy-класса приводят к обращениям вида:
return new Workbook(_comObject.GetType().InvokeMember("Add", BindingFlags.InvokeMethod, null, _comObject, new object[]{Missing.Value}));


Таким образом, получается библиотека из порядка восьми классов-proxy и десятка коллекций.
Пользователь, работающий с данной библиотекой, не видит никаких низкоуровневых операций типа InvokeMember.
Например, так:
using(Excel excel=new Excel())
{
    excel.Visible=true;
    int wbCount=excel.Workbooks.Count;
    object workbook1=excel.Workbooks.Add();

    foreach(Worksheet wsh in excel.Workbooks[1].Worksheets) //даже так
        Console.WriteLine(wsh.Name);

    Worksheet ws=excel.Workbooks[1].Worksheets["Лист1"];

    for(int i=1; i<10; i++)
        for(int j=1;j<3;j++)
            ws.Cells[i,j].Value=i*10+j;
                
    Range range=excel.Workbooks[1].Worksheets[1].GetRange("A1", "B9");
    range.Select();

    excel.Quit();
}


На последок замечу, что библиотека, описывающая практически все объекты Excel'a, была написана начинающим программистом за 2 дня. И библиотека с удовольствием используется всей фирмой.
В человечишке все должно быть прекрасненьким: и одёжка, и душенка, и мордочка, и мыслишки.
Re[2]: Взаимодействие Microsoft Excel с приложениями .NET -
От: bo Россия  
Дата: 21.11.05 12:14
Оценка:
Маленькое добавление:
разрабатывается и тестируется библиотека под Excel97 для обеспечения обратной совместимости, а далее при желании можно проверить работоспособность под Excel 2003.
В человечишке все должно быть прекрасненьким: и одёжка, и душенка, и мордочка, и мыслишки.
Re[2]: Взаимодействие Microsoft Excel с приложениями .NET -
От: SISerge  
Дата: 13.12.05 08:16
Оценка:
Здравствуйте, bo, Вы писали:

bo>От себя немного добавлю к статье...

bo>Полезно написать библиотеку с классами-обвязками объектов Excel'a, например:
bo>На последок замечу, что библиотека, описывающая практически все объекты Excel'a, была написана начинающим программистом за 2 дня. И библиотека с удовольствием используется всей фирмой.

Здравствуйте!
Один вопрос: а как вы решили проблему с передачей в Range массива объектов? Присваивание по ячейкам работает довольно медленно, а попытка передать в качестве последнего параметра InvokeMember object[][] заканчивается exception. Если можно, то просто кусочек кода. Заранее спасибо.
Re[3]: Взаимодействие Microsoft Excel с приложениями .NET -
От: bo Россия  
Дата: 13.12.05 08:32
Оценка:
Здравствуйте, SISerge, Вы писали:

SIS>Здравствуйте!

SIS>Один вопрос: а как вы решили проблему с передачей в Range массива объектов? Присваивание по ячейкам работает довольно медленно, а попытка передать в качестве последнего параметра InvokeMember object[][] заканчивается exception.
Присваивание по ячейкам работает медленно и из самих макросов Excel (сейчас не знаю, но на моём первом P1-133 и Excel'97 процесс пробегания по ячейкам можно было наблюдать невооруженным взглядом ).
В любом случае следует стараться использовать range сразу для нескольких ячеек.

SIS>Если можно, то просто кусочек кода. Заранее спасибо.


Можно:
    public class Worksheet
    {
        object _comObject=null;

        internal Worksheet(object ComObject)
        {
            _comObject=ComObject;
        }

//первый способ получения объекта Range
        public Range GetRange(string cell1)
        {
            return new Range(_comObject.GetType().InvokeMember("Range", BindingFlags.GetProperty, null, _comObject, new object[]{cell1}));
        }

        public Range GetRange(string cell1, string cell2)
        {
            return new Range(_comObject.GetType().InvokeMember("Range", BindingFlags.GetProperty, null, _comObject, new object[]{cell1, cell2}));
        }

        public Range GetRange(Range cell1, Range cell2)
        {
            return new Range(_comObject.GetType().InvokeMember("Range", BindingFlags.GetProperty, null, _comObject, new object[]{cell1.GetObject(), cell2.GetObject()}));
        }


//второй способ получения
        public Range Cells
        {
            get
            {
                return new Range(_comObject.GetType().InvokeMember("Cells", BindingFlags.GetProperty, null, _comObject, new object[0]));
            }
        }

        public Range Columns
        {
            get
            {
                return new Range(_comObject.GetType().InvokeMember("Columns", BindingFlags.GetProperty, null, _comObject, new object[0]));
            }
        }


        public Range Rows
        {
            get
            {
                return new Range(_comObject.GetType().InvokeMember("Rows", BindingFlags.GetProperty, null, _comObject, new object[0]));
            }
        }
    }


//и собственно сам Range
    public class Range
    {
        object _comObject=null;

        public Range(object ComObject)
        {
            _comObject=ComObject;
        }

        public Range Cells
        {
            get
            {
                return new Range(_comObject.GetType().InvokeMember("Cells", BindingFlags.GetProperty, null, _comObject, new object[0]));
            }
        }

        public int Column
        {
            //возвращает номер первого столбца
            get
            {
                return (int)_comObject.GetType().InvokeMember("Column", BindingFlags.GetProperty, null, _comObject, new object[0]);
            }
            set
            {
                _comObject.GetType().InvokeMember("Column", BindingFlags.SetProperty, null, _comObject, new object[]{value});
            }
        }

        public Range Columns
        {
            get
            {
                return new Range(_comObject.GetType().InvokeMember("Columns", BindingFlags.GetProperty, null, _comObject, new object[0]));
            }
        }

//пример публичного свойства
        public string Text
        {
            get
            {
                return (string)_comObject.GetType().InvokeMember("Text", BindingFlags.GetProperty, null, _comObject, new object[0]);
            }
        }

    }

Остальные методы классов покоцаны...
В человечишке все должно быть прекрасненьким: и одёжка, и душенка, и мордочка, и мыслишки.
Re[4]: Взаимодействие Microsoft Excel с приложениями .NET -
От: SISerge  
Дата: 13.12.05 09:11
Оценка:
Спасибо, но методы получения Range я знаю как реализовать. Я хотел узнать, как вы свойству Value самого Range присваиваете двумерный массив? Т.е. был у меня wrapper для Excel на VC++ 6, сейчас его нужно перетащить на C#. На С++ я Invoke передавал в качестве параметра для DISPATCH_PROPERTYPUT свойства Value простой двумерный массив COleSafeArray и Range быстренько заполнялась им. Сейчас я передаю заполненый object[][] в таком вызове:


range.GetType().InvokeMember("Value",BindingFlags.SetProperty,null,range,args);


где в args[0] и лежит мой object[][].
В результате получается вот такой exception:

Specified array was not of the expected type.
Re[5]: Взаимодействие Microsoft Excel с приложениями .NET -
От: bo Россия  
Дата: 13.12.05 20:35
Оценка:
Здравствуйте, SISerge, Вы писали:

SIS>Спасибо, но методы получения Range я знаю как реализовать. Я хотел узнать, как вы свойству Value самого Range присваиваете двумерный массив? Т.е. был у меня wrapper для Excel на VC++ 6, сейчас его нужно перетащить на C#. На С++ я Invoke передавал в качестве параметра для DISPATCH_PROPERTYPUT свойства Value простой двумерный массив COleSafeArray и Range быстренько заполнялась им. Сейчас я передаю заполненый object[][] в таком вызове:



SIS>
SIS>range.GetType().InvokeMember("Value",BindingFlags.SetProperty,null,range,args);
SIS>


SIS>где в args[0] и лежит мой object[][].

SIS>В результате получается вот такой exception:

SIS>Specified array was not of the expected type.


Сейчас проверил с int[,] — всё работает:
    Range range=excel.Workbooks[1].Worksheets[1].GetRange("A1", "B2");

    int[,] values=new int[,]{{1, 2}, {3, 4}};
    range.Value=values;
В человечишке все должно быть прекрасненьким: и одёжка, и душенка, и мордочка, и мыслишки.
Re[2]: Взаимодействие Microsoft Excel с приложениями .NET -
От: slv Украина  
Дата: 23.12.05 07:03
Оценка:
Здравствуйте, bo, Вы писали:
bo>На последок замечу, что библиотека, описывающая практически все объекты Excel'a, была написана начинающим программистом за 2 дня. И библиотека с удовольствием используется всей фирмой.
А нет ли у Вас желания выложить библиотеку в форуме Исходники ?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[3]: Взаимодействие Microsoft Excel с приложениями .NET -
От: Avos Беларусь  
Дата: 23.12.05 09:27
Оценка:
Здравствуйте, slv, Вы писали:

slv>Здравствуйте, bo, Вы писали:

bo>>На последок замечу, что библиотека, описывающая практически все объекты Excel'a, была написана начинающим программистом за 2 дня. И библиотека с удовольствием используется всей фирмой.
slv>А нет ли у Вас желания выложить библиотеку в форуме Исходники ?

поддерживаю предыдущего оартора
Re[6]: Взаимодействие Microsoft Excel с приложениями .NET -
От: ravex  
Дата: 12.01.06 10:58
Оценка:
Здравствуйте, bo, Вы писали:

bo>Сейчас проверил с int[,] — всё работает:

bo>
bo>    Range range=excel.Workbooks[1].Worksheets[1].GetRange("A1", "B2");

bo>    int[,] values=new int[,]{{1, 2}, {3, 4}};
bo>    range.Value=values;
bo>


А можно глянуть, как реализовано свойство Value класса Range?
Взаимодействие Microsoft Excel с приложениями .NET - позднее
От: Аноним  
Дата: 12.01.06 13:08
Оценка:
А не легче ли будет сделать Excel'евский XML файл, чем работать напрямую с Excel чукуз позднее связывание...?
Если долго мучаться, то что нибудь получится.


данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re[7]: Взаимодействие Microsoft Excel с приложениями .NET -
От: bo Россия  
Дата: 12.01.06 13:43
Оценка:
Здравствуйте, ravex, Вы писали:

R>А можно глянуть, как реализовано свойство Value класса Range?


public object Value
{
    get
    {
        return _comObject.GetType().InvokeMember("Value", BindingFlags.GetProperty, null, _comObject, new object[0]);
    }
    set
    {
        _comObject.GetType().InvokeMember("Value", BindingFlags.SetProperty, null, _comObject, new object[]{value});
    }
}


_comObject представляет Excel'евское зеркало данного объекта range.
В человечишке все должно быть прекрасненьким: и одёжка, и душенка, и мордочка, и мыслишки.
Re: Взаимодействие Microsoft Excel с приложениями .NET - поз
От: bo Россия  
Дата: 12.01.06 13:44
Оценка:
Здравствуйте, Tamagochi, Вы писали:

T>А не легче ли будет сделать Excel'евский XML файл, чем работать напрямую с Excel чукуз позднее связывание...?


И установить везде Office 2003?
В человечишке все должно быть прекрасненьким: и одёжка, и душенка, и мордочка, и мыслишки.
Re: Взаимодействие Microsoft Excel с приложениями .NET - поз
От: ravex  
Дата: 13.01.06 04:05
Оценка:
Здравствуйте, Tamagochi, Вы писали:

T>А не легче ли будет сделать Excel'евский XML файл, чем работать напрямую с Excel чукуз позднее связывание...?


T>
данное сообщение получено с www.gotdotnet.ru

T>ссылка на оригинальное сообщение


Ну если учесть, что пользователи юзают широкий спектр офисов, начиная с 97-го и заканчивая 2003-м, то никак не легче
Re[8]: Взаимодействие Microsoft Excel с приложениями .NET -
От: ravex  
Дата: 13.01.06 04:47
Оценка:
Здравствуйте, bo, Вы писали:

bo>Здравствуйте, ravex, Вы писали:


R>>А можно глянуть, как реализовано свойство Value класса Range?


bo>
bo>public object Value
bo>{
bo>    get
bo>    {
bo>        return _comObject.GetType().InvokeMember("Value", BindingFlags.GetProperty, null, _comObject, new object[0]);
bo>    }
bo>    set
bo>    {
bo>        _comObject.GetType().InvokeMember("Value", BindingFlags.SetProperty, null, _comObject, new object[]{value});
bo>    }
bo>}
bo>


bo>_comObject представляет Excel'евское зеркало данного объекта range.


Ага, спасибо! Я в общем-то так и сделал. Просто меня насторожил момент, когда в Value передается не одно значение, а массив, т.е. когда Range представляет собой массив ячеек. Но проверил — все работает нормально.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.