Visual Studio 2017 (15.9.4) Community版を利用して、OfficeToPDFをビルドしたので、その時のメモを残します。
別のPCのVS2017 (15.9.26)で試したところ、コンパイル時にエラーになったので、その対策を加筆しています。
環境
- 【ビルド環境】Windows 10 Pro 1803 (64bit) / 2004 (64bit)
- PowerShell 5.1
- Visual Studio 2017 Community (15.9.4) / (15.9.26)
- 【ワークロード】.Netデスクトップ開発
- 【ワークロード】Office/Sharepoint開発
- 【機能拡張】Github Extension for Visual Studio
- 【実行環境】Windows7 32bit
GithubのREADME.mdにもありますが、Windows7では、Visual Studio 2010 Tools for Office Runtimeと2007 Microsoft Office Add-in: Microsoft Save as PDF or XPSを導入しておく必要があります。
Windows10で実行する場合には、Windows7で必要だったパッケージの導入は必要ないはずです。
概要
他の部署からCD-Rで保存用に資料をもらったところ、サブディレクトリ(sub directory)に様々なワード(.doc)、パワーポイント(.ppt)が配置されていました。
過去に、保存されていたppt95形式のファイルが開けない問題があったりしたので、現在はポリシーとしてPDFファイルにした上でM-DISCに保存するようにしています。
バッチ的にMicrosoft Officeで作成されたファイルをPDFに変換したかったので、いろいろ探したところCodePlex Archiveにofficetopdfを見つけて試してみようと思いました。
Cognidoxが作成し、Githubで現在は公開されているとのことなのですが、バイナルは配布されていない様子だったのでVisual Studio2017を使ってビルドしてみることにしました。
Visual Studio 2017 (VS2017) の導入
公式サイトからダウンロードしたインストーラーを起動し、VS2017を導入します。
VS2017の構成
インストール時に選択する構成は、事後でもメニューからVisual Studio Installerを起動することで行なえます。
.Netデスクトップ と Office開発用コンポーネントの選択
開発対象を選択する画面が表示されるので、.Netデスクトップ開発とOffice Developer Tools for Visual Studioをインストールするために、Office/Sharepoint開発を選択します。
Githubに対応した機能拡張のインストール
機能拡張はInstallerではなく、通常のVS2017のツールメニューから操作をします。
Githubからコードをダウンロードする方法はいろいろありますが、VS2017上でコードをGithubからcloneできるように拡張機能を導入します。
VS2017の拡張機能を探す時には、左側のペイン(pane)でオンラインを選択してから、検索ウィンドウでキーワードを入力します。
Github Extension for Visual Studioはダウンロード数が上位にあるので、すぐに見つけられるはずです。
インストールした後はVS2017のウィンドウを全て閉じて終了するとインストールが始まります。
コードのダウンロード(Clone)
Githubからソースコードをcloneし、VS2017で認識できるようにしていきます。
VS2017を起動し、ファイルメニューからソース管理から開くを選択し、チームエクスプローラーを起動します。
チームエクスプローラーが起動するので、コンセントのアイコンを選択します。
画面下のローカルGitリポジトリの複製メニューからGithubのURLと適当な空のディレクトリを選択します。
登録されたOfficeToPDFをダブルクリックするか、コンセントアイコンの隣りにあるホームアイコンをクリックし、チームエクスプローラーのホームを表示します。
画面下に認識されたソリューションが表示されるため、OfficeToPDF.slnをクリックします。
ビルド
ソリューションを開いた後は、ビルドメニューから、"OfficeToPDFのビルド"を選択し、実行ファイルを生成します。
ビルド時のエラー
VS2017 (15.9.26)でビルドすると次のようなエラーメッセージが出力されました。
重大度レベル コード 説明 プロジェクト ファイル 行 抑制状態
警告 タイプ ライブラリ "MSHTML" のラッパー アセンブリが見つかりません。次のことを確認してください。(1) COM コンポーネントが正しく登録されている。(2) ターゲット プラットフォームのビットが COM コンポーネントと同じである。たとえば、COM コンポーネントが 32 ビットの場合、64 ビットのターゲット プラットフォームは使用できません。 OfficeToPDF
対応方法は、ソリューションエクスプローラーの参照を確認すると、MSHTMLに警告マークが付いているのが分かります。
VS2019では問題がなかったので調べてみると、当初は一旦削除し、Microsoft.mshtml.dllを参照に追加すれば良いと思っていたのですが、regasmを再度実行するのが適切な対応策だと考え直しました。
詳細は下記のブログに記載されていて、他にも同様の記述があるようです。
管理者権限で起動したPowerShellやコマンドプロンプト内部で、Microsoft.mshtml.dllのあるディレクトリに移動し、regasmを実行します。
以下は失敗例です。
PS C:\Windows\assembly\GAC\Microsoft.mshtml\7.0.3300.0__b03f5f7f11d50a3a> regasm .\Microsoft.mshtml.dll
Microsoft (R) .NET Framework Assembly Registration Utility 2.0.50727.9136
Copyright (C) Microsoft Corporation 1998-2004. All rights reserved.
RegAsm : error RA0000 : An error occurred while writing the registration information to the registry. You must have administrative credentials to perform this task. Contact your system administrator for assistance
以下は成功例です。
C:\Windows\assembly\GAC\Microsoft.mshtml\7.0.3300.0__b03f5f7f11d50a3a>regasm Microsoft.mshtml.dll
Microsoft (R) .NET Framework Assembly Registration Utility 2.0.50727.9136
Copyright (C) Microsoft Corporation 1998-2004. All rights reserved.
Types registered successfully
VS2017を再起動すれば、MSHTMLについてエラーはなくなります。
32bitオブジェクトの生成
業務用のPCにはまだWindows7(32bit)のものがあるので、32bitの実行ファイルも生成します。
ターゲットをReleaseに、リリースにx86を選択した上で、ビルドメニューからOfficeToPDFのビルドを選択します。
出力ペイン(pane)をみると
生成されたOfficeToPDF.exeファイルをコピーするなどし、ターゲットのマシンで利用します。
OfficeToPDFの実行例
単純な例としてはトップディレクトリにOfficeToPDF.exeファイルをコピーしたとして、次のように配下のフォルダに含まれる.docxファイルをPDFファイルに変換します。
PS \> ls -R *.docx | ForEach-Object { .\OfficeToPDF.exe $_ }
実用的な実行例
既にPDFファイルが存在している場合には処理を飛ばすような処理を加えるには次のような方法が考えられます。
ls -R *.docx | ForEach-Object {
$pdfpath = ($_.FullName) -Replace ($_.Extension + '$'), '.pdf'
if (Test-Path $pdfpath -PathType Leaf) {
echo ($pdfpath + " skipping...")
} else {
echo ($pdfpath+ " converting...")
.\OfficeToPDF.exe $_
}
}
複数の拡張子に対応する
前述のconvtest1.ps1では、拡張子がどんなものでも対応できるようにしているので、次のようにカンマで区切って複数のパターンを記述することができます。
ls -R "*.docx","*.pptx" | ForEach-Object {
PowerShellスクリプトの開発・デバッグについて
UNIXのShellスクリプトでは変数の実体は常に文字列ですが、PowerShellスクリプトでは、実体は常にオブジェクトなので変数に格納されているオブジェクトの型に注目します。
型を調べる方法としては、GetType()があるので、今回の例では次のようなスクリプトの断片を実行していました。
PS E:\> ls -R *.docx | ForEach-Object { $_.GetType() ; $_.FullName.GetType() }
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True FileInfo System.IO.FileSystemInfo
True True String System.Object
Windows7標準のPowerShell2.0では
ls -R -include *.docx
のように明示的に-includeを追加する必要がありました。
これでlsの実行結果から渡されるオブジェクトがSystem.IO.FileSystemInfoクラスのものだと分かります。
あとはAPIリファレンスでメソッドを調べたり、文字列に落し込んで基本的な操作で解決するようにしました。
OfficeToPDF実行時の注意点
- WordやExcelといったOfficeアプリを全て閉じて利用しないと、処理が止まったりPDFの生成に失敗する場合があります。
- NAS等のネットワークドライブを対象とする場合には、.ps1ファイルを直接実行するためには、ExecutionPolicyをUnristricted (もしくはBypass)に変更する必要があります。
以上