Класс 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();
}
Все комментарии
Чтобы оставить комментарий, необходимо войти или зарегистрироваться.
Пока нет комментариев. Будьте первым!