AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Kontextsensitive Hilfe aus Programm zu PDF

Ein Thema von TiGü · begonnen am 3. Nov 2015 · letzter Beitrag vom 4. Dez 2015
Antwort Antwort
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.060 Beiträge
 
Delphi 10.4 Sydney
 
#1

Kontextsensitive Hilfe aus Programm zu PDF

  Alt 3. Nov 2015, 13:56
Hallo zusammen,

ich betreue eine Handvoll alte Programme in Delphi 2007.
Bisher liegt auf jeden Formular ein Button für kontextsensitive Hilfe.
Drückt der User darauf, öffnet sich die zum Formular passende Seite in der CHM-Datei.

Realisiert wurde das damals mit der Komponente TContextHelp 1.0 von Easycash Software (gibts nicht mehr).
Diese Komponente wiederum verwendet THelpRouter von EC Software (http://www.helpandmanual.com/downloads_delphi.html).
Am Ende wird HtmlHelp aus der Windows-Unit aufgerufen und die CHM-Datei öffnet sich an der korrekten Position.

Meine Frage:
Gibt es die Möglichkeit, derartige Verlinkungen auch zu einen PDF-Dokument zu machen?
Wenn ja, wie würde sowas aussehen?
Man müsste auch Stichwort/Überschriften-spezifisch arbeiten können, weil die Doku sich zukünftig erweitern kann und man daher nicht "Öffne Seite 73" zum einen PDF-Reader mit ShellExecute sagen darf.

Hintergrund:
Unsere Dokumentationsabteilung verwendet zur Erstellung der Hilfe Microsoft Word und leider kein Tool wie Help+Manual.
Das Erstellen einer PDF aus den Word-Dokument geht natürlich problemlos, nur das Konvertieren in eine CHM-Datei scheint einige Mühe zu machen und Zeit zu kosten.

Ich bin für Ideen, Code-Schnipsel, Links zum Weiterlesen und/oder Erfahrungsberichte dankbar!
  Mit Zitat antworten Zitat
Benutzerbild von Neutral General
Neutral General

Registriert seit: 16. Jan 2004
Ort: Bendorf
5.219 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#2

AW: Kontextsensitive Hilfe aus Programm zu PDF

  Alt 3. Nov 2015, 16:06
Ich habe sowas vor Kurzem von Hand gemacht. Habe die PDF selbst eingelesen/geparst und die benötigte Seitennummer rausgelesen und dann die PDF auf dieser Seite mit dem Acrobatreader geöffnet (geht über die Kommandozeile bzw. CreateProcess).

Wenn du die Seite schon weißt, dann kannst du die PDF ja wie oben genannt einfach aufrufen.
Michael
"Programmers talk about software development on weekends, vacations, and over meals not because they lack imagination,
but because their imagination reveals worlds that others cannot see."
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.110 Beiträge
 
Delphi 10 Seattle Enterprise
 
#3

AW: Kontextsensitive Hilfe aus Programm zu PDF

  Alt 3. Nov 2015, 16:41
Oh, so etwas habe ich für die nächsten Tage auch auf der Agenda. Mein Plan war einfach die Bedienungsanleitung als PDF abzulegen und im passenden Kapitel aufzuschlagen.

Ich hänge dir mal eine Liste der Adobe Aufrufparameter an, keine Ahnung mehr wo ich das herhatte.

Ansonsten hier einmal was ich irgendwann einmal angefangen hatte. Das geht allerdings fest auf den Adobe-Reader da wir nur fertige Systeme ausliefern und den vorinstalllieren. Mit einem beliebigen PDF-Viewer kann man das natürlich nicht verwenden.

Delphi-Quellcode:
unit PdfViewer experimental;

interface

type

   TParams = record
      public type
         TPageMode = (none, bookmarks, thumbs);
      public var
         forceNewInstance:   Boolean;
         filePath:         String;

         startPage:         Word;
         pageMode:         TPageMode;

         /// <remarks>
         /// Scheint in Acrobat Reader DC keine Auswirkung zu haben sondern
            /// sich die Einstellung für jedes Dokument einzeln zu merken
            /// </remarks>
         showToolbar:      Boolean;
         showStatusBar:      Boolean;
         showNavPanes:      Boolean;
      public
         procedure reset();
    end;

    {TODO -oJM -cCleanup : Umbenennen in TAcroLauncher oder sowas}
   TPdfViewer = class(TObject)
      protected
         class function getCmdLineArguments(const forParams: TParams): PChar; virtual;
      public const
         executableName   =   'AcroRd32';
      public
         class procedure ShowAsync(const params: TParams); virtual;
   end;

implementation uses
   System.SysUtils, System.Types,
   WinApi.ShellApi, WinApi.Windows,
   Spring.Utils
;


type
   /// <summary>
   /// Schreibt Booleans als '0' oder '1'
   /// </summary>
   TStringBuilderHelper = class helper for System.SysUtils.TStringBuilder
      function Append(const Value: Boolean): TStringBuilder; overload;
   end;


{ TPdfViewer }

class procedure TPdfViewer.ShowAsync(const params: TParams);
var
   info: SHELLEXECUTEINFO;
begin
   info := Default(SHELLEXECUTEINFO);
   info.cbSize := SizeOf(SHELLEXECUTEINFO);

   info.fMask := SEE_MASK_DEFAULT;
   info.lpVerb := 'open';
   info.lpFile := executableName;
   info.nShow := SW_SHOWNORMAL;

   info.lpParameters := getCmdLineArguments(params);
   Win32Check( ShellExecuteEx( Addr(info)) );
end;

class function TPdfViewer.getCmdLineArguments(const forParams: TParams): PChar;
var
   stringBuilder: TStringBuilder;
begin
   stringBuilder := TStringBuilder.Create();
   try
      if forParams.forceNewInstance then stringBuilder.Append('/n ');
        stringBuilder.Append('/A ');

      stringBuilder
         .Append('"')
         .Append('page=')      .Append(forParams.startPage)
         .Append('&toolbar=')   .Append(forParams.showToolbar)
         .Append('&statusbar=')   .Append(forParams.showStatusBar)
         .Append('&navpanes=')   .Append(forParams.showNavPanes)
         .Append('&pageMode')   .Append( TEnum.GetName(forParams.pageMode) )
         .Append('"').Append(Space);

      stringBuilder.Append('"').Append(forParams.filePath).Append('"');

      Result := PChar( stringBuilder.ToString() );
   finally
      stringBuilder.Destroy();
    end;
end;

{ TParams }

procedure TParams.reset();
begin
   filePath := EmptyStr;
   startPage := 1;
   showToolbar := False;
   showStatusBar := False;
   showNavPanes := False;
   forceNewInstance := True;
   pageMode := TPageMode.none;
end;

{ TStringBuilderHelper }

function TStringBuilderHelper.Append(const Value: Boolean): TStringBuilder;
begin
   Result := Append( Value.ToString(TUseBoolStrs.False) );
end;

end.
Angehängte Dateien
Dateityp: pdf pdf_open_parameters (1).pdf (106,2 KB, 17x aufgerufen)
  Mit Zitat antworten Zitat
BenjaminH

Registriert seit: 14. Okt 2004
Ort: Freiburg im Breisgau
713 Beiträge
 
Turbo Delphi für Win32
 
#4

AW: Kontextsensitive Hilfe aus Programm zu PDF

  Alt 3. Nov 2015, 16:44
Eventuell kann man statt das manuell zu parsen schauen, wie synctex (nach pdflatex + synctex googlen) das macht.
Dann muss man die Hilfedateien halt mit Latex erzeugen, dadurch werden die aber eh besser.
Benjamin
  Mit Zitat antworten Zitat
Benutzerbild von Dalai
Dalai

Registriert seit: 9. Apr 2006
1.680 Beiträge
 
Delphi 5 Professional
 
#5

AW: Kontextsensitive Hilfe aus Programm zu PDF

  Alt 3. Nov 2015, 17:43
Wenn ich mir das von Neutral General verlinkte PDF von Adobe so anschaue, müsste das mit Named Destinations machbar sein, ggf. in Verbindung mit Bookmarks/Lesezeichen. Ich würde auf jeden Fall davon Abstand nehmen, programmspezifische Parameter zu benutzen, also z.B. solche, die nur im Adobe Reader funktionieren, denn wer sagt denn, dass dieser in jedem Fall installiert und/oder das Standardprogramm für PDFs ist?

MfG Dalai
  Mit Zitat antworten Zitat
zeras

Registriert seit: 11. Mär 2007
Ort: Saalkreis
1.618 Beiträge
 
Delphi 12 Athens
 
#6

AW: Kontextsensitive Hilfe aus Programm zu PDF

  Alt 3. Nov 2015, 19:04
Wenn ich mir das von Neutral General verlinkte PDF von Adobe so anschaue, müsste das mit Named Destinations machbar sein
..

MfG Dalai
Ich habe für unsere Firma ein Programm geschrieben, womit man Named Destination erzeugen kann. Das sind sogenannten Ziele in einer PDF Datei.
Man nimmt einfach eine PDF Datei und die durchsuche ich nach bestimmten Merkmalen. Wenn ich ein solches Merkmal gefunden habe, mache ich ein "Ziel" draus und schon kann man dies von außen anspringen.
Geht ganz gut für unsere Steuerung, wenn man beispielsweise ein Hilfe integrieren will.
Gemacht alles mit quickpdf/ Kostet zwar einiges, ist aber jeden Cent wert.
Matthias
Es ist nie falsch das Richtige zu tun!
- Mark Twain
  Mit Zitat antworten Zitat
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.060 Beiträge
 
Delphi 10.4 Sydney
 
#7

AW: Kontextsensitive Hilfe aus Programm zu PDF

  Alt 4. Nov 2015, 10:32
Wenn ich mir das von Neutral General verlinkte PDF von Adobe so anschaue, müsste das mit Named Destinations machbar sein, ggf. in Verbindung mit Bookmarks/Lesezeichen. Ich würde auf jeden Fall davon Abstand nehmen, programmspezifische Parameter zu benutzen, also z.B. solche, die nur im Adobe Reader funktionieren, denn wer sagt denn, dass dieser in jedem Fall installiert und/oder das Standardprogramm für PDFs ist?
Das mit den "Named Destinations" sieht interessant und auch praktikabel aus, gerade in Hinblick auf verschiedene PDF Reader.

Kann ich mir das vereinfacht so vorstellen, dass der Ersteller der PDF irgendwie zu den jeweiligen Themen eine "Named Destination" erstellt und ich dann per ShellExecute die PDF mit den dafür registrierten Programm öffne und durch den "Named Destinations"-Parameter springt das Ganze zur passenden Stelle?
Delphi-Quellcode:
ShellExecute(Application.Handle,
                 'open',
                 PChar('C:\TestPath\myfile.pdf#nameddest=custom1'),
                 nil, nil, SW_NORMAL)
  Mit Zitat antworten Zitat
Benutzerbild von Dalai
Dalai

Registriert seit: 9. Apr 2006
1.680 Beiträge
 
Delphi 5 Professional
 
#8

AW: Kontextsensitive Hilfe aus Programm zu PDF

  Alt 4. Nov 2015, 11:42
Kann ich mir das vereinfacht so vorstellen, dass der Ersteller der PDF irgendwie zu den jeweiligen Themen eine "Named Destination" erstellt und ich dann per ShellExecute die PDF mit den dafür registrierten Programm öffne und durch den "Named Destinations"-Parameter springt das Ganze zur passenden Stelle?
So stelle ich mir das ebenfalls vor. Wie aber die Named Destinations erstellt werden können, weiß ich mangels Erfahrung mit PDF leider nicht zu sagen. Eine kurze Suche gestern hat aber einige Ergebnisse zutage gefördert. Es kann sein, dass man diese Dinger nur mit Löhnware hinbekommt (weiß nicht, ob das ein (K.O.)Kriterium für das Vorhaben ist).

MfG Dalai
  Mit Zitat antworten Zitat
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.060 Beiträge
 
Delphi 10.4 Sydney
 
#9

AW: Kontextsensitive Hilfe aus Programm zu PDF

  Alt 4. Nov 2015, 12:56
Es kann sein, dass man diese Dinger nur mit Löhnware hinbekommt (weiß nicht, ob das ein (K.O.)Kriterium für das Vorhaben ist).
Das würde gehen, weil es in der Doku-Abteilung eine Lizenz für den Adobe Acrobat gibt, mit dem bisher die PDFs erstellt und bearbeitet werden.
Ich halte mal Rücksprache und berichte dann.
  Mit Zitat antworten Zitat
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.060 Beiträge
 
Delphi 10.4 Sydney
 
#10

AW: Kontextsensitive Hilfe aus Programm zu PDF

  Alt 4. Dez 2015, 13:58
Heute endlich eine PDF mit Named Destinations von der Doku-Abeteilung bekommen.
Ich dachte ich bekomme es gar nicht hin, aber jetzt ist der Knoten geplatzt.
Also grundsätzlich gehts!

Der folgende Quellcode ist nicht schön, funktioniert aber soweit und sucht auch selbstständig den aktuell eingestellten PDF-Reader raus.
Getestet mit den neusten FoxIt- und Acrobat Reader.

Delphi-Quellcode:
uses
  System.Win.Registry, Winapi.ShellApi;

const
  NAMED_DESTINATION_PREFIX = '/A "nameddest=';
  REG_SHELL_OPEN_COMMAND = '\Shell\Open\Command';
  COMMAND_OPEN = 'open';

function GetAssociation(const DocFileName: string): string;
var
  FileExtension : string;
  FileClass: string;
  Reg: TRegistry;
begin
  Result := '';
  Reg := TRegistry.Create(KEY_EXECUTE);
  try
    Reg.RootKey := HKEY_CLASSES_ROOT;
    FileClass := '';
    FileExtension := ExtractFileExt(DocFileName);
    if Reg.OpenKeyReadOnly(FileExtension) then
    begin
      FileClass := Reg.ReadString('');
      Reg.CloseKey;
    end;

    if FileClass <> 'then
    begin
      if Reg.OpenKeyReadOnly(FileClass + REG_SHELL_OPEN_COMMAND) then
      begin
        Result := Reg.ReadString('');
        Reg.CloseKey;
      end;
    end;
  finally
    Reg.Free;
  end;
end;

procedure DoOpenPDF(const PDFReader, FileName, NamedDestination: string);
var
  ExecuteResult: HINST;
  Parameters: string;
begin
  Parameters := NAMED_DESTINATION_PREFIX + NamedDestination + '" "' + FileName + '"';

  ExecuteResult := ShellExecute(
    Application.Handle,
    COMMAND_OPEN,
    PChar(PDFReader),
    PChar(Parameters),
    nil,
    SW_NORMAL
    );

  if ExecuteResult < 32 then
    RaiseLastOSError;
end;

procedure OpenPDF(const FileName: string; const NamedDestination: string = '');
var
  PDFReader: string;
begin
  PDFReader := GetAssociation('.pdf'); // 'FoxitReader.exe'; //'AcroRd32.exe';
  PDFReader := ExtractFileName(PDFReader);
  PDFReader := PDFReader.Replace('" "%1"', '', [rfReplaceAll, rfIgnoreCase]);

  DoOpenPDF(PDFReader, FileName, NamedDestination);
end;
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:00 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz