Pdfの指定ページを開く

タグの編集
投稿者 Na  (社会人) 投稿日時 2010/6/15 10:07:05
VB(Visual Studio2008)でPdfファイルを関連付けされたアプリケーションで開く際に
ページを指定して開きたいです。

現在は、以下コードでPdfは開くのですが、ペース数を指定して開く方法がわかりません。
ネット検索すると、html内ではファイル名の後に#page=4等でページ数を指定可能との
記述がありましたが、
Link = "D:\Test\Test.pdf"
行を
Link = "D:\Test\Test.pdf#page=4"
のように変えてもダメでした。

よい方法があればご教授ください。

Public Class Form1

    Declare Function GetDesktopWindow Lib "user32" () As Integer
    Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" _
    (ByVal hWnd As Integer, ByVal lpOperation As String, ByVal lpFile As String, _
    ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Integer) As Integer

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Const SW_NORMAL As Integer = 5
        Dim L As Integer
        Dim Link As String

        Link = "D:\Test\Test.pdf"
        L = ShellExecute(GetDesktopWindow, "open", Link, vbNullString, vbNullString, SW_NORMAL)
        If L <= 31 Then
            Dim Msg As String
            Msg = "pdfファイルに関連づけられたアプリケーションが見つかりません"
            MsgBox(Msg, vbOKOnly + vbExclamation)
        End If

End Sub
End Class
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2010/6/15 10:58:11
ShellExecute API を使うぐらいなら、Process クラスを使った方がスマートだと思いますよ。
ただ、それで解決するかどうかは別問題ですけれども。

> Link = "D:\Test\Test.pdf#page=4"
ShellExecute(Ex) や Process.Start でパラメータを渡す場合には、"#" でパラメータを繋ぐのではなく、
 ShellExecute の場合: lpParameters 引数
 ShellExecuteEx の場合: SHELLEXECUTEINFO.lpParameters フィールド
 Process.Start(String, String) の場合: arguments 引数
 Process.Start(ProcessStartInfo) の場合: ProcessStartInfo.Arguments プロパティ
などでパラメータを渡すようにします。 
 
ただし、そのパラメータがどのように利用されるのかは、*.pdf に関連付けられた
アプリケーション(Adobe Reader、Foxit Reader、Sumatra PDF 等々)に依存しています。

その結果、○○ というPDF リーダーならば***のようにすれば表示できるが、
++ というPDF リーダーでは、ページ指定は不可能…といった事態が生じえるため、
そもそも汎用的な方法という物は存在しませんし、PDF リーダーごとに異なる処理が必要です。

なお、Adobe Reader がサポートしているコマンドラインには、下記の物がありますが、
ページ番号の指定方法は見当たりませんでした(他の PDF リーダーについては未調査です)。
http://kb2.adobe.com/jp/cps/510/510705.html


> よい方法があればご教授ください。
ちなみに、Acrobat Reader コントロール (AcroPDF.DLL) を用いた場合には、
下記のようにして、フォーム上に PDF を表示させる事もできます。

AxAcroPDF1.LoadFile("D:\Test\Test.pdf")
AxAcroPDF1.setCurrentPage(4)
投稿者 Na  (社会人) 投稿日時 2010/6/15 19:40:23
早速の回答ありがとうございます。

ShellExecute等のパラメータとして、ページ数を指定しても、
PDFの表示アプリによって、パラメータが様々なので、簡単には実現できない
ということですね...

>ちなみに、Acrobat Reader コントロール (AcroPDF.DLL) を用いた場合には、
>下記のようにして、フォーム上に PDF を表示させる事もできます。

こちらの方法を試みたんですが、うまく動作しません。

[プロジェクト]メニューのプロジェクト名のプロパティの参照タブに、AcroPDF.DLLを追加して、

以下のコードを記述したのですが、エラーは出ませんがなにも表示されません。
どうすれば表示できるのでしょうか?

Public Class Form1

    Private Sub Form1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Click
        Dim AxAcroPDF1 As New AcroPDF

        AxAcroPDF1.LoadFile("D:\Test\Test.pdf")
        AxAcroPDF1.setCurrentPage(4)
    End Sub

End Class
投稿者 (削除されました)  () 投稿日時 2010/6/15 22:50:56
(削除されました)
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2010/6/15 22:53:36
> どうすれば表示できるのでしょうか?
ツールボックスを右クリックしてアイテムを追加した上で、
AxAcroPDF コントロールをフォーム上に貼りつけて利用して下さい。
投稿者 Na  (社会人) 投稿日時 2010/6/16 09:22:47
回答ありがとうございます。

ツールボックスからコントロールとして追加するんですね...

無事表示するようになりました。

後は、AcroPDF.DLLに配布条件があるようなので、
そちらを調べてみます。

ありがとうございました。
投稿者 Na  (社会人) 投稿日時 2010/6/16 11:26:39
ちょっと問題が発生しました。

AcroPDF.DLLを使用して、表示できるようになったのですが、
Adobe Readerがインストールされていないと、ページ指定以前に表示が出来ません。
#試しにFoxit Readerをインストールしてみましたがこれもダメでした。

