Excel (VBA)

Excel VBAに関するフォーラムです。
  • 掲示板への投稿には会員登録(無料)が必要です。会員登録がまだの方はこちら
  • 掲示板ご利用上のお願い」に反するご記入はご遠慮ください。
  • Q&A掲示板の使い方はこちらをご覧ください
トピックに返信
質問

 
(Windows 10 Pro : Excel 2016)
PDF自動印刷
投稿日時: 18/12/15 15:39:47
投稿者: トマト0124

皆様のお知恵を貸してください。
特定のフォルダの中にあるPDFを全部指定したプリンタに飛ばすマクロを、
ネット検索し、近しいものを見つけ、修正して作成しました。
なので、意味がわかっていない部分も、コードの中にあります。
 
現在のコードは下記となります。
▼質問1
PDFを開いてプリンターに飛ばすのですが、「Application.ScreenUpdating = False」を入れて
いても、画面で開いて・閉じての動作が出てきてしまいます。
これを抑えるにはどうしたらよいでしょうか。
 
▼質問2
PDFが開いて・閉じての動作を行うのに、プリンターに印刷データが飛ばないときがあります。
sleepの時間を長くしても飛びませんでした。
ちゃんと飛ぶようにするにはどうすればよいでしょうか。
 
どうぞよろしくお願いいたします。
※AdobeはDCを使用しており、有料のものではありません。
------------------------------------------------------------------------------------
Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Sub PDF_Print1()
     
    Dim STR1(4) As String
    Dim var1 As Variant
    Dim var2 As Variant
     
    Dim FN1 As String
    Dim FN2 As String
    Dim FL1 As Object
     
    Dim FSO As New Scripting.FileSystemObject
  
  Application.ScreenUpdating = False
    STR1(0) = "C:\Program Files\Adobe\Reader " & .Cells(10, 4).Value & ".0\Reader\AcroRd32.exe /t "
    STR1(1) = .Cells(8, 4).Value 'PDF保存場所
    STR1(2) = .Cells(6, 4).Value 'プリンター名
 
  FN1 = Dir(STR1(1), vbDirectory)
    Do Until FN1 = ""
       With FSO
     FN2 = STR1(1) & FN1
 
          'ファイル名の取得
          For Each FL1 In .GetFolder(FN2).Files
              STR1(3) = FL1.Name
              STR1(4) = STR1(0) & """" & FN2 & "\" & STR1(3) & """" & " " & """" & STR1(2) & """"
                             
              'PDFファイルの印刷
              Set var1 = CreateObject("WScript.Shell")
              Set var2 = var1.Exec(STR1(4))
              Sleep 2000 'PDFを開いて印刷を実行して、PDFを閉じるまで待機(8秒)
                             
              'Adobe Readerの終了
              var2.Terminate
                             
              Set var2 = Nothing
              Set var1 = Nothing
 
           Next FL1
        End With
         
        FN1 = Dir()
    Loop
    Set FSO = Nothing
 
    Application.ScreenUpdating = True
    MsgBox "印刷が終了しました!", vbOKOnly
     
End Sub
------------------------------------------------------------------------------------

回答
投稿日時: 18/12/15 17:56:08
投稿者: simple

最初の質問はApplicationとはExcelのことですから。
Excelとは別のもののコントロールまでは守備範囲じゃありません。
 
2点目は、
"WScript.Shell"オブジェクトのRunメソッドを使ってみてはどうですか?
bWaitOnReturn 引数を Trueにして呼び出せばよいと思います(同期処理)
処理終了までスクリプトの実行を待ってくれるはずです。
 
以下を参考にして下さい。
[Run メソッド]
https://msdn.microsoft.com/ja-jp/library/cc364421.aspx
 
ちなみに、唐突に .Cellsとか言われても With句が抜けていますが・・・・

回答
投稿日時: 18/12/15 21:04:05
投稿者: WinArrow
投稿者のウェブサイトに移動

コマンドライン(テキストデータ)を生成して
コマンドラインを起動すれば、
AcrobatReaderを開く必要はないと思いますが・・・・

投稿日時: 18/12/15 21:05:54
投稿者: トマト0124

simple様
ご返信ありがとうございます。
 
質問1について、動作しないようにする方法はありませんでしょうか。
質問2について、参考サイトを掲載していただきましたが、
参考にするのはサイト内の下記部分でしょうか。
-------------------------------------------------------------------------
Set WshShell = WScript.CreateObject("WScript.Shell")
Return = WshShell.Run("notepad " & WScript.ScriptFullName, 1, true)
-------------------------------------------------------------------------
 
私が掲示したコードでは、「STR1(4) = STR1(0) & """" & FN2 & "\" & STR1(3) & """" & " " & """" & STR1(2) & """"」のようにプリンタに飛ばしたいPDFのフルパスを指定して、さらにその後ろに飛ばしたい先のプリンタ名を指定していますが、「"notepad " & WScript.ScriptFullName」の部分に「STR1(4)=〜」をそのまま指定すればよろしいのでしょうか。
 
また、これにより開かれたPDFはプリンタに飛ばした後、閉じられるのでしょうか。
 
いくつも質問してしまい申し訳ございませんが、
よろしくお願いいたします。
 
 
 
 
 
 
 
 
 
 

投稿日時: 18/12/15 21:06:59
投稿者: トマト0124

WinArrow様
ご返信ありがとうございます。
 
どのように記述すればよろしいのでしょうか。
申し訳ございませんが、よろしくお願いいたします。

回答
投稿日時: 18/12/15 22:49:13
投稿者: WinArrow
投稿者のウェブサイトに移動

>どのように記述すればよろしいのでしょうか。
 
参考コード
複数連続して印刷する場合は、
時間調整する必要があると思いますので、追加してください。
 

Sub PdfPrint()
Dim WSH As Variant, rng As Range
Const xCmd As String = "AcroRd32.exe /t ""#1"" #2"
    Set WSH = CreateObject("WScript.Shell")
    For Each rng In Range("A1", Cells(Rows.Count, 1).End(xlUp))
        WSH.Run Replace(Replace(xCmd, "#1", rng.Value), "#2", "プリンタ名")
    Next rng
    Set WSH = Nothing
End Sub

 

回答
投稿日時: 18/12/15 22:55:22
投稿者: simple

https://helpx.adobe.com/jp/acrobat/kb/510705.html

 AcroRd32.exe /t path printername drivername portname
Adobe Reader を起動し、印刷ダイアログボックスを表示せずに PDF ファイルを印刷し、Adobe Reader を終了する
とあったので終了すると思っていましたが、終了しないのならダメですね。
他の方の回答をお待ちください。

投稿日時: 18/12/15 23:39:41
投稿者: トマト0124

WinArrow様
ご返信ありがとうございます。
 
質問なのですが、#1と#2はどういう意味なのでしょうか。
このまま使用すればよいのでしょうか。
 
また、「時間調整する必要があると思いますので、追加してください。」というのは、
「Sleep 2000」でも良いのでしょうか。
記述するとしたら、「Next rng」の前で合っておりますでしょうか。
 
 
 
simple様
ご返信ありがとうございます。
 
「Adobeを終了する」で間違っておりません。
確認ですが、ご提示いただいたサイト「https://msdn.microsoft.com/ja-jp/library/cc364421.aspx」に
記載してある「プログラムの実行が終了するまでスクリプトの実行は中断され、」というのは、
今回の私の場合、「PDFを開いて閉じるまで」を指しているのでしょうか。
 
そうすると、「WshShell.Run("notepad " & WScript.ScriptFullName, 1, true)」の1行で、
「PDFを開いて閉じる」が実行されるのでしょうか。
 
※現在、確認できる環境にないため、質問してしまい申し訳ございません。

回答
投稿日時: 18/12/16 11:16:58
投稿者: WinArrow
投稿者のウェブサイトに移動

>質問なのですが、#1と#2はどういう意味なのでしょうか。
>このまま使用すればよいのでしょうか
 
#1,#2はReplaceメソッドとの対応の単なる文字列データなので、
特に意味はありません。
このまま使っても問題ないと覆います。
 
 
コマンドラインで印刷実行後
AcrobatReaderがメモリに残ってしまう
対策を組み込みました。
強制終了です。
 
