プロが教える店舗&オフィスのセキュリティ対策術

実はアクセスから2種類のドキュメントを連続してプリントアウトしたいと思っています。
ひとつは商品図面(PDF)でもうひとつはその商品の顧客リストです。かつ現場で間違わないように必ず(1)商品図面→(2)顧客リストの順番で出力する事が必須となります。
しかし(1)はAcrobatを介しての出力で(2)はアクセスからのダイレクト出力の為か、VB上での順番とは逆に実際には(2)→(1)の順番となってしまいます。

必ず(1)→(2)の出力順となるような方法はありませんでしょうか?
ネットで調べたところ『WaitForSingleObject』なる関数があるようですが、素人の私ではこれが使えるのかどうか難しくて判りません。


下記がモジュールの内容です。宜しくアドバイスお願いします。

'**** (1)選択肢から選んだ商品図pdfを印刷する ****
pass1 = "C:\商品図面\" & rstTable!図番 & ".pdf" & ""
name1 = Dir(pass1)
Dim objShell As New Shell32.Shell
Dim objShellDP As Shell32.IShellDispatch2

Set objShellDP = objShell

Call objShellDP.ShellExecute(pass1, , , "print", vbNormalFocus)

Set objShellDP = Nothing
Set objShell = Nothing


'**** (2)該当する商品の顧客リストを印刷する ****
DoCmd.OpenReport "R_顧客リスト", acViewNormal, "", "", acNormal

'****

A 回答 (4件)

WaitForSingleObject は呼び出し元がフリーズしたように感じるので


別解です。
Option Explicit
Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

'http://www.wmifun.net/library/win32_printjob.html
Function WaitPrintIn(ByVal DocName As String) As Boolean
  Dim strComputer As String
  Dim objWMIService As Object
  Dim colPrintJobs As Object
  Dim objPrintJob As Object
  strComputer = "."
  Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
  
  Set colPrintJobs = objWMIService.ExecQuery _
    ("SELECT * FROM Win32_PrintJob WHERE Document = '" & DocName & "'")
  If colPrintJobs.Count > 0 Then
    WaitPrintIn = True
  End If
End Function

Function WaitPrintOut(ByVal DocName As String) As Boolean
  Dim strComputer As String
  Dim objWMIService As Object
  Dim colPrintJobs As Object
  Dim objPrintJob As Object
  strComputer = "."
  Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
  
  Set colPrintJobs = objWMIService.ExecQuery _
    ("SELECT * FROM Win32_PrintJob WHERE Document = '" & DocName & "'")
  If colPrintJobs.Count = 0 Then
    WaitPrintOut = True
  End If
End Function

Sub こまんど()
  Dim Pass1 As String
  Dim oFs As Object
  Dim oShell As Object
  Dim sName As String

  Set oFs = CreateObject("Scripting.FilesystemObject")
  Set oShell = CreateObject("Shell.Application")
  Pass1 = "C:\商品図面\" & rstTable!図番 & ".pdf"
  sName = oFs.getFilename(Pass1)
  Call oShell.ShellExecute(Pass1, , , "print", vbNormalFocus)

  Do Until WaitPrintIn(sName) = True '印刷処理に取り掛かるまで待機
    Sleep 500
    DoEvents
  Loop

  Do Until WaitPrintOut(sName) = True '印刷が終わるまで待機
    Sleep 500
    DoEvents
  Loop
  MsgBox ""
  'DoCmd.OpenReport "R_顧客リスト", acViewNormal, "", "", acNormal
  'もしかしたら↑の一行だけをサブモジュールにして呼び出した方が良いかも
  '途中省略

  Set oFs = Nothing: Set oShell = Nothing
  MsgBox "おしまい"
End Sub

※試したわけではない(紙とインクがもったいない・・)ので結果は不明です。
とりあえず、お試しあれ。
投稿用にインデントの代わりに全角スペースを使っています。
なお、こちら(Windows7 AcroRD32 Ver10.1.1)では印刷終了後には
アクロリーダーは自動的に閉じました。
    • good
    • 0
この回答へのお礼

出来ました!完璧なシーケンスで複数種類のドキュメントが順番どおり出力されました。
感謝感激です。何とお礼を言ってよいやら...
本当に有難うございました。

お礼日時:2011/12/12 11:10

