Как стать автором
Обновить

Легкое создание отчетов на C/C++

Время на прочтение4 мин
Количество просмотров11K
Если вы разрабатываете на C/C++ какое-либо ПО для операторов (администраторов) больниц, магазинов, сервисов проката гироскутеров, ремонта сотовых телефонов, то наверняка сталкивались с задачей создания отчетов, чтобы печатать их на принтере, ну или хотя бы в PDF. Существует множество сторонних пакетов для Embarcadero RAD Studio, которые позволяют это делать. Такие как FastReport, QuickReport, Crystal Reports и т.д. Но на мой взгляд все эти пакеты требуют глубокого вникания в свой механизм и интерфейс. Много времени уходит на их изучение, и что самое главное, код для генерирования даже самого простого отчета будет состоять из огромного числа строк. Когда я впервые столкнулся с задачей генерирования отчетов под C/C++, то начал с FastReport и понял, что этот инструмент мне абсолютно не нравится.

В этот самый момент в голову пришла замечательная мысль: как круто бы было взять простой EXCEL-файл, добавить в него статическую информацию и отформатировать под свои нужды. В программе останется только открыть этот файл, наполнить его динамическими данными и сохранить или отправить на печать! Это послужило отправной точкой к моему изучению OLE механизма работы с файлами MS Office из программ, разрабатываемых в Embarcadero RAD Studio.

По ходу деятельности удалось достаточно глубоко вникнуть в тему и сейчас могу с уверенностью сказать, что все те инструменты, которые предоставляет MS Office и OLE, перекрывают все мои потребности по созданию отчетов. Ну а раз так, то наверно и для других разработчиков это был бы самодостаточный, простой и удобный инструмент. Поэтому было принято решение написать DLL и упаковать в него перечень всех часто используемых функций MS Excel, с которыми приходится сталкиваться по ходу создания документов Excel. Это очень удобно, ведь для того, чтобы создать отчет, не нужно изучать кучу мануалов или OLE. Всё, что требуется, это только подгрузить DLL и входящие в нее функции. Ну а с DLL работать умеют многие.

Вот сайт самого проекта.

На сайте проекта достаточно подробно расписан механизм работы с DLL, есть пример и описание всех функций.

DLL поставляется без заголовочного файла и без статической LIB библиотеки. Таким образом, подключать DLL необходимо динамически с использованием функции LoadLibrary. ZIP архив с библиотекой включает следующие файлы:

  • "light_report.dll" — собственно сама DLL библиотека;
  • "DLLTest.cpp" — пример использования библиотеки;
  • "LPDLL.h" — заголовочный файл для примера использования библиотеки (это не заголовочный файл DLL);
  • "Report.xlsx" — документ MS EXCEL для примера использования библиотеки.

Заголовочный файл для примера использования библиотеки "LPDLL.h" содержит следующие объявления:

  • перечисления, которые используются в качестве аргументов функций DLL;
  • типы функций DLL;
  • экземпляры функций DLL;
  • дескриптор загружаемой библиотеки DLL ("HINSTANCE DLL_Handle;");
  • функция LoadLightReportDLL, которая динамически загружает DLL и все входящие в нее функции;
  • функция FreeLightReportDLL, которая выгружает DLL.

Файл «LPDLL.h» уже содержит всё необходимое для работы с DLL и ее функциями. Но вы также можете его отредактировать или взять только самое необходимое для вашего проекта.

Представим, что вы просто подключили к вашему проекту заголовочный файл «LPDLL.h».

Тогда в самом проекте вам просто необходимо:

1) Объявить переменную дескриптор вашего отчета:

Variant report;

​2) Динамически загрузить DLL и все ее функции:

if(!LoadLightReportDLL("C:\\LightReport\\light_report.dll"))return;

3) Далее в конструкции try-catch открыть заранее подготовленный шаблон отчета (файл MS Excel):

report=OpenReport("C:\\LightReport\\Report.xlsx",0);

4) Добавить в отчет какие-нибудь данные:

WriteCell(report, "Sheet1", 9, 1, "Hello world!");


5) Сохранить файл или напечатать:

Save(report);
SaveAs(report, "C:\\LightReport\\Report copy.xlsx");
ExportToPDF(report, "C:\\LightReport\\Report.pdf", false);
PrintOut(report);

6) Закрыть файл:

CloseReport(report);

7) Выгрузить DLL библиотеку:

FreeLightReportDLL();

И всё! Абсолютно ничего лишнего! Есть лишь один нюанс, но и то, он проявляется только при отладке. В работающем приложении всё будет работать хорошо. Я имею ввиду ситуацию, при которой возникает какая-либо ошибка при работе с отчетом. Дело в том, что OLE механизм работы с документами предполагает только выброс исключений при возникновении ошибок. Вот почему при работе с функциями DLL необходимо применять конструкцию try-catch. В блоке catch необходимо без сохранения закрывать отчет:

catch(...){CloseReport(report);}
.
При отладке, когда возникает ошибка, вы можете остановить работу программы. При этом процесс MS Excel останется запущенным, и закрыть его можно будет только через диспетчер задач. Поэтому при многократной отладке приложения может быть запущено несколько экземпляров процесса MS Excel в зависимости от того, как часто вы приостанавливали работу программы при возникновении ошибки, не дожидаясь выполнения кода в catch. За этим надо следить.

В релизе же, при возникновении ошибки обязательно сработает код, указанный в блоке catch, отчет закроется и процесс MS Excel будет завершен. Никаких висящих в системе процессов MS Excel наблюдаться не будет. Но все же стараются писать безошибочный код, поэтому надеюсь у вас не возникнет такая ситуация в работающем приложении.

Напоследок необходимо добавить:

  1. В DLL применяются платформонезависимые типы данных, такие как, unsigned short, unsigned long и char. Это понятно почему.
  2. Пример написан в среде Embarcadero Builder C++ 10. Соответственно, весь код соотносится с этой средой и, возможно, вам необходимо будет внести кое-какие изменения в код примера, чтобы всё заработало в вашем окружении.
  3. Узким местом этой DLL является использование дескритора файла отчета в формате Variant. Это довольно специфический формат и, подозреваю, что могут возникнуть трудности с использованием библиотеки вне Embarcadero RAD Studio. Честно, не проверял.

Поэтому на будущее планируется упаковать весь функционал в класс и скрыть этот формат Variant внутри класса, чтобы наружу пользователю предоставлялись только общепринятые форматы C/C++. Не пробовал ни разу упаковывать классы в DLL, читал, что с этим обязательно возникнут трудности. Тем не менее будем разбираться! А пока, спасибо за внимание, буду очень рад, если эта статья и DLL кому-то помогут.

Ссылка на проект.
Теги:
Хабы:
Всего голосов 25: ↑15 и ↓10+5
Комментарии16

Публикации

Истории

Работа

Программист C++
133 вакансии
Программист С
46 вакансий
QT разработчик
8 вакансий

Ближайшие события