Вопрос, поднятый в данном запросе, касается проблемы, с которой сталкиваются разработчики, использующие Delphi XE2 для работы с компонентами COM, в частности с Excel. Проблема заключается в том, что при работе с объектами Excel через COM-интерфейс в Delphi XE2 возникают исключения, которые не наблюдались в предыдущих версиях, например, в Delphi 2010.
Описание проблемы
Программа на Delphi, предназначенная для работы с Excel, в версии XE2 выдает исключения. Это регрессия по сравнению с версией 2010. В частности, в 32-битной версии XE2 ошибка возникает при повторном обращении к свойству Columns объекта UsedRange, а в 64-битной версии - при обращении к той же функции, которая приводет к нарушению доступа к памяти (ACCESS_VIOLATION).
Контекст
Согласно предоставленному коду, проблема возникает в процедуре DispCallByID в модуле System.Win.ComObj. Это связано с некорректным освобождением интерфейсов и использованием локальных переменных при повторном выполнении цикла. В комментариях к коду указано, что проблема может быть связана с неинициализированным внутренним интерфейсом, который освобождается при вызове _Release.
Подтвержденный ответ
В качестве обходного пути можно использовать следующие методы:
1. Записать количество строк и столбцов в локальные переменные перед циклами for, чтобы избежать повторного вызова свойств объекта UsedRange.
2. Создать отдельную функцию для получения количества столбцов, что также поможет избежать повторного вызова свойства.
Пример кода
program COMbugWorkaround;
{$APPTYPE CONSOLE}
uses
SysUtils, Variants, Windows, Excel2000;
var
Excel: TExcelApplication;
Book: ExcelWorkbook;
Sheet: ExcelWorksheet;
UsedRange: ExcelRange;
Row, Col, rowCnt, colCnt: Integer;
v: Variant;
function ColCount(const range: ExcelRange): Integer;
begin
Result := range.Columns.Count;
end;
begin
Excel := TExcelApplication.Create(nil);
try
Excel.Visible[LOCALE_USER_DEFAULT] := True;
Book := Excel.Workbooks.Add(EmptyParam, LOCALE_USER_DEFAULT) as ExcelWorkbook;
Sheet := Book.Worksheets.Add(EmptyParam, EmptyParam, 1, EmptyParam, LOCALE_USER_DEFAULT) as ExcelWorksheet;
Sheet.Cells.Item[1,1].Value := 1.0;
Sheet.Cells.Item[2,2].Value := 1.0;
UsedRange := Sheet.UsedRange[LOCALE_USER_DEFAULT] as ExcelRange;
rowCnt := UsedRange.Rows.Count;
colCnt := ColCount(UsedRange);
for Row := 1 to rowCnt do begin
for Col := 1 to colCnt do begin
v := UsedRange.Item[Row, Col].Value;
end;
end;
finally
Excel.Free;
end;
end.
Альтернативный ответ
Согласно обсуждению, возможной причиной ошибки может быть отсутствие вызова CoInitialize. Однако, даже с добавлением этого вызова, проблема сохраняется. Также предлагается перемещение функционала в отдельные процедуры, что может помочь в устранении проблемы.
Заключение
Пользователи, столкнувшиеся с аналогичной проблемой, должны обратить внимание на следующие моменты:
- Использование локальных переменных для хранения количества строк и столбцов.
- Создание отдельной функции для подсчета столбцов.
- Перемещение логики в отдельные процедуры для лучшего контроля за состоянием объектов.
- Внимательное изучение логов отладки и комментариев к коду, предоставленных сообществом.
Обновление: Проблема была исправлена в обновлении XE2 Update 2.
Контекст вопроса заключается в том, что разработчики, использующие Delphi XE2 для интеграции с Excel через COM, сталкиваются с исключениями, особенно при работе с 32-битной и 64-битной версиями, которые не наблюдались в предыдущих версиях, таких как Delp
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS