【问题标题】:Name conflict in Excel files by OLEOLE 在 Excel 文件中的名称冲突
【发布时间】:2020-09-22 13:36:32
【问题描述】:

开发从 Excel 文件转换为 PDF 的程序。这是我的代码:

  procedure ExcelToPDF(const InputFileName, OutputFileName: string);
  var
    Excel: Variant;
    Workbook: Variant;
  begin
    try
      CoInitializeEx(nil, 0);

      //Открытие Excel
      Excel := CreateOleObject('Excel.Application');
//      Excel.Application.EnableEvents := False;
      Excel.Application.DisplayAlerts := False;
      Excel.Visible := False;

      if not VarIsNull(Excel) then
      begin
        //Открытие файла
        Workbook := Excel.Workbooks.Open(InputFileName);
        //Сохранение в PDF
        Workbook.ExportAsFixedFormat(xlTypePDF, OutputFileName);        

        Writeln('OK');
      end
      else
      begin
        raise Exception.Create('Не удалось открыть Excel');
      end;
    finally
      if not VarIsNull(Excel) then
      begin
        Excel.Quit;
        Excel := 0;
      end;
    end;
  end;

它工作正常,但是对于某些工作簿,当程序尝试打开工作簿时会出现错误输入对话框(另请查看屏幕截图):

名称冲突
名称不能与内置名称相同。
旧名称:Print_Area
新名称:
确定 取消

旧名称可以是 Print_Area 或 _FilterDatabase 或其他名称。这是非常常见的错误,但我没有找到真正的解决方案。但关键问题在这里:当我自己在 Excel 中打开问题工作簿时,它可以正常工作而没有任何对话框,只有当我通过 OLE 在我的程序中打开它时才会出现。如果在 OLE 中我们只使用 Excel 怎么办?那么也许 Excel 用其他参数打开文件?我正在试验 Open 方法参数,但没有。

【问题讨论】:

  • 您是否发现了工作簿中产生错误的具体内容?你能提供这样的工作簿供下载吗?最后,能否使用调试器查看您的源代码行中的哪一行触发了错误?
  • 工作簿中的问题 := Excel.Workbooks.Open(InputFileName);我在 Internet 上发现了一些具有相同问题的随机文件并对其进行了测试。可以通过链接下载:easyupload.io/wary4j
  • Excel 2019 不想加载您的文件。错误信息是(或多或少:从法语翻译而来):“对不起...我们发现 testbug.xlsb 的内容有问题,但我们可以尝试尽可能多地取回内容。如果您对来源,单击是”。我已经取消了...
  • 基于错误,我相信您的 excel 文件中有多个同名对象。默认情况下这是不可能的,因为 Excel 作为程序会阻止您为多个对象提供相同的名称。但是,如果上述 excel 文件是通过某种自动化构建的,则可能没有遵循不给多个对象赋予相同名称的规则。
  • 你观察到的名字是Reserved Names in Excel。它们是通过激活 Excel 中的特定功能自动创建的。不过,我不知道他们为什么会引起冲突。有一个 similar (unresolved) question 表示您可以通过 Office 互操作打开此类工作簿,但不能通过 OLE 自动化。

标签: excel delphi ole


【解决方案1】:

感谢您的所有 cmets。我找到了解决方案。在 VBA 中有 GetObject 函数。我在 Internet Delphi 实现中找到了它。就是这样:

  function GetObject(const AFileName: TFileName): IDispatch;
  var
    vDispatch : IDispatch;
    vBindCtx : IBindCtx;
    vMoniker : IMoniker;
    vChEaten : Integer;
  begin
    Result := nil;
    vDispatch := nil;
    vBindCtx := nil;
    if CreateBindCtx(0, vBindCtx) = S_OK then
    begin
      vMoniker := nil;
      if MkParseDisplayName(vBindCtx, PWideChar(WideString(AFileName)),
        vChEaten, vMoniker) = S_OK then
      begin
        if vMoniker.BindToObject(vBindCtx, nil, IDispatch, vDispatch) = S_OK then
          Result := vDispatch;
      end;
    end;
  end;

所以,而不是这两行:

Excel := CreateOleObject('Excel.Application');
Workbook := Excel.Workbooks.Open(InputFileName);

只使用一个:

Workbook := GetObject(InputFileName);

【讨论】:

    猜你喜欢
    • 2018-07-04
    • 2011-07-26
    • 2019-01-23
    • 1970-01-01
    • 2014-10-14
    • 1970-01-01
    • 2017-10-31
    • 2023-02-10
    • 1970-01-01
    相关资源
    最近更新 更多