.NET製Winフォーム上にPDFを表示する
最近の仕事で、「.NET製アプリのフォームにPDFを表示させる」というのがあった。
とりあえず調べたことをまとめておく。
環境
- .NET3.5
- Adobe Reader 9.0
- Adobe Acrobat 9.0
どうやって表示するか
ざくっと調べたところ、3つの候補が出てきた
WebBrowserコントロールを利用する
特筆すべきことはなにもない。
フォームデザイナ上でツールボックスから「WebBrowser」を選択して配置するのみ。
Navigateメソッドを使用してPDFファイルの表示を行う。
通常Webブラウザ上でPDFを表示する環境と全く同じことになる。
つまり、PDF表示プラグインがインストールされていなければならない。
Adobe ReaderやFoxit Readerをインストールしておく。
プロセスが終了しないことがあるので、必要であれば以前のメモを参照。
.NETでPDFを開くときの注意 - やりたくないことはやらずに済む努力をすべき
Adobe PDF Readerを利用する
これも簡単。
まず、VisualStudioのデザイナ画面でツールボックスにAdobeReaderのコントロールを追加する。
右クリック→アイテムの選択→COMコンポーネントタブ→「Adobe PDF Reader」にチェック。
(実体はC:\Program Files\Common Files\Adobe\Acrobat\ActiveX\AcroPDF.dll)
フォームに貼りつけて準備完了。
LoadFileメソッドでPDFファイルの表示を行う。
Adobe Acrobatx.x type Libraryを利用する
この方法はAdobe Acrobatのインストールが必要。
まず、参照設定でCOMコンポーネントの中からAdobe Acrobatx.x type Libraryを探して参照を追加する。
表示にはAVDocオブジェクトを使用する。こんな感じでオブジェクトを生成する。
AVDoc = CType(CreateObject("AcroExch.AVDoc"), Acrobat.CAcroAVDoc)
次に、OpenInWindowExメソッドを利用して表示する。
' ここではDocumentPanelというコントロールを配置して、その上にPDFを表示 AVDoc.OpenInWindowEx(DocPathForView, _ Me.DocumentPanel.Handle.ToInt32, _ AV_EXTERNAL_VIEW, 1, 0, PDUseNone, _ AVZoomFitWidth, 0, 0, 0)
ちなみに、AV_EXTERNAL_VIEW = 1, PDUseNone = 1, AVZoomFitWidth = 2。
ここらへんは、AdobeのページからSDKサンプルをダウンロードすると、VBとC#のサンプルが入手できるのでそこから朴る。
Acrobatを利用する際のポイントをいくつか羅列しておく
- COMで定義されているクラスは、まともなインターフェイスをもたないので遅延バインディング必須。
- Acrobat関連のオブジェクトを生成すると、必ずAcroAppオブジェクトが生成される。
- AcroAppオブジェクトは、複数存在しない。AcroApp = CType(CreateObject("AcroExch.App"), Acrobat.CAcroApp)が意味するのは、既存のオブジェクトへの参照の取得。*1
- Win32APIを使っているためか、リサイズ時は自分でリサイズしてやる必要がある。以下のようにする。Win32APIのラッパをつくらなければならないが、PInvokeを使えばOK。
''' <summary>PDF表示領域のリサイズ</summary> ''' <remarks>自動でリサイズしないので、ここでWIN32APIを利用して大きさを調整</remarks> Private Sub DocPanel_Resize(ByVal sender As Object, ByVal e As EventArgs) Handles DocumentPanel.Resize If (Me.Disposing) Then Throw New ObjectDisposedException(MyClass.GetType.Name, "DocPanel_Resize") End If Dim parent As Control = CType(sender, Control) ' AVDocが貼り付いている親ウィンドウ Dim pWndChild As Int32 = Win32API.GetWindow(parent.Handle.ToInt32, GW.CHILD) ' 親ウィンドウのハンドルからAVDocのウィンドウハンドルを取得 If Not (pWndChild.Equals(0)) Then Dim r As Win32API.RECT Win32API.GetClientRect(parent.Handle.ToInt32, r) Win32API.SetWindowPos(pWndChild, HWND.TOP, 0, 0, _ r.Right - r.Left, _ r.Bottom - r.Top, _ SWP.NOZORDER Or SWP.NOMOVE) End If End Sub
*1:もちろん無ければ生成されるが