結局Adobe Readerが必要であれば、こちらとしては、
Adobe Reader必須ということでReaderを指定しても構いません。

そこで、最初のShellExecuteを使用した場合に、
Adobe Reader限定で良いのでページ指定可能なオプションの指定方法が知りたいです。

下記のように、lpParametersに"page=4"と指定しましたが、ページ指定が
効きませんでした。

具体的な指定方法を教えてください。

Const SW_NORMAL As Integer = 5
Dim L As Integer
Dim Link As String
Dim Para As String

Link = "D:\Test\Test.pdf"
Para = "page=4"
L = ShellExecute(GetDesktopWindow, "open", Link, Para, vbNullString, SW_NORMAL)
投稿者 あにす  (社会人) 投稿日時 2010/6/16 11:46:37
ファイル名に実行ファイルを指定しないとパラメータの指定が有効になりません。Adobe Readerのパスを指定して実行するようにして下さい。
また、プロセスの実行にはSystem.Diagnostics.ProcessクラスのStart()メソッドを使用出来ます。このメソッドでも実行ファイルでないとパラメータの指定が有効にならない仕様は同じです。
Adobe Readerのパスを設定ファイルに保持するか、拡張子に関連付けられているAdobe Readerのパスをレジストリから読み込んで指定する等の処理が必要でしょう。
投稿者 あにす  (社会人) 投稿日時 2010/6/16 12:26:17
> 結局Adobe Readerが必要であれば、こちらとしては、
> Adobe Reader必須ということでReaderを指定しても構いません。

というのであれば、AxAcroPDF コントロールを使用する方法で既に解決済みでは?
投稿者 Na  (社会人) 投稿日時 2010/6/16 13:25:29
回答ありがとうございます。

>> 結局Adobe Readerが必要であれば、こちらとしては、
>> Adobe Reader必須ということでReaderを指定しても構いません。

>というのであれば、AxAcroPDF コントロールを使用する方法で既に解決済みでは?

そうなのですが、
Adobe Reader以外のReaderが入っている環境では、表示もできません。

できれば、表示のみなら他のReaderでも可能だけど、
ページ数を指定しての表示はAdobe Readerが必須という方がよいため、

関連付けされたプログラムの起動方法のパラメータで、実現可能であれば、
その方が良かったわけです。

実行ファイル名を指定しないとパラメータ指定が有効にならないのであれば、
残念ですが、ただの表示にせよ、ページを指定して表示にせよ、
とにかくAdobe Reader必須ということにします。

回答を頂いた、

魔界の仮面弁士 さん
あにすさん

ありがとうございました。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2010/6/16 15:19:53
> 下記のように、lpParametersに"page=4"と指定しましたが、ページ指定が
> 効きませんでした。

Adobe Reader で "page=" というパラメータが利用可能という情報は見当たらなかったのですが、
その情報はどこから仕入れた物なのでしょうか? (どのバージョンで利用可能なのでしょうか?)

http://kb2.adobe.com/jp/cps/510/510705.html
http://scripting.cocolog-nifty.com/blog/2007/07/adobe_reader_81_e41e.html
http://pdf-file.jugem.jp/?eid=247


それとも、Adobe Reader 以外のリーダーに対する指定なのでしょうか。
パラメータにスラッシュが無いので、Adobe Reader 用の指定では無いように思えました。
投稿者 あにす  (社会人) 投稿日時 2010/6/17 00:56:57
綺麗じゃないですが、起動後にSendKeysで操作してペ目的のページに移動させるという手も。
投稿者 Na  (社会人) 投稿日時 2010/6/17 10:05:47
>Adobe Reader で "page=" というパラメータが利用可能という情報は見当たらなかったのですが、
>その情報はどこから仕入れた物なのでしょうか? (どのバージョンで利用可能なのでしょうか?)

ちゃんと調べたわけでなく、Htmlでのオプションが
そのまま使えるかな試しにやってみました....

結局、ページ指定でPdfを表示する以下のようなHtmlを出力する関数を作り

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head>
<meta http-equiv="Refresh" content="0; url=Test.pdf#page=4">
</head><body></body></html>

そのHtmlファイルを関連付けされたブラウザで開くコードを書くことにしました。

この方法だと、Adobe Reader以外(Foxit Readerで動作確認)でも表示のみはできますし、
Adobe Readerではちゃんとページ数を指定して表示が可能です。

あまりスマートとは言えませんが、とりあえずこの方法で行こうと思います。

魔界の仮面弁士 さん
あにすさん

ご回答いただいきありがとうございました。
いろいろ勉強になりました。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2010/6/17 10:48:48
コマンドライン指定でページ指定を行う方法がありました。
Adobe のサイトからは発見できていないので、公式な方法かどうかは未確認ですが。

http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1317472663
上記を VB.NET のコードに書き換えてみました。

Dim pdfPath As String = "D:\Test\Test.pdf"
Dim page As Integer = 4

