delphi - ExportAsFixedFormat 的 IgnorePrintAreas 参数好像没有效果

标签 delphi file-conversion excel-automation

在 Delphi 应用程序中,多年来我一直使用以下代码将 xlxs 导出为 pdf:

function TExportTool.ExportExcelToPDF(aFileName, aNewFileName: String): Boolean;
// reference : http://embarcadero.newsgroups.archived.at/public.delphi.oleautomation/200811/081103142.html
// unluckily the link above is dead
{- Sheet is counted from 1 and upwards !! }
Var
  App,oWB,oSheet : OleVariant;
begin
  Result := False;
  App:= CreateOleObject('Excel.Application');
  Try
    App.Visible:= 0;
    oWb := App.WorkBooks.Open(ExpandUNCFileName(afilename),1);  // Open read only
    Try
     oSheet := oWB.ActiveSheet;
     oSheet.ExportAsFixedFormat(0,  //xlTypePDF is constant 0
                            aNewFileName,
                            EmptyParam, 
                            EmptyParam, 
                            EmptyParam, // this should be IgnorePrintAreas
                            EmptyParam,
                            EmptyParam,
                            EmptyParam,
                            EmptyParam
                            );
    Finally
    End;
    Result := True;
  Finally
    App.Quit;
    App:= UnAssigned;
  End;
end;

// IMPROVED WORKING CODE FOLLOWS

function TExportTool.ExportExcelToPDF(aFileName, aNewFileName: String): Boolean;
// reference : http://embarcadero.newsgroups.archived.at/public.delphi.oleautomation/200811/081103142.html
{- Sheet is counted from 1 and upwards !! }

procedure RestoreOriginalPrintArea (oSheet: OleVariant);
// Excel loses print area settings in non-English version of application when file is opened using automation:
// https://stackoverflow.com/questions/71379893/exportasfixedformats-ignoreprintareas-parameter-seems-not-to-have-effect
var
  i:Integer;
begin
  for  i:= 1 to oSheet.Names.Count do
  begin
   if VarToStr(oSheet.Names.Item(i).Name).EndsWith('!Print_Area') then
   begin
     oSheet.PageSetup.PrintArea:='Print_area';
     Break;
   end;
  end;
end;

Var
  App,oWB,oSheet : OleVariant;
  i:Integer;
begin
  Result := False;
  App:= CreateOleObject('Excel.Application');
  Try
    App.Visible:= 0;
    oWb := App.WorkBooks.Open(ExpandUNCFileName(afilename),1);  // Open read only
    Try
     oSheet := oWB.ActiveSheet;
     RestoreOriginalPrintArea(oSheet);  // workaround
     oSheet.ExportAsFixedFormat(0,  //xlTypePDF is constant 0
                            aNewFileName,
                            0, // standard quality = 0, Max quality = 1
                            false, //include doc properties
                            false, //ignore print area
                            EmptyParam,
                            EmptyParam,
                            EmptyParam,
                            EmptyParam
                            );
    Finally
    End;
    Result := True;
  Finally
    oWB.Close(false); // better to close the WorkBook too
    App.Quit;
    App:= UnAssigned;
  End;
end;

现在我意识到使用此代码创建的 pdf 的行为类似于使用“忽略打印区域”选项从 Excel 保存到 pdf 时(这是从 Excel 功能导出到 pdf 的选项之一)。

所以我决定也从代码中“取消选中”该复选框,并研究了 ExportAsFixedFormat 的参数(引用 here)。

第五个参数是IgnorePrintAreas,所以我假设将 False 传递给它,打印区域将被忽略。

我尝试了几种常识性解决方案,包括:

  • 仅传递该参数(传递 True 或 False )
  • 传递所有前 5 个参数(以防它们在运行时是必需的)

但没有结果:我的应用程序创建的 pdf 仍然“忽略打印区域”。

有没有人有关于这个特定主题的建议或经验来指导我解决这个问题?

谢谢。

更新

感谢我将有用的已接受答案附加到解决方案上方的代码以供引用,请注意两件事:

  1. 包含解决方法的 RestoreOriginalPrintArea 过程
  2. 最后调用 oWB.Close(false)

最佳答案

错误的根本原因:

当使用自动化打开文件时,Excel 在非英语版本的应用程序中丢失打印区域设置。

为什么会这样:

当您在工作表中定义打印区域时,Excel 会在内部创建一个 named range .它有两个定义其名称的属性:

  1. Name 此属性始终采用 WorksheetsName!Print_Area 的形式(如果工作表的名称包含一些特殊字符,它也包含在单引号中)。
  2. NameLocal 具有相似的结构,但第二部分被翻译成应用程序的语言。

这就是当您在 Excel 中打开文件并在 VBA 中检查这些属性时的样子,但是当您使用自动化打开同一文件(例如使用有问题的代码)时,NameLocal 不再翻译。此错误导致命名范围无法被正确识别为打印区域。 oSheet.PageSetup.PrintArea 返回空字符串。

解决方法:

使用以下方法打开文件后恢复原始打印区域:

oSheet.PageSetup.PrintArea:='Print_Area';

当sheet中没有定义打印区域时,这行代码会抛出异常,所以有两种选择:

  1. 将此行放在 try..except block 中。
  2. 迭代 Names 集合并查找以 !Print_Area 结尾的 Name,例如:
var i:Integer;
for  i:= 1 to oSheet.Names.Count do
begin
  if  VarToStr(oSheet.Names.Item(i).Name).EndsWith('!Print_Area') then
  begin
    oSheet.PageSetup.PrintArea:='Print_area';
    Break;
  end;
end;

其他重要变化:

因为文件可能已被修改,您还需要添加:

oWB.Close(false);//不保存更改

在关闭应用程序之前,否则每次调用此函数都会导致另一个 Excel 进程仍在运行而不可见。

关于delphi - ExportAsFixedFormat 的 IgnorePrintAreas 参数好像没有效果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71379893/

相关文章:

delphi - 在Delphi中将HBitmap转换为字节数组

delphi - 从 TImageList 保存透明(alpha channel )PNG

windows - 在 Windows 7 64 位上从 Delphi 7 读取注册表时出现问题

pdf - 将 eps 图像转换为 pdf 时如何避免灰色轮廓伪影?

excel - HRESULT : 0x800A03EC when setting value of a cell (through Powershell) 的异常

Delphi:类似 FireFox 中的 AnimateWindow

character-encoding - 使用 Rebol 3 执行文件编码转换

java - com.sun.star.lang.IllegalArgumentException - 不支持的 URL <文件 :///

excel - 在 Delphi 中检测 Excel 的版本

wcf - 使用 Excel 在 WCF mex Moniker 上调用方法时出现自动化错误