Sub PdfPrint()
Dim WSH As Variant, rng As Range
Const xCmd As String = "AcroRd32.exe /t ""#1"" #2"
    Set WSH = CreateObject("WScript.Shell")
    For Each rng In Range("A1", Cells(Rows.Count, 1).End(xlUp))
        WSH.Run Replace(Replace(xCmd, "#1", rng.Value), "#2", "プリンタ名")
    Next rng
    Set WSH = Nothing
Dim wProcess As Object
    For Each wProcess In GetObject("winmgmts:root\cimv2") _
        .ExecQuery("select * from Win32_Process where Name='AcroRD32.exe'")
        wProcess.Terminate
    Next
End Sub
 
 

投稿日時: 18/12/16 14:37:04
投稿者: トマト0124

WinArrow様
ご返信ありがとうございます。
 
サンプルコードまで作成いただきありがとうございます。
時間調整につきましては、「Sleep 2000」を「Next rng」の前で合っておりますでしょうか。

回答
投稿日時: 18/12/16 14:45:36
投稿者: WinArrow
投稿者のウェブサイトに移動

>時間調整につきましては
 
simpleさんのレスの中に
>bWaitOnReturn 引数を Trueにして呼び出せばよいと思います(同期処理)
> 処理終了までスクリプトの実行を待ってくれるはずです。
 
と説明があります。
ご確認してください。
 

回答
投稿日時: 18/12/16 14:59:47
投稿者: WinArrow
投稿者のウェブサイトに移動

>時間調整
↓のページを参考に
 
https://msdn.microsoft.com/ja-jp/library/cc364421.aspx

投稿日時: 18/12/17 09:00:53
投稿者: トマト0124

simple様、WinArrow様
ありがとうございます。
 
お2方にご教示いただいたことを元に作成を続けてみます。
またわからないことがあれば質問いたしますので、
そのときはよろしくお願いいたします。
 
解決済みにするまで、少しお時間を頂きたいとおもいます。

回答
投稿日時: 18/12/17 17:34:48
投稿者: Suzu

こんにちは。
 
ExcelVBAの板でこんな事を言うのもはばかられますが
個人的は、VBAでと言うのに抵抗があります。
 
用途を考えると、Excelで実現しなければならないと言う訳でもなく
単に、省力化の為にVBAを利用したいと受け止められます。
 
VBSでドラックアンドドロップにしてしまうとか、
同様の機能を持つフリーツールもありましたよ。

投稿日時: 18/12/27 22:41:49
投稿者: トマト0124

WinArrow様、simple様
時間が空いてしまいましたが、まだできていないため、お力をお貸しください。
 
WinArrow様にご提示いただいた下記コードを元に作成してみましたところ、
下記のような質問がございます。
 
質問1
「WSH.Run Replace(Replace(xCmd, "#1", rng.Value), "#2", "プリンタ名"),,True」
としたところ、プリンタにデータは飛びますが、手動でAdobeを閉じないと次に進みません
でした。
手動で閉じなくても次に進むようにするにはどうすればよろしいでしょうか。
 
質問2
For Each wProcess In GetObject("winmgmts:root\cimv2") _
    .ExecQuery("select * from Win32_Process where Name='AcroRD32.exe'")
    wProcess.Terminate
Next
上記コードですが、「wProcess.Terminate」が2回目の実行されるときエラーとなってしま
います。
このエラーが出ないようにするにはどうすればよろしいでしょうか。
 
質問3
simple様にご提示た抱いたサイトのように
「Return = WSH.Run(Replace(Replace(xCmd, "#1", rng.Value), "#2", "プリンタ名"),1,True)」としようとしましたが、「=」のところで「ステートメントの最後です」というエラーとなりました。
どこを直せばよろしいのでしょうか。
 
いくつも質問してしまい申し訳ございませんが、どうぞよろしくお願いいたします。
------------------------------------------------------------------------
Sub PdfPrint()
Dim WSH As Variant, rng As Range
Const xCmd As String = "AcroRd32.exe /t ""#1"" #2"
    Set WSH = CreateObject("WScript.Shell")
    For Each rng In Range("A1", Cells(Rows.Count, 1).End(xlUp))
        WSH.Run Replace(Replace(xCmd, "#1", rng.Value), "#2", "プリンタ名")
    Next rng
    Set WSH = Nothing