Dim arguments As String = String.Format("/A page={0} ""{1}""", page, pdfPath)
Process.Start("AcroRd32.exe", arguments)
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2010/6/17 10:54:41
> Adobe のサイトからは発見できていないので、公式な方法かどうかは未確認ですが。
"/A" スイッチに対する公式情報が見つかりました。
http://partners.adobe.com/public/developer/en/acrobat/PDFOpenParameters.pdf#page=5

これによると、ページ指定以外のコマンドも指定できるようです。
たとえば「/A zoom=150 D:\Test\Test.pdf」なら、拡大率 150% で表示されます。
投稿者 ?-?  (その他) 投稿日時 2010/6/17 11:19:58
コマンドラインで便乗実験。

AcroRd32 /A "zoom=150=openActions&page=2" ~.pdf

で、2ページ目を150%で表示できました。
が、ウィンドウサイズも大きくなっちゃうのね。
投稿者 Na  (社会人) 投稿日時 2010/6/17 14:44:37
コマンドラインでの指定方法をご教授頂きありがとうございます。

コマンドライン指定で実行となると、
実行ファイル"AcroRd32.exe"の場所を把握しないといけません。

また、Readerでなく、Adobe Acrobat 7.0 Standardでも動作を確認できたので、
実行ファイル"Acrobat.exe"の場所も把握しないといけません。

どのようにすればうまく最適な実行ファイルのパスをとってこれますか?

実は、レジストリの操作の経験がほとんどなく、先程調べて、下記コードで、

RetValue = Registry.GetValue("HKEY_CURRENT_USER\Software\Adobe\Acrobat Reader\9.0\InstallPath", Nothing, Nothing)

自分のPCにインストールされているAdobe Reader9.0の実行ファイルのパスが
取ってこれることはわかったのですが、

Adobe Readerがインストールされているか?
 されているなら最新版はどれか?

Adobe Readerがインストールされていない場合Acrobat Standardはインストールされているか?
 されているなら最新版はどれか?

みたいな検索をかけて最初にヒットしたパスでコマンドラインで実行するのかな!?
いう認識です。

なにかまわりくどい方法のような気がしますがもっとよい方法があるのでしょうか?
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2010/6/17 21:11:59
> コマンドライン指定で実行となると、
> 実行ファイル"AcroRd32.exe"の場所を把握しないといけません。
Adobe Reader を正規の手順でインストールしているのであれば、
 Process.Start("AcroRd32.exe", arguments)
だけで実行できるはずです。

この場合、AcroRd32.exe のパスはレジストリから自動的に読み込まれます。
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths

> 実行ファイル"Acrobat.exe"の場所も把握しないといけません。
あれ? Acrobat が入っていようといなかろうと、
>> Adobe Reader必須ということでReaderを指定しても構いません。
だったのではありませんか?

アプリの動作条件として、Adobe Reader が必須ということにしたのであれば、
Acrobat Standard の存在確認を行う必要は無いと思いますけれども…。


> なにかまわりくどい方法のような気がしますがもっとよい方法があるのでしょうか? 
インストールされているアプリケーションを調べたいという意図であればこちら。
http://social.msdn.microsoft.com/Forums/ja-JP/vcgeneralja/thread/ef7b915e-0f20-40c3-919c-4c426d6199db

拡張子 pdf への関連付けを調べたいという意図であればこちら。
http://dobon.net/vb/dotnet/system/findassociatedexe.html
投稿者 Na  (社会人) 投稿日時 2010/6/18 19:15:09
何度も回答頂きありがとうございます。

>Adobe Reader を正規の手順でインストールしているのであれば、
> Process.Start("AcroRd32.exe", arguments)
>だけで実行できるはずです。

>この場合、AcroRd32.exe のパスはレジストリから自動的に読み込まれます。
>HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths

自動的に読み込まれるんですね...
まったく知りませんでした。

>> 実行ファイル"Acrobat.exe"の場所も把握しないといけません。
>あれ? Acrobat が入っていようといなかろうと、
>>> Adobe Reader必須ということでReaderを指定しても構いません。
>だったのではありませんか?

インストールされていなかった場合、
"ページを指定してのPdfの表示にはAdobe Readerが必須です!"
のようなメッセージを表示しようと思っていたので、

インストールされているか判断するために、
レジストリの検索が必要かと思っていました...

Process.Start("AcroRd32.exe", arguments)
の例外判定でインストールされていないかを判定しようと思います。

>アプリの動作条件として、Adobe Reader が必須ということにしたのであれば、
>Acrobat Standard の存在確認を行う必要は無いと思いますけれども…。

Acrobat Standardでも同様の表示可能なのでどちらかのインストール必須に
条件を緩和してもよいかなと思ったのですが、別に必須でも構わないので、
Acrobat Standardは除外します。

ありがとうございました。
投稿者 Na  (社会人) 投稿日時 2010/6/18 20:03:07
何度も何度もすいません...

すべてクリア!
と思ったのですが、少々問題が起きました。

初回の
Process.Startは良いのですが、
表示されたAcrobat Readerを閉じずに、別のページを指定して
Process.Startをした場合に、
前のページが表示されたままです。

Acrobat Readerを閉じずに2回目以降もページを移動したいのです
ができるのでしょうか?