Delphi:以编程方式在PDF中的指定目的地打开PDF(Sumatra,Foxit和Adobe)文件

时间:2014-01-20 15:07:55

标签: delphi pdf named

我是开源项目的主要开发人员(http://nbcgib.uesc.br/lec/software/editores/tinn-r/en)。

现在项目的用户指南是PDF格式(在LaTeX下制作)。

我正在尝试制作一个程序,以编程方式在PDF 中的指定目的地/部分打开用户指南。

由于我不知道用户的默认PDF查看器,我正在开发一个支持专业的程序:Sumatra,Foxit和Adobe。

该程序适用于苏门答腊岛,但不适用于Foxit和Adobe。

代码下方:

function GetAssociation(const DocFileName: string): string;
var
  FileClass: string;
  Reg: TRegistry;

begin
  Result:= '';
  Reg:= TRegistry.Create(KEY_EXECUTE);
  Reg.RootKey:= HKEY_CLASSES_ROOT;
  FileClass:= '';
  if Reg.OpenKeyReadOnly(ExtractFileExt(DocFileName)) then
  begin
    FileClass:= Reg.ReadString('');
    Reg.CloseKey;
  end;
  if FileClass <> '' then begin
    if Reg.OpenKeyReadOnly(FileClass +
                           '\Shell\Open\Command') then
    begin
      Result:= Reg.ReadString('');
      Reg.CloseKey;
    end;
  end;
  Reg.Free;
end;

procedure TfrmTinnMain.OpenUserGuidePDF(sWhere: string);
var
  sFile,
   sViewerDefault,
   sParameter: string;

begin
  sViewerDefault:= GetAssociation('.pdf');

  if pos('Sumatra',                     // Sumatra: OK
         sViewerDefault) > 0 then
    sParameter:= '-reuse-instance ' +
                 '-named-dest ' +
                 sWhere
  else if pos('Foxit',                  // Foxit: opens the file, but not at the named destination
              sViewerDefault) > 0 then
    sParameter:= '/A ' +
                 'page=100'
  else if pos('Adobe',                  // Adobe: opens the file, but not at the named destination
              sViewerDefault) > 0 then begin
    sWhere:= StringReplace(sWhere,
                           '"',
                           '',
                           [rfReplaceAll]);

    sParameter:= '/A ' +
                 '"' +
                 'nameddest=' +
                 sWhere +
                 '"';
  end
  else
    sParameter:= '';

  sFile:= sPathTinnR +
          '\doc\User guide.pdf';
  try
    // Open PDF viewer
    ShellExecute(0,
                 'open',
                 Pchar(sFile),
                 Pchar(sParameter),
                 nil,
                 sw_shownormal);

  except
    MessageDlg('PDF viewer is not accessible!',
               mtInformation,
               [mbOk],
               0);
  end;
end;

procedure TfrmTinnMain.menHelUserGuideClick(Sender: TObject);
begin
  OpenUserGuidePDF('"Contents"');
end;

2 个答案:

答案 0 :(得分:0)

我要感谢所有观察和建议!

我发现(与Tinn-R联合)分发便携版SumatraPDF更实际。 如果苏门答腊是系统默认值,它将被使用。否则,将使用便携版。

在计算解决方案之下:

procedure TfrmTinnMain.OpenUserGuidePDF(sWhere: string);
var
  sFile,
   sViewerDefault,
   sPathSumatra,
   sParameter: string;

begin
  sFile:= sPathTinnR +
          '\doc\User guide.pdf';

  sParameter:= '-reuse-instance ' +
               '-named-dest ' +
               sWhere;
  try
    sViewerDefault:= GetAssociation('.pdf');

    if pos('Sumatra',
           sViewerDefault) > 0 then
      // Open default PDF viewer
      ShellExecute(0,
                   'open',
                   Pchar(sFile),
                   Pchar(sParameter),
                   nil,
                   sw_shownormal)
    else begin
      sPathSumatra:= sPathTinnR +
                     '\sumatra\SumatraPDF.exe';

      // Open SumatraPDF viewer
      OpenCmdLine(sPathSumatra +
                  ' "' +
                  sFile +
                  '"' +
                  sParameter,
                  sw_shownormal);
    end;
  except
    MessageDlg('PDF viewer is not accessible!',
               mtInformation,
               [mbOk],
               0);
  end;
end;

电话:

procedure TfrmTinnMain.menHelUserGuideClick(Sender: TObject);
begin
  OpenUserGuidePDF('"Contents"');
end;

必要的功能和程序:

{ Execute a complete shell command line without waiting. }
function OpenCmdLine(const CmdLine: string;
                     wWindowState: Word): Boolean;
var
  sUInfo: TStartupInfo;
  pInfo : TProcessInformation;

begin
  { Enclose filename in quotes to take care of long filenames with spaces. }
  FillChar(sUInfo,
           SizeOf(sUInfo),
           #0);
  with SUInfo do
  begin
    cb         := SizeOf(sUInfo);
    dwFlags    := STARTF_USESHOWWINDOW;
    wShowWindow:= wWindowState;
  end;
  Result:= CreateProcess(nil,
                         PChar(CmdLine),
                         nil,
                         nil,
                         False,
                         CREATE_NEW_CONSOLE or
                         NORMAL_PRIORITY_CLASS,
                         nil,
                         nil {PChar(ExtractFilePath(sFileName))},
                         sUInfo,
                         pInfo);
end;

function GetAssociation(const DocFileName: string): string;
var
  FileClass: string;
  Reg: TRegistry;

begin
  Result:= '';
  Reg:= TRegistry.Create(KEY_EXECUTE);
  Reg.RootKey:= HKEY_CLASSES_ROOT;
  FileClass:= '';
  if Reg.OpenKeyReadOnly(ExtractFileExt(DocFileName)) then
  begin
    FileClass:= Reg.ReadString('');
    Reg.CloseKey;
  end;
  if FileClass <> '' then begin
    if Reg.OpenKeyReadOnly(FileClass +
                           '\Shell\Open\Command') then
    begin
      Result:= Reg.ReadString('');
      Reg.CloseKey;
    end;
  end;
  Reg.Free;
end;

欢迎任何建议!

一切顺利,

J.C.Faria

答案 1 :(得分:-1)

让Windows决定该文件类型的默认查看器:

ShellExecute(0, 'open', Filename, nil, nil, SW_SHOW);