Dim wProcess As Object
    For Each wProcess In GetObject("winmgmts:root\cimv2") _
        .ExecQuery("select * from Win32_Process where Name='AcroRD32.exe'")
        wProcess.Terminate
    Next
End Sub
------------------------------------------------------------------------

投稿日時: 18/12/27 22:44:11
投稿者: トマト0124

Suzu様
アドバイスいただきありがとうございます。
Suzu様のおっしゃる通り、省力化の為にVBAを利用したいと考えています。
フリーのツールは入れることができないため、エクセルで作成しようと考えました。
また、VBSは全く触れたことがありません為、思いもつきませんでした。

回答
投稿日時: 18/12/27 23:19:38
投稿者: WinArrow
投稿者のウェブサイトに移動

引用:
質問2
 For Each wProcess In GetObject("winmgmts:root\cimv2") _
     .ExecQuery("select * from Win32_Process where Name='AcroRD32.exe'")
     wProcess.Terminate
 Next
上記コードですが、「wProcess.Terminate」が2回目の実行されるときエラーとなってしま
 います。
このエラーが出ないようにするにはどうすればよろしいでしょうか。
 

 
自動でADOBE READER を閉じるコードが、↑のコードです。
>2回目の実行
とは、ADOBE READER が複数起動されているということですか?

回答
投稿日時: 18/12/28 10:18:38
投稿者: Suzu

引用:
>2回目の実行
とは、ADOBE READER が複数起動されているということですか?

 
bWaitOnReturn に True を設定 かつ、wProcess.Terminate も含めたコードにすると
Readerのウィンドプロセスが自動で閉じてくれない。
なので、手動で閉じないと、次のPDFの処理に移行しません。
 
だからと言って、Trueを指定しないと wProcess.Terminate の部分が、
印刷完了前に 実行されてしまい、印刷をされず終了してしまう様です。
 
アプリケーションウィンドが残ってしまいますが、
wProcess.Terminate を使わないで、bWaitOnReturn に True を指定してしまっては?
 
 
 
ついでに。。いちいちExcelを使うのが面倒なので、VBSで処理。
ファイルをVBSで保存、そのファイルに印刷対象PDFをドラックアンドドロップ
 
Set WshArgs = WScript.Arguments
Set WshShell = WScript.CreateObject("WScript.Shell")
 
