Пакетная печать отчетов в MS Dynamics AX 2012 при помощи XMLExcelReport_RU
Класс XMLExcelReport_RU наследник RunBaseBatch, соответственно должен работать в пакете, но для отправки отчета сразу на печать используется COM объект, который может работать не стабильно при больших объемах в пакете. Можно использовать библиотеки Microsoft.Office.Interop, которые чаще используются в пакетном режиме. Также в XMLExcelReport_RU используется WinAPI, его тоже не совсем корректно использовать при работе на сервере, потому что, к примеру, WinAPI::deleteFile() используется в методе processInExcel() без учета возвращаемого значения и при не удачной попытке выполнить команду на сервере продолжает работу приложения, при этом не выводя сообщений, а временные файлы отчетов продолжают копиться. Ниже приведен код для запуска печати на сервере в MS Dynamics AX 2012 (метод XMLExcelReport_RU.processInExcel()).
case SRSPrintMediumType::Printer: if (isRunningOnServer()) { this.excelPrintOnServer(_filename); } else {
Печать выведена в отдельный метод.
private void excelPrintOnServer(Filename _filename) { Microsoft.Office.Interop.Excel.ApplicationClass excel; Microsoft.Office.Interop.Excel.Workbooks workBooks; Microsoft.Office.Interop.Excel._Workbook workbook; System.Type type = System.Type::GetType('System.Reflection.Missing'); System.Reflection.FieldInfo info = type.GetField('Value'); System.Object missing = info.GetValue(null); //________ void deleteFile() { boolean fileExists; new InteropPermission(InteropKind::ClrInterop).assert(); fileExists = System.IO.File::Exists(_filename); CodeAccessPermission::revertAssert(); if (fileExists) { XmlExcelReport_RU::removeFileServer(_filename); } } //_______ void errorCatched() { new InteropPermission(InteropKind::ClrInterop).assert(); if (excel) { excel.Quit(); excel = null; System.GC::Collect(); System.GC::WaitForPendingFinalizers(); } else { error(strFmt("Ошибка создания объекта Microsoft.Office.Interop.Excel на '%1'", xGlobal::computerName())); } CodeAccessPermission::revertAssert(); deleteFile(); throw error(strFmt("Ошибка при печати файла %1 на сервере %2", _filename, xGlobal::computerName())); } //______ boolean checkPrinterName() { System.Drawing.Printing.PrinterSettings printerSettings; if (!printDestinationSettings.printerName()) { return checkFailed("Имя принтера не указано"); } printerSettings = new System.Drawing.Printing.PrinterSettings(); printerSettings.set_PrinterName(printDestinationSettings.printerName()); if (!printerSettings.get_IsValid()) { return checkFailed(strFmt("Имя принтера '%1' не допустимо для печати на '%2'", printDestinationSettings.printerName(), xGlobal::computerName())); } return true; } boolean openFile() { // BP deviation documented workbook = workBooks.Open(_fileName, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing); // BP deviation documented return !CLRInterop::isNull(workbook); } //====== setPrefix(strFmt("Печать на принтер '%1' на сервере '%2'", printDestinationSettings.printerName(), xGlobal::computerName())); if (!checkPrinterName()) { deleteFile(); throw Exception::Error; } try { CodeAccessPermission::revertAssert(); new InteropPermission(InteropKind::ClrInterop).assert(); excel = new Microsoft.Office.Interop.Excel.ApplicationClass(); workBooks = excel.get_Workbooks(); if (openFile()) { workbook.PrintOut(missing, missing, CLRInterop::getObjectForAnyType(1), False, CLRInterop::getObjectForAnyType(printDestinationSettings.printerName()), false, true, ''); workbook.Close(false, missing, missing); workBook = null; workBooks.Close(); workBooks = null; excel.Quit(); excel = null; System.GC::Collect(); System.GC::WaitForPendingFinalizers(); CodeAccessPermission::revertAssert(); } else { CodeAccessPermission::revertAssert(); throw error(strFmt('Не удалось открыть файл "%1".', _filename)); } } catch (Exception::CLRError) { error(AifUtil::getClrErrorMessage()); errorCatched(); } catch { errorCatched(); } }
Проверка наименования принтера классом System.Drawing.Printing.PrinterSettings была добавлена, потому что если было передано пустое имя принтера или наименование не установленного на данном сервере принтера, то печать зависала. Также зависало выполнение пакетного задания если вовремя не завершались процессы Excel. Для этого дополнительно вызывается сборщик мусора System.GC и присваиваются объектам Excel значение null. Также дополнительно освобождалась переменная excelDocument в методе XMLExcelReport_RU.run()
if (excelDocument) { if (excelDocument.getComDocument()) { excelDocument.visible(true); excelDocument.finalize(); } else { excelDocument.quitApplication(false); excelDocument.finalize(); } excelDocument = null; System.GC::Collect(); System.GC::WaitForPendingFinalizers(); }
Comments
So empty here ... leave a comment!