最近は企業の「生産性」というものに注意が払われるようになってきました。要はいかに少ない労力でより多くの成果をあげるかということですが、これは個人のレベルでも業務のやり方の「改善」という形で多くの人が創意工夫してきたと思われます。
しかし現場の方たちの生産性は日本は世界の中でトップクラスと言われていますが、本社で働いているような事務的な仕事をしている人たちの生産性は世界の国々と比較すると燦燦たる有様のようです。
自分は経理としていくつかの会社でここまで何年か働いてきましたが、特にさぼっていたわけではなく、むしろ「どうすればもっと速くミスなくできるようになるか」を常に考えながら仕事をしてきました。
そのような意識の中で仕事をしながら見つけたのがエクセルのVBAです。エクセルのVBAについての効果やすごさについては最近このブログでよく書いていきました。
最近はどうすれば「VBAを使って指定のPDFを一括して印刷できるか」を考えていました。というのも、現在の仕事で時々上司から「○○の請求書のコピーを×月から△月まで印刷しておいて下さい」と言われるからです。
別に1枚や2枚だったら特に気にすることもないのですが、これが10枚や20枚になってくると結構面倒になってきます。
今回はタイトルにもあるように、この請求書のPDFについて拙いながらも自分なりに「SendKeysメソッドとfolderfilelistでPDFを自動印刷できないか」どうか考えてみたので、そのことについて今回は書いていってみます。
今回の記事の注意点として「できないか」と書いてあるので、自動印刷できるマクロができたわけではありません。自動印刷するために自分がどんなことについて試行錯誤してきたかについて書かれた内容です。
ちなみに自動印刷に「近い」ことは、次の記事で書こうと思っているので、そのような前提で読んでいただければと思います。
指定のPDFを印刷するまでの手順と背景
事務的な職業をしている方でもそうでない人でもPDFを印刷したことがある人は多いでしょう。PDFを印刷する時というのは、基本的に次のような手順になるかと思います。ちなみにここではパソコンのデスクトップ上にPDFファイルがあると仮定します。
- まず指定のPDFのファイルをダブルクリックして開く
↓
- 開いたPDFファイルのメニューから「ファイル」を選択
↓
- ドロップダウンメニューから「印刷」を選択
↓
- 開かれた印刷ダイアログボックスから「印刷」を選択
以上が大まかな流れかと思います。上に挙げた例はわかりやすいように非常に簡略化しました。実際の業務などでは印刷したいPDFはデスクトップ上にはなく、決まったフォルダに格納されているのが普通かと思います。
また印刷するときも、その時の状況によって印刷ダイアログボックスから「どのページにするのか」といったことや「カラーか白黒か」といった点など、いろいろと変えなければいけない設定が出てくる場合もあります。
以上のような手順をエクセルのVBAで自動化できないものかと思いました。しかしPDFというと、エクセルとは違うアプリケーションになります。正確にはAdobe AcrobatReader DCというアプリケーションになるわけですが。
もしかしたら何らかの方法があるかもしれないとインターネット上でいろいろと検索してみました。あるにはあるのですが、どれも自分が勉強してきたレベルでは理解できないような難しいコードです。
例えばShellオブジェクトのShellExecuteメソッドを使えばいいと書かれていても、自分のようなVBAを勉強してから日が浅い初心者にはまだ理解するのが難しい。
それらのコードについて書かれたコメントや感想などを読んでみると実際難しいようです。自分なりにVBEにコードを打ち込んでいっていろいろいじって動作させようとしてもなかなか意図通りには動いてくれません。
もっと初心者でも簡単にPDFを自動で印刷できるコードはないものでしょうか。
自分としては、この面倒で単調な作業をどうしても自動化したかったので粘り強く調べてみたらもしかしたらこれはいけるんじゃないか?と思えるものがありました。
それがSendkeysメソッドというものです。
SendKeysメソッドとは
エクセルのVBAにおけるSendkeysメソッドとは、エクセルではなくエクセル以外の外部アプリケーションなどにエクセルから指示が出せるコードです。
一般的なイメージでは、エクセルのVBAというとエクセルの機能のひとつなのでエクセル上でしか動作させることができないと思いがちです。しかしそうではなく例えばエクセルからでもワードとかエクセル以外のアプリケーションでもエクセルから動作させることができるのです。
自分は最初このようなやり方があるのを知ったときは驚愕しました。「こんなやり方もあるのか!?」と。詳しい内容についてはMicroSoftが以下のようなページを掲載しています。
キーボードから入力したときのように、1 つ以上のキー ストロークをアクティブなウィンドウに送ります。
object.SendKeys(string)引数
- object
- WshShell オブジェクトです。
- string
- 送信するキーストロークを文字列式で指定します。
解説
SendKeys メソッドは、オートメーション インターフェイスを持たないアプリケーションにキーストロークを送信する場合に使用します。キーボードの文字のほとんどは単一のキーで表現されます。キーボードの文字の中には、Ctrl+Shift+Home などのように、いくつかのキーの組み合わせで表現されるものもあります。キーボードの文字を 1 つ送信するには、その文字自身を string 引数に指定します。たとえば、X キーを送信するには、string 引数に文字列 “X” を指定します。
ShellオブジェクトとかOpenステートメント といったものは初心者には難しいかもしれませんが、ショートカットキーの「Ctrl+P」などであれば難しくはないでしょう。
そういった動作をエクセルから外部アプリケーションに指示を送れるのが、Sendkeysメソッドです。
例えばここまでPDFを印刷する手順について書いてきました。それをキーボードだけで操作した場合どういった形になるでしょうか?それは以下のような形になります。
- PDFファイルを選択してenterを押す
↓
- PDFファイルが画面上に表示されるので、Ctrl+Pのショートカットキーで印刷ダイアログボックスが開く
↓
- 印刷ダイアログボックスが開かれている状態でenterを押すと印刷が実行される
↓
- Alt+F4でPDFファイルを閉じる
どうでしょうか。どのページを印刷するかといった特に込み入った設定が必要なければ、マウスを操作しなくてもキーボード上のキーだけでPDFファイルを印刷することができます。
自分はこのやり方をエクセルからVBAを通してPDFへ指示を送れないかを試してみました。
Folderfilelistとは
Folderfilelistとはフリーソフトのひとつで、指定のフォルダの中にある全部のファイルまでのパスを全て抽出することができます。ちなみに以下のVectorのページからダウンロードできます。Folderfilelistの使い方の詳細は以下のページから見ていただければと思います。
ファイルまでのパスがどう役に立つの?今回のPDFを印刷するマクロとどう関係があるの?と思うかもしれませんが、使い方によっては本当に便利なんです。
なぜファイルまでのパスを抽出できることが良いのかというと、コンピュータは、このパスで指定のファイルがコンピュータ上のどこにあるのか、というのを理解できるからです。
この機能を利用して、指定のPDFへリンクして開いて印刷できるようにしようと考えました。
ボタンひとつでPDFを印刷できるマクロのコード
以上のようないくつかのアイデアをVBAを使ってコードに落とし込んだものが以下のような形になります。
Sub 印刷()
Dim i As Long
Dim buf As String
On Error Resume Next
Range("F7").Select
Range("F7").Value = "=VLOOKUP(RC[-4],パス!C[-5]:C[3],9,0)"
Selection.AutoFill Destination:=Range("F7:F100"), Type:=xlFillDefault
For i = 7 To 100
If Cells(i, 2) <> "" Then
Cells(i, 6).Hyperlinks.Add Anchor:=Cells(i, 6), Address:=Cells(i, 6).Value
Cells(i, 6).Hyperlinks(1).Follow
SendKeys "^{p}"
SendKeys "{enter}"
SendKeys "%{F4}"
End If
Next i
Range("F7:F100").Delete
End Sub以上のコードをエクセルの開発タブ>Visual Basicを開いて標準モジュールに貼り付けます。それと並行してエクセルのシートを以下のような形にします。