For I = 0 to WshArgs.Count - 1
 WshShell.Run "AcroRd32.exe /t """ & WshArgs(I) & """ プリンタ名", 0, True
Next

投稿日時: 18/12/28 13:17:48
投稿者: トマト0124

WinArrow さんの引用:
引用:
質問2
 For Each wProcess In GetObject("winmgmts:root\cimv2") _
     .ExecQuery("select * from Win32_Process where Name='AcroRD32.exe'")
     wProcess.Terminate
 Next
上記コードですが、「wProcess.Terminate」が2回目の実行されるときエラーとなってしま
 います。
このエラーが出ないようにするにはどうすればよろしいでしょうか。
 

 
自動でADOBE READER を閉じるコードが、↑のコードです。
>2回目の実行
とは、ADOBE READER が複数起動されているということですか?

 
WinArrow様
ご返信ありがとうございます。
 
ADOBEはマクロで開いている1つしか起動していません。
ご提示いただいた閉じるコードで1つ閉じた後、ループが終了せず、2回目が実行されてしまい、
エラーとなってしまいます。
※エラーの内容は忘れてしまいました。すみません。

投稿日時: 18/12/28 13:27:37
投稿者: トマト0124

[quote="Suzu"]

引用:

ついでに。。いちいちExcelを使うのが面倒なので、VBSで処理。
ファイルをVBSで保存、そのファイルに印刷対象PDFをドラックアンドドロップ
 
Set WshArgs = WScript.Arguments
Set WshShell = WScript.CreateObject("WScript.Shell")
 
For I = 0 to WshArgs.Count - 1
 WshShell.Run "AcroRd32.exe /t """ & WshArgs(I) & """ プリンタ名", 0, True
Next

Suzu様
ご返信ありがとうございます。
 
VBSコードのご提示ありがとうございます。
これはメモ帳に上記をコピペして、プリンタ名とかを環境に合わせて修正し、
「.vbs」として保存すればよいのでしょうか。
 
 
おっしゃる通り、Adobeが自動で閉じてくれません。
手動で閉じないと、ずっと待機している状態でした。
また、Trueで待機するようにしないと、プリンターに飛ばないファイルも出てきます。
 
>wProcess.Terminate を使わないで、bWaitOnReturn に True を指定してしまっては?
すみません。これはどういう風に記述するということでしょうか。

回答
投稿日時: 18/12/28 14:30:37
投稿者: WinArrow
投稿者のウェブサイトに移動

引用:

ご提示いただいた閉じるコードで1つ閉じた後、ループが終了せず、2回目が実行されてしまい、
エラーとなってしまいます。

 
タスクバーを見ると
ADOBE READERは、1つですが、
内部的には、印刷したファイルを数だけ、存在するようです。
Terminateでは、1つ目は解除されますが、2つ目は、「見つかりません」エラーになります。
1つ目でループを抜ける対応で、↓のコードに差し替えればいかがでしょう?
 
         If Not wProcess Is Nothing Then wProcess.Terminate: Exit For
 

回答
投稿日時: 18/12/28 15:12:33
投稿者: Suzu

引用:
これはメモ帳に上記をコピペして、プリンタ名とかを環境に合わせて修正し、
「.vbs」として保存すればよいのでしょうか。

その通りです。
 
 
引用:
>wProcess.Terminate を使わないで、bWaitOnReturn に True を指定してしまっては?
すみません。これはどういう風に記述するということでしょうか。

 
VBSにて確認した現象として
  
WshShell.Run "AcroRd32.exe/t """ & objArgs(I) & """ プリンタ名"
→ Adobe Reader のウィンド が、プロセスとして残る
 
AdodeReader のウィンドを消す為に wProcess.Terminate を入れたい。
 
その為には、Adobe Reader のプロセスを順次実行し、終了するのを待ちたい。
Return = WshShell.Run ("AcroRd32.exe /t 〜〜 ,True)
と結果を受ける様に変える。
  → 複数印刷する際に、一ファイル印刷が終わったら、
      Adobe Readerの ウィンドを「手動」で消さないと、次の印刷が始まらない。
 
という事ですよね。
  
なので、
→ Adobe Reader のウィンド が、プロセスとして残る
をそういうものだと諦めてはどうですか?と言う話です。

投稿日時: 18/12/28 20:55:03
投稿者: トマト0124

WinArrow さんの引用:
引用:

ご提示いただいた閉じるコードで1つ閉じた後、ループが終了せず、2回目が実行されてしまい、
エラーとなってしまいます。

 
タスクバーを見ると
ADOBE READERは、1つですが、
内部的には、印刷したファイルを数だけ、存在するようです。
Terminateでは、1つ目は解除されますが、2つ目は、「見つかりません」エラーになります。
1つ目でループを抜ける対応で、↓のコードに差し替えればいかがでしょう?
 
         If Not wProcess Is Nothing Then wProcess.Terminate: Exit For
 

WinArrow様
ご返信ありがとうございます。
年明けに試してみます。
 
他の質問についてはいかがでしょうか。
 
[quote="トマト0124"]
引用:

質問1
「WSH.Run Replace(Replace(xCmd, "#1", rng.Value), "#2", "プリンタ名"),,True」
としたところ、プリンタにデータは飛びますが、手動でAdobeを閉じないと次に進みません
でした。
手動で閉じなくても次に進むようにするにはどうすればよろしいでしょうか。
 
質問3
simple様にご提示た抱いたサイトのように
「Return = WSH.Run(Replace(Replace(xCmd, "#1", rng.Value), "#2", "プリンタ名"),1,True)」としようとしましたが、「=」のところで「ステートメントの最後です」というエラーとなりました。
どこを直せばよろしいのでしょうか。

投稿日時: 18/12/28 21:02:42
投稿者: トマト0124

Suzu さんの引用:
引用:
>wProcess.Terminate を使わないで、bWaitOnReturn に True を指定してしまっては?
すみません。これはどういう風に記述するということでしょうか。

 
VBSにて確認した現象として
  
WshShell.Run "AcroRd32.exe/t """ & objArgs(I) & """ プリンタ名"
→ Adobe Reader のウィンド が、プロセスとして残る
 
AdodeReader のウィンドを消す為に wProcess.Terminate を入れたい。
 
その為には、Adobe Reader のプロセスを順次実行し、終了するのを待ちたい。
Return = WshShell.Run ("AcroRd32.exe /t 〜〜 ,True)
と結果を受ける様に変える。
  → 複数印刷する際に、一ファイル印刷が終わったら、
      Adobe Readerの ウィンドを「手動」で消さないと、次の印刷が始まらない。
 
という事ですよね。
  
なので、
→ Adobe Reader のウィンド が、プロセスとして残る
をそういうものだと諦めてはどうですか?と言う話です。

 
Suzu様
ご返信ありがとうございます。
「Return = WSH.Run(Replace(Replace(xCmd, "#1", rng.Value), "#2", "プリンタ名"),1,True)」をVBAで試してみたところ、質問3のようなエラーとなりました。
 
これでエラーがでないようになると、自動で開いて閉じて開いて・・・を繰り返すようになるのでしょうか。

回答
投稿日時: 18/12/28 22:51:33
投稿者: WinArrow
投稿者のウェブサイトに移動

引用:

「Return = WSH.Run(Replace(Replace(xCmd, "#1", rng.Value), "#2", "プリンタ名"),1,True)」をVBAで試してみたところ、質問3のようなエラーとなりました。

 
コードお修正ミスがあります。
 
Return = WSH.Run(Replace(Replace(xCmd, "#1", rng.Value), "#2", "プリンタ名"),True)
 
ところで「プリンタ名」は、このまま実行しているのですか?

投稿日時: 18/12/29 08:15:32
投稿者: トマト0124

WinArrow様
ご返信ありがとうございます。
「プリンタ名」は、実際のプリンタ名をそのまま指定しています。
<例>プリンタ名が「1号機」となっている場合、「STR1(3)="1号機"」として「STR1(3)」と指定しています。
 
これで、自動で開いて閉じて開いて・・・を繰り返すようになりますでしょうか。

回答
投稿日時: 18/12/29 11:00:54
投稿者: WinArrow
投稿者のウェブサイトに移動

コードミスのヶ所は
「プリンタ名」のところではありません。
次の赤字能文です。
"),1,True
 
紛らわしいコメントで申し訳ありません。

投稿日時: 18/12/29 15:01:06
投稿者: トマト0124

WinArrow さんの引用:
コードミスのヶ所は
「プリンタ名」のところではありません。
次の赤字能文です。
"),1,True
 
紛らわしいコメントで申し訳ありません。

WinArrow様
ご返信ありがとうございます。
年明けに試してみます。
またしばらくお時間をいただきたいと思います。
これで自動で開いて閉じて開いて・・・を繰り返すようになってくれればいいのですが・・・

投稿日時: 19/01/19 04:23:17
投稿者: トマト0124

皆様に教えていただいたことを試してみましたが、
やはり、ADOBEは手動で閉じる必要があり、状況は変わりませんでした。
 
Suzu様に教えていただいたVBSも試してみましたが、
複数のPDFをドラッグすると、同じ状況となりました。
 
印刷したいPDFファイルが100以上ある為、効率化を図るには、
どうしても「自動で開いて、自動で閉じて、また自動で開いて・・・」を
繰り返すようにしたいと思うのですが、どうしたらよいでしょうか。

回答
投稿日時: 19/01/22 10:04:23
投稿者: Suzu

引用:
やはり、ADOBEは手動で閉じる必要があり

 
私は
引用:
アプリケーションウィンドが残ってしまいますが、
wProcess.Terminate を使わないで、bWaitOnReturn に True を指定してしまっては?

と、しており、残るのは承知の上です。
必要であれば、印刷後に、Adobe Reader DC のプロセスを終了するコマンドを発行すれば良いと思います。
 
 
引用:
どうしても「自動で開いて、自動で閉じて、また自動で開いて・・・」を
繰り返すようにしたいと思うのですが、どうしたらよいでしょうか。

 
確実なのは、Adobe Acorobat を オートメーションにて操作する事だと思います。

トピックに返信