2008年7月14日

Adobe Readerで指定したファイルの指定したページを開く

2017/03/07追記: Adobe Acrobat/Reader X以降でDDEのサービス名が変更になったことに対応したアーティクルを作成しましたので、そちらをご覧ください。
Adobe Reader(X以降)で指定したファイルの指定したページを開く

PDFファイルの任意のページをプログラムから開くときは、Adobe Readerのパスをレジストリから取得し、DDEでキックしてからDocOpenでPDFを開きDocGotoで所定のページに移動する、というマクロを実行します。
uses
{$IFDEF Unicode}
  AnsiStrings,
{$ENDIF}
  Windows, SysUtils, DdeMan, Registry;

function GetAdobeReader: String;
begin

  with TRegistry.Create do
  begin
    try
      RootKey := HKEY_CLASSES_ROOT;
      OpenKeyReadOnly('Software\Adobe\Acrobat\Exe');
      try
        Result := ReadString('');

      finally
        CloseKey;
      end;

    finally
      Free;
    end;
  end;

end;


procedure OpenPDF(const Filename: String; Page: Integer);
const
  CDdeCommand: AnsiString = '[DocOpen("%s")][DocGoTo(NULL,%d)]';
var
  Macro: AnsiString;
begin

  Macro := Format(CDdeCommand,[Filename,Page - 1]);

  with TDdeClientConv.Create(nil) do
  begin
    try
      ConnectMode := ddeManual;
      ServiceApplication := ChangeFileExt(GetAdobeReader,'');
      SetLink('Acroview','Control');
      if OpenLink = True then
      begin
        ExecuteMacro(PAnsiChar(Macro),False);
        CloseLink;
      end;

    finally
      Free;
    end;
  end;

end;

Adobe Readerの所在は"HKEY_CLASSES_ROOT\Software\Adobe\Acrobat\Exe"から取得する(これが一番確実)、Adobe ReaderはDDEで呼び出してマクロ実行でファイルを開きページを移動する、DelphiのTDdeClientConvには不具合があるので使用する都度生成しないと正常に動作しない、といったところが注意点ですかね。

2008/08/16追記: AnsiString版のFormatを使用するようにコードを修正しました。

2009/03/17再追記: Adobe Acrobat/ReaderのDDEコマンドなどを定義した"Interapplication Communication API Reference"(アプリケーション間通信APIリファレンス)がAdobeのサイトにあります(英語ですが)。
Adobe Acrobat 7.0.5 Acrobat Interapplication Communication Reference
Adobe Acrobat SDK Version 8.0 Interapplication Communication API Reference

2017/03/05追記: おかぽんさんからAcrobat X以降では仕様の変更があったという情報をコメントでいただきました。調査してわかったことがありましたら追記します。(Bloggerはコメントが見づらいのでここに追記しておきます。おかぽんさん、情報ありがとうございました。)

5 件のコメント:

おかぽん さんのコメント...

こんにちは。
当方 delphi使いのため、こちらにコメント残させていただきます。

DDEを使った方法ですが、Acrobat X から、DDEのサービス名が変更されています。

> Acroview{A|R}{MajorVersion} where {A|R} refer to Acrobat and Reader respectively.
> For example, the name is AcroViewA10 for Acrobat X and AcroViewR10 for Reader 10.
Big Changes in the DDE Naming Convention for Acrobat X
http://blogs.adobe.com/pdfdevjunkie/2011/01/big-changes-in-the-dde-naming-convention-for-acrobat-x.html
より引用

'Acroview' で記載されたページが多く、「動かない!」と悩みまくった結果が、上記仕様の変更だったようで。

ちなみに、"HKEY_CLASSES_ROOT\Acrobat\Shell\Open\ddeexec\application" に DDEサービス名が
記載されているように見えますが、うちの環境には、Acrobat Reader XI がインストールされているので、
'AcroviewR11'である必要があるのですが、なぜか 'AcroviewR10' となっていて、混乱中。
実際、DDEサービス名が 'AcroviewR11' でないと動作しません。

Reader X から Reader XI に変えた場合、変わらないのかもしれませんが未検証です。

ふー さんのコメント...

おかぽんさん、こんにちは。
Acrobat Readerの仕様変更の件、こちらでも調べてみます。情報ありがとうございました。

ふー さんのコメント...

手元のReader XIでも "HKEY_CLASSES_ROOT\acrobat\shell\open\ddeexec\application" には "AcroViewR10" が格納されています。何らかの方法でReaderのバージョンを取得しないとDDEのサービス名が確定できない、ということですよね。うーん。

ふー さんのコメント...

同じく手元のReader DCでも "AcroViewR10" ですね。DCでは "AcroViewR12" が必要なんですよね?これはexeのバージョン情報を見るしかないと思います。

おかぽん さんのコメント...

今週、ちょっと忙しくてレスできませんでした。
新しい記事の投稿、お疲れ様です。
私は、2/23のコメント後、ふーさん同様、exeのバージョン情報にたどり着き、動くようにできました。
が、今後のバージョンアップで、どのように変わるかわかりませんし、注意が必要そうですね。