「印刷」シートに以下の処理をする
- B4セルに印刷したいファイルが入っているフォルダのパスをコピペ
- B7セルにコピペしたフォルダに入っているファイルのファイル名をコピペ
「パス」シートに以下の処理をする
フリーソフトのFolderfilelistを利用して、印刷したいファイルが入っているフォルダから抽出した全てのファイルへのパスをコピペする
以上の処理を実行後、「ボタン1」に登録した「印刷マクロ」を押すことで「印刷したいPDFファイルを自動で印刷」できるはずでした。
しかし、ここで問題が発生します。
問題点と今後の課題
以上ここまで書いたやり方で「こんなやり方でもVBAでPDFを印刷できるようになりますよ」と言えればこれほど嬉しいことはないのですが、やはり問題点もあります。
それは「コピペしたファイル名のファイルを全て印刷できるわけではない」という問題です。今の時点では「なぜそうなってしまうのか」というのはわかりません。
自分の中の仮説では「読み込み時間」の問題ではないかと思っています。
VBAという分野には「OLEオートメーション」というやり方があります。これもエクセル上から外部アプリケーションに対して何らかの動作をさせるための方法です。
『VBAエキスパート公式テキスト ExcelVBAスタンダード 』という本には次のように書かれています。
p.188
インターネットへの接続では、ページが完全に読み込まれるまでに時間が必要だからです。ページの読み込みが完了する前にInnerTextプロパティの値を取得しようとするとエラーになります。
そこでページの読み込みが完了するまで処理を一時停止しなければなりません。これには、Do…Loopステートメントを使います。・・・
もしかしたらこれだろうか?と思いました。エクセルからの指示が速すぎてPDFの方がついてこれていないのかも・・・。
確かにPDFファイルをダブルクリックして画面上に完全に開かれるまでの時間とか印刷ダイアログボックスが開くまでの時間、印刷を実行して印刷ダイアログボックスが閉じるまでの時間には若干の「タイムラグ」があります。
上記の『VBAエキスパート公式テキスト ExcelVBAスタンダード 』に書かれているコードをマネしていろいろと試行錯誤してみましたが上手くいきません。
しかし、どうしてもこの処理を自動化したいという想いからインターネットで何か良い方法はないかと調べていたら別の方法を発見しました。
今回書いた記事の方法は、後日改善されることになります。そのことについては、次の次の記事で書こうかと思っています。
今回の記事の続きです
⇒PDFの自動印刷のためにAPIのkernel32を利用してみた






















コメント
FolderFileListの作成者のどどんきです。
FolderFileListを使用していただきありがとうございます。
お礼が言いたくコメントをさせていただきました。
これからもFolderFileListをよろしくおねがいします。
>どどんき様
コメントありがとうございます。
どどんきさんの「FolderFileList」には仕事でとてもとても助けられました。
ありがとうございます。