これで良いのかな?よく分からんけど (^^ゞ



Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, _
                           ByVal dwMilliseconds As Long) As Long
Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, _
                       ByVal bInheritHandle As Long, _
                       ByVal dwProcessId As Long) As Long
Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long

'--- Win32 API 定数の宣言 ---
Global Const PROCESS_ALL_ACCESS As Long = &H1F0FFF
Global Const INFINITE As Long = &HFFFF

Sub WaitRun()
  Dim TaskId As Long     'タスクID
  Dim hProc As Variant   'プロセスハンドル

  ' 外部プログラムの実行
  TaskId = Shell("C:\Program Files (x86)\Adobe\Reader 10.0\Reader\AcroRd32.exe /p " & "E:\PDF\20111111120222.pdf", 2)
  ' プロセスハンドルの取得
  hProc = OpenProcess(PROCESS_ALL_ACCESS, False, TaskId)
  ' プロセスのオープン
  If OpenProcess(PROCESS_ALL_ACCESS, False, TaskId) <> vbNull Then
    ' プロセスのシグナル待ち
    Call WaitForSingleObject(hProc, INFINITE)
    ' プロセスクローズ
    CloseHandle hProc
  End If
beep: beep
MsgBox ""
End Sub

ネタ元はこちらです。丸写しです・・・
http://www.moug.net/tech/exvba/0150034.html
    • good
    • 0
この回答へのお礼

私もあれからネットで探したモジュールのサンプルを改造して色々試してみました。外部プログラムでの作業が終了するまでルーチンを待機させる為には"WaitForSingleObject"関数が有効というところまではわかりましたが、外部プログラムそのものをマニュアルで閉じないと待機解除にならず、それでは担当者がPCに付きっ切りになってしまいます。
出来たら印刷終了を以ってプログラムが自動的に閉じられ、ルーチンも自動的に再開できないかと虫の良い事を考えています。
もう少し苦しんでみます。有難うございました。

お礼日時:2011/12/09 08:58

Yahoo知恵袋でも答えたのですが、結局


> Call objShellDP.ShellExecute(pass1, , , "print", vbNormalFocus)
が非同期処理になっているために、Adobe Readerの起動を待たずに
> DoCmd.OpenReport "R_顧客リスト", acViewNormal, "", "", acNormal
を実行してしまいます。
あちらの回答のようにプロセスIDを元に待つようにすれば、とりあえずは回避できるように思いますが、Adobe Readerの仕様上、印刷がが終了してもプログラムのプロセスは自動終了しません。ユーザーにAdobe Readerの終了を行ってもうら必要があると思いますが、それは構いませんか?
    • good
    • 0
この回答へのお礼

有難うございます。実は金曜日までに仕上げるつもりで焦っていたのでYahoo!にも並行で質問させていただきました。こちらで併せて御礼申し上げます。

今回実は出力しようと思っている書類はACCESSからのダイレクト出力が2種類、Accrobat経由が2種類ありpdfは選択する商品によって枚数も多種多様です。
その4種類を順番に出力し且つ予め選択しておいた複数の商品を上から順番にひとつのルーチンでバッチ処理したいと考えています。
従って全ての出力が完了するまで、途中でマニュアル操作を加えるのは出来る限り避けたいと思っています。(都合の良い話で申し訳ありません)

先ほどネットで検索していたら"Shell"と"WaitForSingleObject"を組み合わせる事でシェルで実行したプロセスが完了するまでアプリの実行を待機できるとの記事を読みました。
"ShellExecute"を"Shell"に換えてAcrobat.exeの場所を特定する事でpdfのプリント中はVBを待機状態とし、その終了を以ってアプリの待機も解除するという様なことは無理でしょうか?

お礼日時:2011/12/07 18:37

顧客リストもPDFにして図面と結合したら?

    • good
    • 0
この回答へのお礼

有難うございます。PDF図面はマスターで内容変更はありませんが、顧客リストは瞬間瞬間に変わってゆくデータベースですので毎回PDF化をするとしてもかなり負荷と時間のかかるルーチンになると思われます。
出来たら顧客リストは現行のままデータベースから直に出力処理したいと思っていますが、上手く行かない場合の代替案として検討させていただきます。

お礼日時:2011/12/07 18:14

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

関連するカテゴリからQ&Aを探す