VB.NETでPDFファイルをAcrobatを使用して非同期印刷する
この記事は2023/05/31に作成されました。
作成日:2023/05/31
最終更新日:2023/05/31
環境
エディター:Visual Studio Community 2022 17.4.4
ターゲットフレームワーク:.NET Framework 4.7.2
Adobe Acrobat Pro:2023.001.20174
(検証はできていませんが、Proではなくてもおそらく可能)
はじめに
今回は、VB.NETを使って複数のPDFファイルを非同期に印刷する方法をご紹介します。
印刷する部分を非同期のTaskで作成しているため、印刷中も他の処理をすることが可能です。
例えば、タスクトレイにアイコンを表示し、そのメニューからプログラムを終了させたりすることも可能です。
本体の印刷するプログラムはモジュールで作成しています。
初期設定
printerName = 印刷するプリンター名
acrobatPath = Acrobatのexeファイルへのパス
filePathList = 印刷するPDFファイルへのパスのList
processList As List(Of ProcessInfo)
'ProcessInfoクラス 複数の process を管理するため作成
Private Class ProcessInfo
Public Property Process As Process
Public ReadOnly Property Filename As String
Public Property HasExited As Boolean
Public Property ErrorMsg As String
Public Sub New(process As Process, filename As String)
Me.Process = process
Me.Filename = filename
HasExited = False
End Sub
End Class
プリンター存在確認
設定された printerName のプリンターが、PCと接続されているかの確認をします。
'Module1.main
Dim printerSettings As New PrinterSettings()
For Each printer As String In PrinterSettings.InstalledPrinters
If printer = printerName Then
Return True
End If
Next
Return False
PDFファイルの数ぶんループ
'Module1.main
For Each filePath As String In filePathList
'すこしsleepする
Thread.Sleep(1000)
PrintPdfAsync(filePath)
Next
非同期処理中、アプリケーションが終了しないように待機
'Module1.main
'Imports System.Windows.Forms
Application.Run()
Taskで印刷処理を開始
'Module1
Private Sub PrintPdfAsync(filePath As String)
Task.Run(Sub()
Dim result = PrintPdfClass.PrintPdf(filePath)
If Not result Then
' PrintPdfがFalseを返した場合、アプリケーションを終了する
PrintPdfClass.Dispose()
Environment.Exit(0)
End If
End Sub)
End Sub
Acrobatを開き、印刷する
エラーハンドリング等省略していますが、失敗した場合に false を返すことでアプリケーションが終了します。
'PrintPdfClass
Public Function PrintPdf(filePath As String) As Boolean
Dim printArgs As String = String.Format("/h /t ""{0}"" ""{1}""", filePath, printerName)
' Acrobat Readerを起動してPDFファイルを印刷する
Dim processInfo As New ProcessStartInfo(acrobatPath, printArgs)
processInfo.CreateNoWindow = True
processInfo.WindowStyle = ProcessWindowStyle.Hidden
Dim process = New Process With {
.EnableRaisingEvents = True,
.StartInfo = processInfo
}
AddHandler process.Exited, AddressOf ProcessExited
Dim processInfoClass As New ProcessInfo(process, filePath)
processList.Add(processInfoClass)
process.Start()
Return True
End Function
processがexitedのとき、終了処理を行う
'PrintPdfClass
'Acrobatのウィンドウを閉じるときに使用する
Private Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr
Private Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hWnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
Private Const WM_SYSCOMMAND As Integer = &H112
Private Const SC_CLOSE As Integer = &HF060
Private Sub ProcessExited(sender As Object, e As EventArgs)
Dim exitedProcess As Process = CType(sender, Process)
exitedProcess.Dispose()
'すべてのプロセスが終了した場合のIf内で
' Acrobat Readerのウィンドウを閉じる処理を非同期に実行する
Task.Run(
Sub()
' Acrobat Readerのウィンドウを探す
Dim adobeWindowHandle As IntPtr = IntPtr.Zero
Do Until adobeWindowHandle <> IntPtr.Zero
adobeWindowHandle = FindWindow("AcrobatSDIWindow", vbNullString)
Loop
' Acrobat Readerのウィンドウを閉じる
SendMessage(adobeWindowHandle, WM_SYSCOMMAND, SC_CLOSE, 0)
End Sub
)
End Sub
Disposeですべてのprocessを終了する
Public Sub Dispose()
For Each processInfo In processList
processInfo.Process.Dispose()
Next
End Sub
以上のコードで、ローカルのPDFファイルを印刷することが可能です。
これらを使用することで、あるディレクトリにあるPDFを全て印刷したり、Windowsのタスクスケジューラで定期的に実行することで印刷の自動化が可能になります。
使用用途に合わせて改変してください。
最後に
高校生のときにVisual Basicでアナログ時計を作ったりした経験はありましたが、本格的なプログラムは初めてでした。
すんなりとはいきませんでしたが、形になってとてもうれしかったです。
プログラマー/A.A