2014-01-20 2 views
0

Я являюсь основным разработчиком проекта с открытым исходным кодом (http://nbcgib.uesc.br/lec/software/editores/tinn-r/en).Delphi: Откройте файл PDF (Sumatra, Foxit и Adobe) программно в названии адресата в формате PDF

Теперь руководство пользователя по проекту находится в формате 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; 
+0

Что ваш вопрос? –

+1

Каким образом это не «работает нормально»? Что вы ожидаете от программы, и что происходит вместо этого? Что вы узнали из отладчика? –

+0

PDF - очень плохой выбор для онлайн-справочной службы. –

ответ

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

+0

У вас много проблем с вашим кодом. Для начала второй параметр CreateProcess должен быть доступен для записи. Ваш код завершится неудачей с литералом в сборке Unicode. Используйте UniqueString, чтобы сделать этот параметр модифицируемым. Вам нужно использовать try/finally для защиты объектов. Например, экземпляр TRegistry. Ваш вызов CreateProcess устраняет дескрипторы, возвращаемые в параметре info процесса. –

-1

Пусть Windows, решить, что зритель по умолчанию для этого типа файла является:

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

-1 Пользователь хочет перейти в определенное место в документе –

+1

@DavidHeffernan Вы правы, это было слишком быстро – jpfollenius

+0

Я знаю этот общий вызов для ShellExecute. Но я хочу быть более конкретным: я хочу открыть руководство пользователя (Sumatra, ** Foxit ** и ** Adobe **) в любом конкретном именованном месте назначения. Например: «База данных», «Конфигурация» и т. Д. Процедура уже работает для Суматры, но не для Foxit и Adobe Reader. – jcfaria

Смежные вопросы